Правильное удаление записей с метаданными и вложениями
У меня есть обзор пользовательских типов записей. У них есть пользовательские таксономии, а также вложения.
В моем обзоре мне нужно предоставить ссылки для удаления записей. При этом мне также нужно удалить вложение и метаданные.
Я использовал это:
if ( !current_user_can( 'delete_bkroadkill', $post->ID ) )
return;
$link = "<a href='" . wp_nonce_url( get_bloginfo('url') . "/wp-admin/post.php?action=delete&post=" . $post->ID, 'delete-post_' . $post->ID) . "'>".$link."</a>";
echo $before . $link . $after;
Я нашел Ссылка для удаления записи, ее метаданных и вложений, но там нет готового решения.
Этот код удаляет только запись, но ничего больше. Как правильно это сделать?
Я использую этот код для удаления связанных медиафайлов с записью. Если вам нужно проверить определённый тип записи, вы можете использовать глобальную переменную global $post_type
. По сути, код получает все вложения и удаляет их по одному. Ссылка на источник
function delete_associated_media( $id ) {
$media = get_children( array(
'post_parent' => $id,
'post_type' => 'attachment'
) );
if( empty( $media ) ) {
return;
}
foreach( $media as $file ) {
wp_delete_attachment( $file->ID );
}
}
add_action( 'before_delete_post', 'delete_associated_media' );

Хотя это работает, я бы предложил создать массив ID для удаления, затем сформировать кастомный запрос и выполнить его. Ваш вариант выполнит несколько запросов для удаления вложений; возможно, это не проблема для 3 или 4, но если у вас 100 вложений, это может значительно замедлить работу.

Этот код выполняет не больше запросов, чем ваш. Он делает один запрос для получения вложений, затем один запрос для их удаления, всё через WordPress, без кастомного SQL.

Неверно. Вы делаете один запрос к базе данных для получения всех вложений, а затем по одному запросу на каждое вложение при их удалении; 10 вложений = 11 запросов в сумме. Я делаю один запрос для получения всех вложений и один запрос для удаления всех связанных записей; 10 вложений = 2 запроса. Стоит отметить, что ваш код также удаляет файл, тогда как мой просто удаляет проблемную строку из базы данных. Думаю, это вопрос предпочтений, но для производительности я бы сделал по-своему, а затем запустил бы очистку для удаления несвязанных вложений (это мог бы обработать простой плагин).

Я понимаю, о чем вы. Я думал, что смысл в том, чтобы полностью удалять вложения при удалении записи.

Возможно, автор вопроса имел это в виду, наверное, зависит от интерпретации. Исходя из прошлого опыта, я заметил, что исключение потенциально трудоемких задач по обслуживанию из пользовательского интерфейса способствует лучшему взаимодействию, поэтому я интерпретировал это именно так.

@s_ha_dum предполагает, что метаданные записи будут удаляться автоматически. Поэтому, учитывая его репутацию, можно предположить, что он знает, о чем говорит. Данное решение обрабатывает только вложения записи.
Рекомендую ознакомиться с документацией по хуку before_delete_post(), так как он позволяет проверять тип удаляемой записи и другие параметры.
add_action('before_delete_post', 'delete_post_attachments');
function delete_post_attachments($post_id){
global $post_type;
if($post_type !== 'my_custom_post_type') return;
global $wpdb;
$args = array(
'post_type' => 'attachment',
'post_status' => 'any',
'posts_per_page' => -1,
'post_parent' => $post_id
);
$attachments = new WP_Query($args);
$attachment_ids = array();
if($attachments->have_posts()) : while($attachments->have_posts()) : $attachments->the_post();
$attachment_ids[] = get_the_id();
endwhile;
endif;
wp_reset_postdata();
if(!empty($attachment_ids)) :
$delete_attachments_query = $wpdb->prepare('DELETE FROM %1$s WHERE %1$s.ID IN (%2$s)', $wpdb->posts, join(',', $attachment_ids));
$wpdb->query($delete_attachments_query);
endif;
}
Важное примечание из упомянутой документации -
Важно отметить, что хук срабатывает только тогда, когда пользователь WordPress очищает корзину. Если вы используете этот хук, имейте в виду, что он не сработает при удалении вложения, поскольку вложения удаляются сразу, минуя корзину. Вместо этого используйте хук delete_post().
Еще одно примечание
Следует упомянуть, что хотя код в этом ответе удалит все строки из базы данных, связанные с вложениями записи, сами файлы вложений не будут удалены.
Причина этого — производительность. В зависимости от количества вложений, их удаление по одному может занять много времени. Я считаю, что лучше сначала удалить только записи из базы данных для всех вложений, чтобы улучшить пользовательский опыт, а затем выполнить дополнительную очистку для удаления самих файлов вложений (достаточно просто найти и удалить файлы, не связанные с записями). В общем, меньше запросов + меньше работы во время взаимодействия с пользователем = меньше времени.

Я обновил свой ответ (очевидно, замените my_custom_post_type
на соответствующий тип записи). Также проверьте ссылку в посте на хук before_delete_post(), там всё подробно объяснено.
