Удаляем комментарии ветками

Предлагаю вниманию хук для удаления всех дочерних комментариев при удалении комментария, т.е. мы удаляем комментарий и вместе с ним удаляются все его дочерние комментарии, и дочерние дочерних, и так далее. Другими словами, при удалении комментария удалится вся ветка ответов на него.

Чтобы "удаление ветками" начало работать вставляем код в файл темы functions.php.

/**
 * Удаление всех дочерних комментариев (всего дерева) при удалении комментария
 */
add_action( 'delete_comment', 'del_child_comments_on_del_comment' );

function del_child_comments_on_del_comment( $comment_id ) {
	global $wpdb;

	$child_comments = $wpdb->get_col(
		"SELECT comment_ID FROM $wpdb->comments WHERE comment_parent='$comment_id'"
	);

	// если нет детей, возвращаем
	if( ! $child_comments ){
		return;
	}

	foreach( $child_comments as $val ){
		wp_delete_comment( $val );
	}
}

Ключевые моменты хука: фильтр - delete_comment и функция - wp_delete_comment():

Над кодом я просидел прилично, потому что тут используется рекурсия, а она часто вредная и я с ней не очень...

В программировании рекурсия — вызов функции из неё же самой (простая рекурсия) или через другие функции (сложная или косвенная рекурсия). Например, функция A вызывает функцию B, а функция B — функцию A. Количество вложенных вызовов функции или процедуры называется глубиной рекурсии.

Сидел сначала и пробовал натурально использовать рекурсию (написал функцию, повесил её на хук и вызывал её из нее же самой) — что надо не выходило, а код только рос. В один момент, как только я пошел налить себе чайку, пришла её величество Эврика и я все понял: замыкание будет происходить при срабатывании хука delete_comment в момент очередных вызовов функции wp_delete_comment() и не надо вызывать функцию из функции в чистом виде, т.е. будет косвенная рекурсия.

Честно говоря, плохо могу себе представить реальную ситуацию, на обычном блоге, где бы такое удаление комментариев было особо нужно. Однако, оно логично и может кому-то понадобится. На этом блоге я сделал именно так, потому что, если удалить комментарий у которого есть дочерние комментарии, то смысл дочерних комментариев чаще всего будет просто потерян: будут комментарии не понятно о чем. Приводя аллегорию — это комментарии к посту, без самого поста. Думаю, мне такое тут не надо.

Перемещение в корзину

После того, как задача с удалением была решена, по проторенной дороге, я написал такое же перемещение комментариев ветками в корзину и извлечение их ветками из корзины.

Принцип тот же самый, только используются теперь фильтры: trash_comment, untrash_comment и функции: wp_trash_comment(), wp_untrash_comment():

/**
 * Перемещение в корзину всех дочерних комментариев (вся глубина дерева), при удалении комментария
 */
add_action( 'trash_comment', 'trash_child_comments_on_trash_comment' );
function trash_child_comments_on_trash_comment( $comment_id ) {
	global $wpdb;

	// если нет детей, возвращаем
	$child_comments = $wpdb->get_col(
		"SELECT comment_ID FROM $wpdb->comments WHERE comment_parent='$comment_id'"
	);
	if( ! $child_comments ){
		return;
	}

	foreach( $child_comments as $val ){
		wp_trash_comment( $val );
	}
}

add_action( 'untrash_comment', 'untrash_child_comments_on_untrash_comment' );
function untrash_child_comments_on_untrash_comment( $comment_id ) {
	global $wpdb;

	// если нет детей, возвращаем
	$child_comments = $wpdb->get_col(
		"SELECT comment_ID FROM $wpdb->comments WHERE comment_parent='$comment_id'"
	);
	if( ! $child_comments ){
		return;
	}

	foreach( $child_comments as $val ){
		wp_untrash_comment( $val );
	}
}

Упрощенная запись перемещения в корзину

Вот весьма интересный код, для тек кто разбирается в php: упрощенная версия записи для кода выше (для корзины). Здесь интересно посмотреть как можно использовать функцию current_filter() и необычный вызов функции PHP, динамичный, с использованием переменной ($use_function( $val )). В общем, смотрите сами:

/**
 * Перемещение в корзину всех дочерних комментариев (вся глубина дерева), при удалении комментария
 */
add_action( 'trash_comment', 'trash_untrash_child_comments_with_parent' );
add_action( 'untrash_comment', 'trash_untrash_child_comments_with_parent' );
function trash_untrash_child_comments_with_parent( $comment_id ) {
	global $wpdb;

	// если нет детей, возвращаем
	$child_comments = $wpdb->get_col(
		"SELECT comment_ID FROM $wpdb->comments WHERE comment_parent='$comment_id'"
	);
	if( ! $child_comments ){
		return;
	}

	foreach( $child_comments as $val ){
		// получим wp_trash_comment или wp_untrash_comment
		$use_function = 'wp_' . current_filter();
		$use_function( $val );
	}
}