案例:使用 ACF,我为我的画廊创建了一个转发器字段“resort_pics”,其中有 2 个字段“picture_title”作为文本,“picture”作为图片类型。
然后愉快地上传了 100 张照片,其中一些帖子在几个帖子中是相同的,所以我只从上传的图库中点击了那些(我将使用“参考图像”一词来表示这些)。
问题:然后有一天,我发现我们的 api 中缺少所有“引用的图像”。
原因:如“Uriahs Victor”(https://developer.wordpress.org/reference/functions/get_attached_media/)的文档评论中所述
需要注意的是,此函数仅返回第一次上传/添加到帖子的附件。如果使用以下代码,则将图像上传到帖子 A(ID 1)然后将该图像稍后添加到帖子 B(ID 2)将给出一个空数组:
$media = get_attached_media( 'image', 2 );
var_dump( $media );
真正的原因:所有这些问题的真正根源是关于“参考图像”的信息没有存储在“wp_posts”表中,但实际上存储在“wp_postmeta”中,所以只需查询“wp_posts”表或使用get_attached_media()只看那里你也不会得到所有的附件。
解决方案:让我们以 ID 的帖子为例 - $postId 定义了转发器 - 'resort_pics',转发器中的字段与图像'图片'。(使用 ACF 插件创建)
首先以经典方式(也可以使用'get_attached_media')获取我们帖子(度假村)的所有附件(包括图像/pdf等):
$images = $wpdb->get_results("select ID,guid from wp_posts where post_parent = " . $postId . " and `post_type`= 'attachment'");
其中 guid 是附件的“url”,让我们索引数组中的那些,其中键将是附件的 post id
$mapImages = [];
foreach ($images as $image) {
$mapImages[$image->ID] = $image->guid;
}
现在我们有了所有附件,但缺少所有引用的图像/文件。
让我们继续为我们的帖子(度假村)选择所有元数据。
$metas = $wpdb->get_results("select meta_key,meta_value from wp_postmeta where post_id=" . $postId);
并通过元键索引它们
$mapMetas = [];
foreach ($metas as $meta) {
$mapMetas[$meta->meta_key] = $meta->meta_value;
}
假设我们的帖子 ($postId) 在 'resort_pics' 中有 9 个条目,其中一个图像上传到它的 'picture' 字段,那么 $mapMetas['resort_pics'] 的值将是 8。现在转发器字段键的方式存储在 $mapMetas 数组中,实际上是一个:
'resort_pics_0_picture' -> itsPostId (5640 for example)
'resort_pics_1_picture' -> itsPostId (5641 for example)
'resort_pics_2_picture' -> itsPostId (5642 for example)
...
'resort_pics_8_picture' -> itsPostId (5648 for example)
知道了这一点,我们可以简单地获得“resort_pics”的所有图片网址
for ($i = 0; $i < $mapMetas['resort_pics']; $i++) {
$picture = [];
$picture['name'] = $mapMetas['resort_pics_' . $i . '_picture_title'];
$picture['url'] = $mapImages[$mapMetas['resort_pics_' . $i . '_picture']];
$pictures[] = $picture;
}
您可能已经到了这一点,只需从 $mapMetas 获取图像 ID 并使用它从 $mapImages 获取图像 url。
假设“resort_pics_1_picture”是“引用”的(不是直接上传的图片),我们有它的 id '5641',但由于它没有连接到我们的 $postID,而是连接到实际上传的其他一些帖子 id。它在我们的 $mapImages 数组中丢失了,所以让我们稍微编辑一下这段代码。
for ($i = 0; $i < $mapMetas['resort_pics']; $i++) {
$picture = [];
$picture['name'] = $mapMetas['resort_pics_' . $i . '_picture_title'];
$picture['url'] = getAttachmentOrItsReferenceUrl('resort_pics_' . $i . '_picture', $mapImages, $mapMetas);
$pictures[] = $picture;
}
我们添加了一个getAttachementOrItsReferenceUrl()方法,它会首先检查我们是否已经有这张图片(全部上传到这篇文章),如果没有,它将通过它的帖子 id 从“wp_posts”表中获取图像数据。
function getAttachmentOrItsReferenceUrl($code, $allAttachmentById, $allPostMetaByKey) {
global $wpdb;
$attachmentUrl = $allAttachmentById[$allPostMetaByKey[$code]];
if($attachmentUrl === null && isset($allPostMetaByKey[$code]) && $allPostMetaByKey[$code] !== '') {
$attachments = $wpdb->get_results("select ID,guid from wp_posts where ID = " . $allPostMetaByKey[$code]);
foreach ($attachments as $image) {
return $image->guid;
break;
}
} else {
return $attachmentUrl;
}
return "";
}
最后的想法:如果你知道你的字段结构,你可以非常简单地建立它的键例如'rooms'中继器,它具有内部'room_gallery'中继器,它具有内部'image'图像字段。
'rooms_0_room_gallery_0_image'
--
$mapMetas['rooms'] - number of rooms
$mapMetas['rooms_' . $i . '_room_gallery'] - number of gallery images for room
--
'rooms_' . $i . '_room_gallery_' . $j . '_image'
它有多重?并非如此,如果您像我一样,只有少量参考图像,您甚至都不会感觉到。我们添加到加载的只是一个帖子的元查询,如果没有引用图像就这样,那么对于每个引用的图像都会有一个更多的查询,但它对 ID 的查询应该很快。有很多方法可以减少负载,例如,不要查询每一个丢失的图像,而是在末尾使用“where in (id1,id2..)”进行单个查询,以便通过单个查询来获取所有图像,或者在获取新的图像数据后,通过其 id 将其存储在某个全局数组中,并在为下一个帖子获取图像之前检查此数组(因此,如果一个图像存储在 200 个帖子中,并且您正在获取所有内容,则它只会进行 1 个查询) ,你明白了,我把它留在了想法上,因为即使没有这个,这篇文章也太长了:
希望这对将来的任何人都有帮助。