Content Duplicator
WordPress plugin that adds a Duplicate row action to the list tables of selected post types. Clicking it creates a copy of the post, including taxonomy terms and post meta.
by jswebforge · github.com/jswebschmiede/content-duplicator · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/jswebschmiede/content-duplicator/archive/refs/heads/main.zipWordPress plugin that adds a Duplicate row action to the list tables of selected post types. Clicking it creates a copy of the post, including taxonomy terms and post meta.
Requirements
- PHP 8.3+
- Composer, for the autoloader (
composer installin this directory) - Node.js 20.18+ only when running the local Playground site
Structure
content-duplicator.php Plugin bootstrap
src/Common/ Hook registration
src/Controllers/ Settings screen, row action, duplicate request
src/Models/ Settings storage and post copying
views/ Settings markup
Namespaces use Jswebforge\ContentDuplicator\ and Composer PSR-4 from src/.
Options
Configured under Settings → Content Duplicator:
| Field | Type | Description |
|---|---|---|
content_duplicator_post_types |
checkbox | Post types that show the row action (default post, page; none checked disables duplication) |
content_duplicator_roles |
checkbox | User roles that may duplicate; choices come from the registered roles (default administrator, editor; none checked disables duplication) |
content_duplicator_post_status |
select | Status of the duplicate: draft, pending, private, publish (default draft) |
content_duplicator_redirect |
select | Redirect after duplicating: list or edit screen of the duplicate (default list) |
content_duplicator_title_suffix |
text | Optional suffix appended to the title (– <suffix>) |
Attachments and internal post types (wp_*, acf-*) are not offered.
Behaviour
- The link is shown when the user has one of the enabled roles, can edit the source post and can create posts of that type. On multisite, network super admins always pass the role check.
- Posts in the trash cannot be duplicated.
- Without the post type's
publish_postscapability, a configuredpublishorprivatestatus falls back topending. - The current user becomes the author of the duplicate.
- Meta keys
_edit_lock,_edit_last,_wp_old_slug,_wp_old_date,_wp_trash_meta_status,_wp_trash_meta_time,_wp_trash_meta_comments_status,_wp_desired_post_slug,_enclosemeand_pingmeare not copied. Meta values whose serialized form contains an object or enum are skipped; the check runs before unserializing. - After redirecting to the list, a notice links to the edit screen of the duplicate.
- Uninstalling removes the options; on multisite from every site.
Hooks
content_duplicator_excluded_meta_keys(filter): list of meta keys that are not copied. Receives the list and the source post ID.content_duplicator_after_duplicate(action): fires after the duplicate and its terms and meta were created. Receives the duplicate post ID and the sourceWP_Post.
Development
composer install
composer php:lint
composer php:rector
composer i18n
composer playground
composer production
composer i18n refreshes the POT/PO files and compiles .mo / .l10n.php. Those compiled files are gitignored and rebuilt for local use or the release zip.
composer production compiles translations, installs production dependencies, writes dist/content-duplicator-<version>.zip, then restores the development vendor/ tree.
composer playground starts WordPress Playground CLI with PHP 8.3. The CLI mounts this plugin and opens the settings screen. The site is stored under ~/.wordpress-playground/sites/. Pass --reset on the CLI when you need a fresh site (npx @wp-playground/cli@latest start --php=8.3 --blueprint=blueprint.json --reset).