SQL:如何查找任何帖子/页面/CUSTOM_POST_TYPE中未使用的所有附件

时间:2020-04-14 作者:yoho

我有一个wordpress安装,其中的帖子还包含使用media library -> add.

我想查找任何帖子/页面/自定义\\u帖子类型中未使用的所有附件

例如,如果我得到某个月上传的附件的结果,对我来说是可以的january 2017.

下面是我编写SQL的尝试:

select distinct a.*
from (
    select *
    from wp_posts
    where post_type = \'attachment\'
    and post_date between \'2017-01-01\' and \'2017-01-31\'
) as a,
(
    select post_content
    from wp_posts
    where post_type in (\'post\', \'page\', \'custom_post_type_1\', \'custom_post_type_2\', \'custom_post_type_n\')
    and post_status = \'publish\'
) as p
where p.post_content not like CONCAT(\'%/wp-content/uploads/\', DATE_FORMAT(a.post_date, \'%Y/%m\'), \'/\', a.post_name, \'%\')
由于并非所有附件都通过媒体库嵌入到内容中,因此我无法使用:

select *
from wp_posts
where post_type = \'attachment\'
and post_parent = 0;
有人知道更好的方法吗?我的SQL查询速度很慢。

2 个回复
最合适的回答,由SO网友:Tom J Nowell 整理而成

你所追求的并不是真正可能的。你可以接近,但你不能确定附件是否在使用中。

我们可以找到接近解决方案的地方,但要做到这一点,我们需要单独处理每个附件。

因此,首先,获取所有附件ID的列表。使用标准WP_Query 为此,您甚至可以从对象缓存中获得速度提升。

以下是官方日期查询文档:

https://developer.wordpress.org/reference/classes/wp_query/#date-parameters

对于每个附件:

检查附件URL的所有帖子内容和帖子元,删除图像大小,检查所有选项和帖子元,查看附件ID,检查附件是否有帖子父级,如果其中任何一个是真的,则附件可能正在使用中,由于PHP执行限制,无法从浏览器运行查询。您需要成批或通过CLI命令执行附件。最好是100批次。如果您试图一次处理所有47k,PHP将耗尽内存。

然而,测试附件是否正在使用的最有效方法是对整个网站进行爬行并将结果保存在本地,然后在文件夹中搜索URL。请注意,这不会捕获仅在表单提交一次后显示的内容,或RSS特定的内容,以及仅向登录用户显示的内容,等等

SO网友:And Finally

我找到了一个有用的SQL查询here 这解决了汤姆提到的许多问题。为了我的目的,我对它做了一些调整。

$ids = $wpdb->get_col(
    "SELECT i.ID FROM $wpdb->posts i
        WHERE i.post_type = \'attachment\'
        AND i.post_parent > 0
        AND NOT EXISTS (SELECT * FROM $wpdb->posts p WHERE p.ID = i.post_parent)
        AND NOT EXISTS (SELECT * FROM $wpdb->postmeta pm WHERE pm.meta_key = \'_thumbnail_id\' AND pm.meta_value = i.ID)
        AND NOT EXISTS (SELECT * FROM $wpdb->postmeta pm WHERE pm.meta_key = \'_product_image_gallery\' AND pm.meta_value LIKE CONCAT(\'%\', i.ID,\'%\'))
        AND NOT EXISTS (SELECT * FROM $wpdb->posts p WHERE p.post_type <> \'attachment\' AND p.post_content LIKE CONCAT(\'%\', i.guid,\'%\'))
        AND NOT EXISTS (SELECT * FROM $wpdb->postmeta pm WHERE pm.meta_value LIKE CONCAT(\'%\', i.guid,\'%\'))"
);
这应该可以找到所有附件

post_parent 大于0post_parent 指不存在的帖子_thumbnail_id) 对于任何职位guid (这通常意味着附件的URL)不会出现在任何帖子内容中一旦您有了ID列表,您就可以循环查看它并调用wp_delete_attachment( $attachment_id, true ) 强制删除每个附件及其附带的postmeta以及相关的媒体文件。

对产品库ID的查询有点粗糙,虽然对我来说已经足够好了,如果附件的URL与它们的URL不同,那么帖子内容搜索将不适用于您guids