Almost every tool that copies a post from one WordPress site to another works the same way. An editor clicks Publish. The origin site opens an HTTP connection to each destination and sends the whole post over the REST API. When the last destination answers, the editor gets their screen back.
It is the obvious design, and for two sites it is a perfectly good one. The trouble is that its costs do not grow gently. They grow with the number of sites, the number of posts and the slowest server in the group — all at once, and all inside one editor's request. This post walks through the three places it gives way, and what changes when you stop pushing.
Failure one: the work happens in the wrong place
In a push model, the origin does everything. It serialises the post, uploads the media, waits for each destination to write to its database, and only then moves to the next one. Every one of those steps happens inside the PHP request that started when the editor clicked the button.
That request has a budget: max_execution_time, usually 30 to 60 seconds, and a memory_limit. One post to five sites fits. A bulk change to a few dozen posts, multiplied by five sites, does not — and when PHP kills the request, it does not roll anything back. Some sites have the change and some do not, and nothing on the origin recorded which.
The fix is not a bigger timeout. It is to stop doing remote work inside an editor's request at all.
Failure two: a failed push is a lost post
Pushing assumes the destination is there. Servers are not always there. They are mid-deploy, or rate-limiting, or restarting PHP, or down for ten minutes at 3am.
When a push fails, most tools report an error and stop. There is no queue behind it. If nobody is watching, the destination comes back an hour later and is simply missing everything that was published while it was away — with no record, on either side, of what it missed.
This is the difference between a message and a log. A message is sent once and is either received or lost. A log is written once and can be read by anyone, at any time, from any position. Kafka made this idea familiar in backend engineering: producers append, consumers keep their own offset, and a consumer that was offline resumes from where it stopped.
The same shape works inside WordPress. The hub appends every change to an ordered event log — a cheap, local database write. Each node remembers the last event it applied. A node that was down does not need to be rescued. It asks for everything after its cursor and replays it, in order.
Failure three: the links are wrong everywhere but home
This is the failure that does not show up in the CMS at all. A story written on the hub links to other hub stories. Copy that HTML to a sister site and each of those links now does one of two things: it sends the reader away to another domain, or it points at a URL that does not exist on this site.
The first quietly moves sessions and internal link equity off the local title. The second is a 404 in front of a reader and a crawler.
The origin cannot fix this before sending, because the right answer is different on every destination. Whether this site carries the linked story is something only this site knows. So the decision has to move to the receiving end: the hub describes each link and where its target has been distributed, and the node decides — its own copy first, then a sister site that carries it, and if neither exists, plain text rather than a dead link. We wrote that up in detail on the Features page.
What pull does not solve
Moving to an event log and node-side pulls takes the network out of the editor's request, makes outages recoverable and puts link decisions where the knowledge is. It does not make WordPress a batch-processing system.
A manual bulk operation on the hub still runs as one PHP request on one thread. Appending events is far cheaper than pushing posts, but a bulk action over a large slice of an archive is still a large job in a small box. Routine daily publishing is what this architecture is built for; back-filling years of history is a migration, and migrations belong in WP-CLI, in batches, with pauses. We keep the specifics in the scale note.
The short version
- Push puts all the work in the editor's request, loses whatever a destination was not there to receive, and copies links that are only correct on the origin.
- An event log with per-node cursors makes publishing a local write, makes catch-up automatic, and lets each site resolve links for its own domain.
- Neither turns a wp-admin bulk action into a migration tool. Use the CLI for that.
If you run a network of WordPress titles and recognise any of the three failures, tell us which in the comments — or write to hello@editorialpack.io.
Loading comments…