{"id":374811,"date":"2026-09-27T20:34:49","date_gmt":"2026-09-27T20:34:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/pageferry\/"},"modified":"2026-09-27T20:34:14","modified_gmt":"2026-09-27T20:34:14","slug":"pageferry","status":"publish","type":"plugin","link":"https:\/\/arq.wordpress.org\/plugins\/pageferry\/","author":23573004,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.0","stable_tag":"1.1.0","tested":"7.1.2","requires":"6.5","requires_php":"8.1","requires_plugins":null,"header_name":"PageFerry","header_author":"vadim.xyz","header_description":"Ferry a page from staging to production \u2014 media included. Export a single Gutenberg page, post, or custom post type to ZIP, import it elsewhere with correct attachment remapping.","assets_banners_color":"","last_updated":"2026-09-27 20:34:14","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/vadim.xyz\/pageferry","header_author_uri":"https:\/\/vadim.xyz","rating":0,"author_block_rating":0,"active_installs":0,"downloads":51,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.0":{"tag":"1.1.0","author":"vadimc","date":"2026-09-27 20:34:14","revision":3716041}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[1859,148076,87,4155,19979],"plugin_category":[59],"plugin_contributors":[283008],"plugin_business_model":[],"class_list":["post-374811","plugin","type-plugin","status-publish","hentry","plugin_tags-export","plugin_tags-gutenberg","plugin_tags-import","plugin_tags-migration","plugin_tags-staging","plugin_category-utilities-and-tools","plugin_contributors-vadimc","plugin_committers-vadimc"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/pageferry.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>PageFerry exports a single Gutenberg page, post, or custom post type (content + manifest + media) to a ZIP file on staging, then imports it on production with correct block-level attachment remapping, slug + taxonomy preservation (categories, tags, and custom taxonomies), domain rewrite, hash-based media dedup, and update-in-place.<\/p>\n\n<p>Scope (Gutenberg-only): export\/import via ZIP for pages, posts, and block-editor custom post types; featured + inline images; slug + categories\/tags\/custom taxonomies; basic staging\u2192prod domain rewrite; existing-media reuse; create-new or update-selected; land-as-draft option; pre-import backup of overwritten content + plain-language log.<\/p>\n\n<p>Explicit v1 non-goals: builders (detect + refuse with a clear message), ACF\/SEO meta beyond pass-through (exception: ACF blocks that store their fields in post meta via <code>usePostMeta<\/code> ferry their values with media-ID remap \u2014 see FAQ), bulk, direct push-without-ZIP, multisite.<\/p>\n\n<p>Small ZIPs import in one upload. Larger bundles (over your host's per-upload limit) import file-by-file through an in-browser worker (bundled JavaScript, no extra service): the same dedupe\/remap\/create result either way. A single asset larger than the limit cannot import \u2014 the error names the file.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload <code>pageferry<\/code> to <code>\/wp-content\/plugins\/<\/code>, activate.<\/li>\n<li>Staging: open a page \u2192 PageFerry Export \u2192 Ferry this page \u2192 download ZIP.<\/li>\n<li>Production: Tools \u2192 PageFerry Import \u2192 upload ZIP \u2192 choose create-new or update-selected \u2192 Upload and preview \u2192 Confirm import.<\/li>\n<li>Completed imports record one row each under Tools \u2192 PageFerry Import \u2192 Logs; pre-overwrite snapshots list under Backups.<\/li>\n<\/ol>\n\n<p>Requires: WordPress 6.5+, PHP 8.1+, PHP zip extension (for the export side).<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"why%20was%20my%20elementor%20page%20refused%3F\"><h3>Why was my Elementor page refused?<\/h3><\/dt>\n<dd><p>PageFerry v1 imports Gutenberg pages only. The exporter detects page-builder meta (Elementor, Divi, Beaver Builder, Bricks, WPBakery) and records it in the bundle; the importer refuses the bundle with a message naming the builder instead of silently corrupting the layout. Export your content as Gutenberg blocks (or rebuild the page in the block editor) and ferry again. Builder support is planned after v1.<\/p><\/dd>\n<dt id=\"how%20does%20media%20dedup%20work%3F\"><h3>How does media dedup work?<\/h3><\/dt>\n<dd><p>Every media file is hashed (SHA-256) at export. On import, PageFerry looks the hash up in its reuse index and verifies the match by re-hashing the existing attachment \u2014 a stale index row never reuses a deleted file. Identical bytes reuse the existing attachment; same filename with different bytes uploads separately. The confirmation screen reports reused-vs-new counts, and the Logs tab records them per import.<\/p><\/dd>\n<dt id=\"update%20vs%20create%20%E2%80%94%20which%20is%20used%3F\"><h3>Update vs create \u2014 which is used?<\/h3><\/dt>\n<dd><p>You choose on the import screen. Create-new (default) inserts the content as a draft with a unique slug (a clash gets a <code>-2<\/code> suffix plus a notice). Update-selected overwrites the target's content, excerpt, terms, and featured image after snapshotting the prior content + meta into Backups and writing a log row. Terms (categories, tags, and custom taxonomies) match by name: existing terms are reused as-is (their current parents are kept, never restructured); only new terms are created with their exported hierarchy. The imported post type must be registered on the production site (activate the plugin or theme that provides the custom post type first). There is no one-click rollback in v1 \u2014 restore from the Backups tab by pasting the stored content back.<\/p><\/dd>\n<dt id=\"where%20is%20my%20pre-import%20backup%3F\"><h3>Where is my pre-import backup?<\/h3><\/dt>\n<dd><p>Tools \u2192 PageFerry Import \u2192 Backups. Each update-selected import stores the target's prior content and meta under a <code>pf-*<\/code> key before writing anything (kept: last 20). The Logs tab links each update row to its backup key.<\/p><\/dd>\n<dt id=\"the%20import%20says%20a%20file%20is%20too%20large.%20what%20now%3F\"><h3>The import says a file is too large. What now?<\/h3><\/dt>\n<dd><p>Your host caps each upload (<code>upload_max_filesize<\/code>). Bundles over that cap import file-by-file automatically \u2014 but one single asset over the cap cannot. Raise the PHP upload limit, or drop that asset from the page and re-export. The error names the file.<\/p><\/dd>\n<dt id=\"does%20pageferry%20ferry%20acf%20block%20data%3F\"><h3>Does PageFerry ferry ACF block data?<\/h3><\/dt>\n<dd><p>Blocks that keep their field data in the block comment (the ACF default) ferry like any other blocks: media IDs remap, everything else passes through. Blocks that store their fields in post meta (<code>usePostMeta<\/code>, ACF PRO 6.3+) ferry their field values too: image\/file\/gallery IDs remap to the new attachments, upload URLs rewrite, all other values restore verbatim through the ACF API. Two limits apply: reference fields (post\/relationship\/taxonomy\/user\/page-link IDs) point at source-site content and ferry verbatim \u2014 the export warns when they hold values \u2014 and on update-selected imports, fields unset on the source keep the target's existing values.<\/p><\/dd>\n<dt id=\"does%20pageferry%20phone%20home%20or%20load%20remote%20code%3F\"><h3>Does PageFerry phone home or load remote code?<\/h3><\/dt>\n<dd><p>No. v1 makes no outbound requests, loads no CDN scripts, and runs with no account or license key. All JavaScript (including the large-bundle worker dependency fflate 0.8.3, MIT, source at https:\/\/github.com\/101arrowz\/fflate) ships inside the plugin. Import\/export handlers require the <code>import<\/code> \/ <code>edit_post<\/code> capabilities plus nonces.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Custom post types (block-editor) and custom taxonomies: the export metabox appears on every Gutenberg-edited post type, bundles carry all attached taxonomies, and the importer recreates the post type + term hierarchy on production (the post type must be registered there first).<\/li>\n<li>ACF <code>usePostMeta<\/code> blocks: field values stored in post meta now ferry in the bundle (<code>acf_post_meta<\/code>) and restore on import with media-ID remap and URL rewrite, written back through the ACF API. Skipped values are reported in the import log row (<code>acf_skipped<\/code>); reference-type IDs ferry verbatim (export warns).<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release: ferry a Gutenberg page or post with its media as a single ZIP bundle \u2014 export with manifest, import with block-level attachment remap, URL + domain rewrite, SHA-256 media dedup, slug + category\/tag preservation, create-new or update-selected, land-as-draft, pre-import backup plus plain-language log. Builder-marked bundles refuse with a clear message.<\/li>\n<\/ul>","raw_excerpt":"Ferry a page from staging to production \u2014 media included.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/374811","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=374811"}],"author":[{"embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/vadimc"}],"wp:attachment":[{"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=374811"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=374811"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=374811"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=374811"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=374811"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/arq.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=374811"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}