wordpress 如何删除和防止创建具有重复post_names的帖子

xpcnnkqh  于 2023-05-06  发布在  WordPress
关注(0)|答案(1)|浏览(102)

首先感谢大郡
第二声
即时通讯有问题,在相同的职位,它显示2个职位与相同的名称与2个不同的内容和id的职位
我尝试禁用所有插件和更改主题与“二十十九”
刷新后无任何变化
我也检查主题
我用这个sql找到2个帖子我在一个帖子里看到它

SELECT id, post_title, post_status, post_type, SUBSTR(post_content, LOCATE('Carob is an evergreen flowering tree whose', post_content) -1, 100) FROM wpw8_posts WHERE locate('Carob is an evergreen flowering tree whose', post_content) > 0

如何检查此问题我尝试调试,但没有显示为错误或问题页面
我可以附加content-single.php和single.php,但我已经设置为wordpres的默认主题,所以我不知道我在哪里可以找到这个问题
“使用autopost插件发布make”

nfg76nw0

nfg76nw01#

检查和删除重复的post slug(post_name)的代码可以类似于下面的示例。它使用了WordPress的action hook save_post

警告:在现场/生产现场测试之前,先在开发/测试现场测试所有代码!

此代码尚未测试。默认情况下,WordPress通过在帖子保存到数据库之前自动更改post_name来避免重复的post_names。在你的例子中,你的插件可能正在做一些事情来避免默认的行为。在将其部署到活动站点之前,请在测试站点上对其进行测试。在部署之前,请记住备份您的数据库。

删除重复帖子

function delete_post_with_duplicate_post_name( $post_id, $post, $update ) {
    $force_delete = false;

    // Do not touch updates to existing posts.
    if ( $update ) {
        return;
    }

    $posts = \get_posts( array(
        'post_name__in' => array( $post->post_name ),
        'post_status' => 'publish',
        'numberposts' => 2
    ) );

    if ( 2 === count( $posts ) ) {
        \wp_delete_post( $post_id, $force_delete );
    }
}

add_action( 'save_post', 'delete_post_with_duplicate_post_name', 10, 3 );

$force_delete选项控制帖子是立即发送到垃圾桶还是永久删除。如果被发送到垃圾桶,您有机会看到作者是谁,确定帖子是否应该替换原始帖子,并在需要时恢复它。

搜索重复帖子

搜索重复帖子的SQL查询可能如下所示:

use DATABASE_NAME;

SELECT COUNT(*) AS Count, P.post_name
FROM wp_posts P
WHERE P.post_name <> ''
  AND P.post_status = 'publish'
GROUP BY P.post_name
HAVING Count > 1;

找到重复的帖子后,您可以在管理员中再次查询帖子ID并删除帖子。

更新#2:删除所有重复的帖子

以下代码未经测试

代码应该删除所有基于post_namepost_status的重复帖子。您可以将其添加到插件或子主题的主文件中,使用它来删除重复的帖子,然后在删除重复的帖子后将其删除。
删除帖子的语句已注解掉以供测试。首先,在从该语句中删除注解之前,确认代码找到了正确的帖子。
代码必须从WordPress内部执行,而不是直接在数据库上执行,因为wp_delete_post函数会删除与帖子相关的 meta数据和其他实体。阅读wp_delete_post上的WP文档

function dangerously_delete_duplicate_posts() {
    global $wpdb;
    $force_delete = false;

    $order = 'ASC';

    $table_prefix = $wpdb->prefix;

    // Find duplicate slugs.
    $sql  = "";
    $sql .= "SELECT COUNT(*) AS Count, P.post_name";
    $sql .= " FROM {$table_prefix}posts P";
    $sql .= " WHERE P.post_name <> ''";
    $sql .= " AND P.post_status = 'publish'";
    $sql .= " GROUP BY P.post_name";
    $sql .= " HAVING Count > 1";
    $sql .= ";";

    $post_names = $wpdb->get_col( $sql, 1 );

    if ( count( $post_names ) > 0 ) {

        // Find IDs of duplicates.
        $query = "SELECT DISTINCT P.ID, P.post_name, P.post_date";
        $query .= " FROM {$table_prefix}posts P";
        $query .= ' WHERE P.post_name IN (' . implode(', ', array_fill(0, count( $post_names ), '%s') ) . ')';
        $query .= " AND P.post_status = 'publish'";
        $query .= " ORDER BY P.post_name, P.post_date {$order}";
        $query .= ";";

        $sql2 = call_user_func_array(
            array( $wpdb, 'prepare' ),
            array_merge(
                array( $query ),
                $post_names
            )
        );

        $posts = $wpdb->get_results( $sql2, 'ARRAY_A' );
        $previous_posts = array();
        $found_posts = array();

        // Delete all except the earliest posts for each set of duplicate posts.
        foreach ( $posts as $index => $current ) {
            if ( $index > 0 && $current['post_name'] !== $previous_posts[0]['post_name'] ) {
                foreach ( $previous_posts as $index2 => $previous_post ) {
                    if ( $index2 > 0 ) { // Avoid deleting the first post.
                        /**
                         * Remove the comment from this line when you have
                         * confirmed the correct posts are found.
                         */
                        // \wp_delete_post( $previous_post['ID'], $force_delete );

                        /**
                         * For testing.
                         * Comment out the line below when you have
                         * confirmed the correct posts are found.
                         */
                        $found_posts[] = $previous_post;
                    }
                }
                $previous_posts = array();
            }
            $previous_posts[] = $current;
        }
        foreach ( $previous_posts as $index3 => $previous_post ) {
            if ( $index3 > 0 ) {
                \wp_delete_post( $previous_post['ID'], $force_delete );
            }
        }
    }

    /**
     * For testing.
     * Comment out the line below when you have
     * confirmed the correct posts are found.
     * Instead of echo you could save the result
     * from print_r() to a file and use the file
     * as a reference when verifying the posts in
     * the database or in the WP Admin pages.
     */
    echo print_r( $found_posts, true );
}

add_action( 'init', 'dangerously_delete_duplicate_posts', 10, 1 );

UPDATE #3防止重复发布

由于“autopost”插件不使用REST API,您至少有下面列出的四个选项-其中三个不需要cron。

1. delete_post_with_duplicate_post_name(不需要cron)

delete_post_with_duplicate_post_name函数添加到您自己的插件或子主题中。并包括add_action( 'save_post', 'delete_post_with_duplicate_post_name', 10, 3 );

2. dangerously_delete_duplicate_posts(不需要cron)

dangerously_delete_duplicate_posts函数添加到您自己的插件或子主题中。并包括add_action( 'init', 'dangerously_delete_duplicate_posts', 10, 1 );

3. cron

如果您不希望选项**1.2.**对每个服务器请求执行,则可以使用cron根据您设计的计划降低执行代码的频率。一些服务器提供了cron接口,以便于配置。有些服务器并不容易,您必须自己编写命令行代码。cron的基本思想是配置一个定期的调度来在服务器上执行PHP脚本。这不容易解释,因为它可能需要使用WordPress CLI或编写使用数据库凭证直接访问数据库的PHP脚本。我认为避免cron对你来说更容易。

4. WordPress cron任务(不需要cron)

WordPress Cron Scheduling是我认为最好的选择。它几乎与standard cron类似,但不需要编写和向服务器添加特殊的PHP脚本。您可以按照下面列出的步骤操作。要了解更多信息,您可以查看Cron Scheduling的WordPress文档中的示例。
WordPress cron和标准cron的主要区别是:标准的cron可以通过精确的时间设置,以精确的、规则的时间间隔执行脚本。WordPress cron的时间间隔和执行时间并不精确。如果请求页面的时刻发生在间隔之后,则在该时刻执行脚本或函数。精确的时间间隔对于清理重复的帖子并不重要。因此,WordPress cron可以很好地实现这一目的。

第一步:添加危险的_删除_重复的_帖子

dangerously_delete_duplicate_posts函数添加到您自己的插件或子主题中。并且包含语句add_action( 'save_post', 'dangerously_delete_duplicate_posts', 10, 3 );

步骤1.1:更新SQL查询

既然你知道“autopost”插件会在draft模式下创建重复的帖子,那么应该更新dangerously_delete_duplicate_posts中的两个SQL查询,以查找状态为 publishdraft 的帖子。

编辑$sql查询

$sql查询需要有这一行:

$sql .= " AND P.post_status = 'publish'";

。。。改成。。

$sql .= " AND ( P.post_status = 'publish' OR P.post_status = 'draft' )";
编辑$query查询

而**$query**查询中的这些行需要更改为:

$query .= " AND P.post_status = 'publish'";
$query .= " ORDER BY P.post_name, P.post_date {$order}";

到...

$query .= " AND ( P.post_status = 'publish' OR P.post_status = 'draft' )";
$query .= " ORDER BY P.post_name ASC, P.post_status DESC, P.post_date {$order} ASC";

这些更改首先按 post_name 对搜索结果进行排序,然后按 post_status,然后按 post_date,以便 publish posts在 draft posts之前列出。此排序顺序假定您要保留的帖子在您要删除的帖子之前发布。

第二步:计划WP Cron

将以下代码添加到步骤#1中的同一插件或子主题中。这将每小时调用一次dangerously_delete_duplicate_posts函数。这可能比在每个页面请求上调用该函数的频率低得多,并且有助于避免降低网站性能。

if ( ! wp_next_scheduled( 'my_duplicate_posts_preventer' ) ) {
    wp_schedule_event( time(), 'hourly', 'my_duplicate_posts_preventer' );
}

add_action( 'my_duplicate_posts_preventer', 'dangerously_delete_duplicate_posts' );

第三步(可选)

它可能不适用于您的情况,但如果您需要取消安排WordPress cron任务,您可以按照WordPress文档中的说明进行操作。

UPDATE #4创建帖子前防止重复帖子

wp_insert_post的WordPress文档列出了相关的钩子。钩子wp_insert_post_empty_content在帖子被保存之前触发,这对于防止创建重复的帖子是非常完美的。钩子将未保存的post信息传递给钩子回调函数,该函数可用于测试重复项。

钩子的目的是测试是否有空的 titleexcerptauthor。开发者可以在钩子回调中编写自己的测试条件,返回 true(Post为空,不会保存)或 false(Post不为空,保存)。当返回 true 时,钩子会产生以下错误消息:* 发布失败。内容、标题和摘录为空。* 或 * 更新失败。内容、标题和摘录为空。*。
下面的代码演示了如何使用这个钩子来防止重复的帖子。

prevent_duplicate_post()

自动草稿帖

当选择 * 添加新文章 * 选项时,WordPress会自动创建一个post_status为auto-draft的占位符文章。如果 wp_insert_post_empty_content 回调函数(下面的prevent_duplicate_post函数)返回 true,则自动草稿帖子不会自动删除。要删除这些自动草稿帖子,您可以在回调函数中调用wp_delete_auto_drafts(),或者使用WordPress Cron调度函数。**wp_delete_auto_drafts()**删除7天以上的自动草稿帖子。有了WordPress的Cron-schedule功能,您可以使用常规的时间表和自定义的延迟(例如:删除3天以上的自动草稿帖子)。

/**
 * Callback function for 'wp_insert_post_empty_content' filter hook.
 *
 * @param $maybe_empty bool  Whether the post should be considered "empty".
 * @param $post_info   array Associative array of Post data.
 *
 * @return bool
 */
function prevent_duplicate_post( bool $maybe_empty, array $post_info ) {
    global $wpdb;
    $table_prefix = $wpdb->prefix;
    $title = $post_info['post_title'];
    $post_id = $post_info['ID'];

    // Find duplicate post titles.
    $sql  = "";
    $sql .= "SELECT P.post_title";
    $sql .= " FROM {$table_prefix}posts P";
    $sql .= " WHERE P.post_title = %s";
    $sql .= " AND ( P.post_status = 'publish' OR P.post_status = 'draft' )";
    $sql .= " AND ( P.ID <> %d )";
    $sql .= ";";

    $sql2 = $wpdb->prepare( $sql, $title, $post_id );
    $wpdb->query( $sql2 );

    if ( $wpdb->num_rows > 0 ) {
        wp_delete_auto_drafts();
        return true; // Duplicate found. Reject post creation.
    } else {
        return false; // No duplicate found. Create the post.
    }
}
add_filter( 'wp_insert_post_empty_content', 'prevent_duplicate_post', 10, 2 );

相关问题