comments_clauses
Позволяет изменить sql подзапросы (fields, join, where, orderby, limits, groupby) при выборке комментариев функцией get_comments().
Использование
add_filter( 'comments_clauses', 'wp_kama_comments_clauses_filter' ); /** * Function for `comments_clauses` filter-hook. * * @param string[] $clauses Associative array of the clauses for the query. * * @return string[] */ function wp_kama_comments_clauses_filter( $clauses ){ // filter... return $clauses; }
- $pieces(string[])
- Ассоциативный массив с sql подзапросами типа fields, join, where, orderby, limits, groupby и так далее.
- $query(WP_Comment_Query)
- Текущий объект класса WP_Comment_Query. Классы в php передаётся по ссылке.
Примеры
#1 Пример данных в фильтре
В консоли админки в метабоксе "На виду" срабатывает функция wp_dashboard_site_activity(), которая в свою очередь использует функцию wp_dashboard_recent_comments() и в последующем get_comments() для вывода последних комментариев в метабоксе. Под администратором код запроса выглядит следующим образом:
$comments_query = array( 'number' => 25, 'offset' => 0, ); get_comments( $comments_query )
Посмотрим, какие данных проходят через фильтр с помощью дебага WordPress:
add_filter( 'comments_clauses', function ( $args ) { error_log( print_r( $args, true ) ); return $args; } );
Получим
Array ( [fields] => wp_comments.comment_ID [join] => [where] => ( ( comment_approved = '0' OR comment_approved = '1' ) ) [orderby] => wp_comments.comment_date_gmt DESC [limits] => LIMIT 0,25 [groupby] => )
#2 wpDiscuz: сортировка по популярным комментариям на основе данных WP Recall
В данном кейсе используются плагины wpDiscuz и WP Recall, которые дают возможность оценивать комментарии (лайкать). Так как комментарии выводит wpDiscuz, то и сортировку он делает на основе своих данных, хранящихся в метаполях под ключом wpdiscuz_votes
. На сайте используется личный кабинет на основе WP Recall и оценивая комментарии через него, пользователь получает карму, на основе которой можно делать всякие плюшки.
Задача: оставить лайки от WP Recall, убрать лайки от wpDiscuz, но оставить возможность сортировать комментарии по популярности.
Данную задачу можно решить двумя способами
Дублирование данных
Можно копировать данных из таблицы {$wpdb->prefix}rcl_rating_totals
плагина WP Recall в метаданные для wpDiscuz. Это можно делать по крону или на событии оценки комментария. Рабочий способ, но так мы способствуем росту базы данных, да и выборки по метаполям как известно не отличаются быстродействием.
Подмена запроса
Что если выборку по метаполям заменить на выборку по таблице WP Recall? Плагин wpDiscuz скуп на собственные фильтры, вмешаться тут не выйдет, но благодаря системному фильтру comments_clauses мы можем это сделать!
Посмотрим какие в оригинале данные проходят через фильтр:
add_filter( 'comments_clauses', function ( $args ) { error_log( print_r( $args, true ) ); return $args; } ); // Получим следующее (оставил только то, что относится к wpDiscuz) Array ( [fields] => kw_comments.comment_ID [join] => LEFT JOIN kw_commentmeta AS `cm` ON kw_comments.comment_ID = `cm`.comment_id AND (`cm`.meta_key = 'wpdiscuz_votes') [where] => ( ( comment_approved = '0' OR comment_approved = '1' ) ) AND comment_post_ID = 93644 AND comment_type NOT IN ('wpdiscuz_sticky') AND comment_parent = 0 [orderby] => IFNULL(`cm`.meta_value,0)+0 DESC, kw_comments.`comment_ID` asc [limits] => LIMIT 0,51 [groupby] => [caller] => wpdiscuz- ) Array ( [fields] => kw_comments.comment_ID [join] => LEFT JOIN kw_commentmeta AS `cm` ON kw_comments.comment_ID = `cm`.comment_id AND (`cm`.meta_key = 'wpdiscuz_votes') [where] => ( ( comment_approved = '0' OR comment_approved = '1' ) ) AND comment_post_ID = 93644 AND comment_type IN ('wpdiscuz_sticky') AND comment_parent = 0 [orderby] => IFNULL(`cm`.meta_value,0)+0 DESC, kw_comments.`comment_ID` asc [limits] => [groupby] => [caller] => wpdiscuz- )
Увидя паттерн, можно изменить запрос на следующий:
add_filter( 'comments_clauses', function ( $args ) { global $wpdb; $is_wpdiscuz = isset( $args['caller'] ) && $args['caller'] === 'wpdiscuz-'; if ( $is_wpdiscuz && strpos( $args['join'], 'wpdiscuz_votes' ) !== false ) { $args['join'] = "LEFT JOIN {$wpdb->prefix}rcl_rating_totals AS `cm` ON $wpdb->comments.comment_ID = `cm`.object_id"; $args['orderby'] = str_replace( 'meta_value', 'rating_total', $args['orderby'] ); } return $args; }, 11 ); // Получим Array ( [fields] => kw_comments.comment_ID [join] => LEFT JOIN kw_rcl_rating_totals AS `cm` ON kw_comments.comment_ID = `cm`.object_id [where] => ( ( comment_approved = '0' OR comment_approved = '1' ) ) AND comment_post_ID = 93644 AND comment_type NOT IN ('wpdiscuz_sticky') AND comment_parent = 0 [orderby] => IFNULL(`cm`.rating_total,0)+0 DESC, kw_comments.`comment_ID` asc [limits] => LIMIT 0,51 [groupby] => [caller] => wpdiscuz- ) Array ( [fields] => kw_comments.comment_ID [join] => LEFT JOIN kw_rcl_rating_totals AS `cm` ON kw_comments.comment_ID = `cm`.object_id [where] => ( ( comment_approved = '0' OR comment_approved = '1' ) ) AND comment_post_ID = 93644 AND comment_type IN ('wpdiscuz_sticky') AND comment_parent = 0 [orderby] => IFNULL(`cm`.rating_total,0)+0 DESC, kw_comments.`comment_ID` asc [limits] => [groupby] => [caller] => wpdiscuz- )
Заметьте, я использовал в коде несколько уточнений, чтобы он применился только в нужном месте, так как фильтр comments_clauses является системным и срабатывает всегда при вызове функции get_comments().
PS: С недавних пор запрос был изменён, возможно единичный случай.
// Изменяет запрос сортировки wpDiscuz -> WP Recall по популярным комментариям add_filter( 'comments_clauses', function ( $args ) { global $wpdb; if ( isset( $args['caller'] ) && $args['caller'] === 'wpdiscuz-' && ! is_admin() && is_singular( 'post' ) ) { if ( strpos( $args['where'], "comment_post_ID = " . get_the_ID() ) !== false ) { $args['join'] = "LEFT JOIN {$wpdb->prefix}rcl_rating_totals AS `cm` ON $wpdb->comments.comment_ID = `cm`.object_id"; $args['orderby'] = "IFNULL(`cm`.rating_total,0)+0 DESC, $wpdb->comments.comment_ID asc"; } } return $args; }, 11 );
Список изменений
С версии 3.1.0 | Введена. |
Где вызывается хук
$clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );