Background
I am writing a migration tool that can move (copy, then delete) posts from one site on a multi-site network to another. I want to correctly separate concerns, and from that point of view it seems that in order to migrate a post from one site to another you need two things:
- The post - in WP represented by a
WP_Post
object. - The site ID - ID of the site to migrate it to.
Question
How can I, being given only a WP_Post
instance, get the ID of the site it belongs to?
Remarks
Foreseeing answers that just use get_current_blog_id()
: that will get the ID of the current site, whatever that is. I want the ID of the site that the given post belongs to.
For those saying "if you're working with a post, you probably know where it came from, because you queried for it":
function doSomethingWithPost(WP_Post $post)
{
// No, I do not know that
}
It appears that the WP_Post
object does not contain the information necessary to track it to its site. Ticket #51373 raised in relation to this problem.
Background
I am writing a migration tool that can move (copy, then delete) posts from one site on a multi-site network to another. I want to correctly separate concerns, and from that point of view it seems that in order to migrate a post from one site to another you need two things:
- The post - in WP represented by a
WP_Post
object. - The site ID - ID of the site to migrate it to.
Question
How can I, being given only a WP_Post
instance, get the ID of the site it belongs to?
Remarks
Foreseeing answers that just use get_current_blog_id()
: that will get the ID of the current site, whatever that is. I want the ID of the site that the given post belongs to.
For those saying "if you're working with a post, you probably know where it came from, because you queried for it":
function doSomethingWithPost(WP_Post $post)
{
// No, I do not know that
}
It appears that the WP_Post
object does not contain the information necessary to track it to its site. Ticket #51373 raised in relation to this problem.
1 Answer
Reset to default 1No, post objects do not store this data. You need to store the site ID separately.
Post objects do not store the site they were created on or are currently hosted on. That information doesn't exist in the posts table, nor does WordPress track it elsewhere. The assumption is always that the post comes from the current site.
The code you're writing will need to store the source site ID somehow. Some plugins do this via post meta.
If you already have posts that have been migrated though, would have to load up each site, and query for the post with the same ID, then compare them, and if they match, you've found it. This assumes no modifications have been made at either end.
Q: How do we know this?
Because there is nowhere in WP_Post
that stores the site ID or network ID. Inspecting a variable holding a post object shows this information isn't available either.
Q: What do other plugins/developers do?
If they need to migrate a post to another site, but also need to trace it back to its source, they store those details in post meta.
For example, the original URL, site ID, and post ID can be stored as post meta. This is useful for UI purposes, telling a user that the post has been migrated or syndicated. This is what the syndicator and distributor plugins do.
Q: Can the GUID be used?
No, GUID's aren't always URLs, aren't always current, and don't always represent the source.
For example, a GUID will not change if a posts slug or URL changes, the GUID can be a hash not a URL, the GUID may be a remote URL, or it may be a URL from an old permalink structure or an old site URL.
Q: Do we need to get the site ID from a post object?
No! If you have a post object then at some point you were in the context of the site it came from. Pass the site ID as a second parameter.
Ideally, your function should receive a post ID and a site ID, not a post object:
function doSomethingWithPost( int $post_id, int $site_id=0 ) {
switch_to_blog( $site_id );
$post = get_post( $post_id );
// ....
restore_current_blog();
}
Or, the site should be assumed to be the current site, and switch_to_blog
called beforehand, e.g.:
switch_to_blog( $site_id );
doSomethingWithPost($post_id);
restore_current_blog();
I recommend passing the site ID as a function parameter so that good dependency injection can be practiced.
WP_Post
, it doesn't meant that the code invoking that function is in the same package, or that it's under my control. – XedinUnknown Commented Sep 22, 2020 at 10:11WP_Post
objects are just data containers, they don't belong to anything, or provide any guarantees. E.g. there's no guarantee that aWP_Post
object has a row in the database, you can do$p = new \WP_Post()
or use a post object after the post is deleted. The APIs around post objects don't account for posts on any site other than what's considered current – Tom J Nowell ♦ Commented Sep 22, 2020 at 15:07