WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

wpDiscuz: сортировка по популярным комментариям на основе данных WP Recall

В данном кейсе используются плагины wpDiscuz и WP Recall, которые дают возможность оценивать комментарии (лайкать). Так как комментарии выводит wpDiscuz, то и сортировку он делает на основе своих данных, хранящихся в метаполях под ключом wpdiscuz_votes. На сайте используется личный кабинет на основе WP Recall и оценивая комментарии через него, пользователь получает карму, на основе которой можно делать всякие плюшки.

Ищем WP-разработчика! Фулл-тайм, удаленка, хорошая зарплата, соц. пакет. Подробности.
Компания Boosta.

Задача: оставить лайки от 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().

Эта заметка встроена в: comments_clauses
campusboy 3919youtube.com/c/wpplus
Создатель YouTube канала wp-plus, на котором делюсь своим опытом. Активный пользователь wp-kama.ru. WordPress-разработчик. Разработка сайтов и лендингов. Доработка существующих проектов. Сопровождение ресурсов.
Комментариев нет
    Войти