Skip to content

Repository files navigation

WP CLI Post Migration

A WP-CLI plugin that imports posts (with their categories and tags) from another WordPress site's REST API, and can later delete everything it imported.

It adds two WP-CLI commands: wp import-posts and wp delete-imported-posts. There is no admin UI — everything runs from the command line.

Requirements

  • WordPress 4.5+
  • PHP 5.6+
  • WP-CLI installed and available on the server
  • The source site must expose the standard WordPress REST API (/wp-json/wp/v2/posts)

Installation

  1. Copy the plugin folder into wp-content/plugins/.
  2. Activate it (via wp-admin or wp plugin activate wp-cli-post-migration).
  3. Run the commands below with WP-CLI.

Commands

wp import-posts

Imports posts from another WordPress site into the current site.

wp import-posts

It will prompt for a REST API URL:

Importing posts...
Enter REST API Url to fetch posts:
> https://example.com/wp-json/wp/v2/posts

The URL must:

  • be a valid URL,
  • use https,
  • contain wp-json/wp/v2/posts.

The command then paginates through that endpoint (10 posts per page) and, for each post, inserts it into the local site if a post with the same title doesn't already exist.

wp delete-imported-posts

Removes posts that were previously imported.

wp delete-imported-posts

It re-fetches the same source REST API URL used during the last wp import-posts run (stored internally, see below) and, for each post found there, deletes the matching local post permanently.

How it works

1. Remembering the source site

When you run wp import-posts, the REST API URL you enter is saved with:

set_transient( 'rest_api_url_to_import_posts', $rest_api_url, 60 * 60 * 24 );

This transient (rest_api_url_to_import_posts, 24-hour lifetime) is what wp delete-imported-posts later reads to know which source site to re-check against when deleting.

2. Fetching posts page by page

handleFetchPosts( $rest_api_url, $page, $per_page ) in cli/manage-posts.php appends page and per_page query args to the URL, calls wp_remote_get(), and decodes the JSON response body. It also reads the X-WP-TotalPages response header so the caller knows when to stop paginating.

Both import_posts() and delete_imported_posts() loop over pages (10 posts per page) until page > total_pages.

3. Avoiding duplicates

gs_check_post_exists( $post_title ) runs a WP_Query for a post with a matching title (post_status => any). This is used in two places:

  • During import, to skip posts that already exist locally.
  • During delete, to find the local post ID that corresponds to a remote post's title, so it can be removed.

4. Inserting a post

gs_manage_posts( $post ) is the core import routine for a single remote post:

  1. Skips the post if a local post with the same title already exists (logs a warning).
  2. Otherwise inserts it with wp_insert_post(), copying title.renderedpost_title and content.renderedpost_content, publishing it under post_author => 1.
  3. Resolves and assigns categories: for each remote category ID, it swaps posts for categories in the saved source URL, fetches {taxonomy_url}/{id} to get the category name via fetch_taxonomy_name_from_api(), and creates/reuses a local category term with wp_insert_term() / term_exists().
  4. Does the same for tags, swapping posts for tags in the source URL and creating/reusing post_tag terms.
  5. Assigns the resolved term IDs with wp_set_post_terms().

5. Deleting imported posts

delete_imported_posts() re-fetches the same source pages, and for each remote post it finds the matching local post (via gs_check_post_exists()) and permanently deletes it with wp_delete_post( $post_id, true ) (bypassing trash).

Matching logic caveat

Posts are matched between the source and local site by title only — there's no stored mapping (e.g. postmeta) linking an imported post back to its source ID. If two unrelated posts share the same title, or a title changes between import and delete, the match can be wrong or missed.

File structure

wp-cli-post-migration.php                   Plugin bootstrap, loads cli/manage-posts.php
cli/manage-posts.php                        Manage_Posts class — both WP-CLI commands live here
readme.txt                                   WordPress.org-format readme
pluginaudit.md                               WordPress.org Plugin Directory guideline audit

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages