WP Manifestindependent plugin directory
manifest / i18n / polylang-copy-content

Polylang Copy Content WP Registry grade B. Medium-severity findings · 2 findingsWP RegistryMedium-severity findings · 2 findingsOpen the reportB #10 in Languages & Localization

Copy content, title and attachments when creating a new translation in Polylang

★ 37stars
18kcomposer installs
1.0.0latest · 7 years ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/aucor/polylang-copy-content/archive/refs/heads/master.zip

On Packagist as aucor/polylang-copy-content:

composer require aucor/polylang-copy-content
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Description

⚠️ Status: In maintenance but not in very active development. Polylang Pro has this feature built-in and actively developed so I recommend supporting the creator of Polylang. ⚠️

Polylang Copy Content is an add-on for the multilingual WordPress plugin Polylang. This add-on let's you copy the content and the title WPML style when creating a new translation. All the images and galleries are translated automatically if you use media translations.

Basic feature list:

  • Copy title, content and attachments for new translation
  • Choose the language you want to copy from (make translation from the translated version's editor)
  • Get useful translation markup for captions and title like (es translation) to be overwritten
  • Media translation works for images, captions, galleries and featured image (if you use media translations)
  • Use various filters to modify copied content in code (to be documented and expanded)
  • Translations are done with Polylang's functions, no messing around

How copying content works?

Copy content basically just copies and pastes all the content first. In this phase this plugin won't need to understand any markup so any shortcodes etc are copied.

On second phase the plugin finds markup with regex, takes out the image IDs, makes or fetches the translation of the image and replaces these inside content. So the plugin can only replace translated images on the markup that this plugin undestands which is the default WordPress markup. If you have plugins that have their own fancy markup, blocks or shortcodes, this plugin copies them but will not process them.

Why processing images matter? If you have media translations enabled, you are able to translate captions and alternative texts. These texts live mainly in attachments so while copying the content we need to also replace the attachments to avoid messing up the original images (overwriting the captions etc).

Copy Content + Classic Editor

Works just fine. Copy content takes care of:

  • Embedded images
  • Galleries
  • Featured image

Copy Content + Gutenberg

Works okay. Copy conten takes care of:

  • Image blocks
  • Gallery blocks
  • Featured image

Copy content won't process

  • Media & Text block (no captions)
  • Custom ACF blocks
  • Other blocks

If you get "invalid content" error on some block after copying content, you might need to safe draft and refresh the page and it will go away. No idea why as the markup doesn't seem to change.

Installation

Download and activate. That's it. You will need Polylang, too (d'oh).

Composer:

$ composer require aucor/polylang-copy-content

With composer.json:

{
  "require": {
    "aucor/polylang-copy-content": "*"
  },
  "extra": {
    "installer-paths": {
      "htdocs/wp-content/plugins/{$name}/": ["type:wordpress-plugin"]
    }
  }
}

Issues and feature whishlist

Issues:

  • Translating a link to a featured media page seems to make a broken link sometimes.
  • Adding translation markup (fr translation) might be someting everybody won't like. Maybe I should drop this in future or make it optional.

Feature whishlist:

  • UI to handel wheteher you want to copy things and choose the language
  • Making the plugin itself translatable
  • Ability to copy images to translation after translation has been created (if new images are added to the original version)
  • Undo copying (remove image translations)
  • :star::star: Get integrated to Polylang :star::star: Polylang Pro has similar function that was build unknowingly of this plugin.

Releases

5 releases.

Tag
Published
1.0.0 latest
Jun 30, 2019 7 years ago
Nov 28, 2018 7 years ago
Dec 15, 2017 8 years ago
Sep 30, 2016 10 years ago
Sep 30, 2016 10 years ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

B grade

Security

Polylang Copy Content 1.0.0 · audited by WP Registry

Medium-severity findings.

2 medium
Audited release
1.0.0
Findings
2
Worst severity
medium
Content hash
561e7034710a83243243cdd2…

Findings

  • medium IDOR: translation copy loads any post into the editor without read/edit capability

    missing_capability

    copy_content_and_title() runs on rest_api_init (Gutenberg, via rest_get_server() during block_editor_rest_api_preload) and add_meta_boxes (classic editor) whenever pagenow is post-new.php and $_GET['from_post'] and $_GET['new_lang'] are present. WordPress core only checks create_posts/edit_posts for the NEW post type; the plugin never calls current_user_can('read_post') or current_user_can('edit_post') on the source ID. It int-casts from_post, get_post()s it, and assigns post_content/post_title onto the global $post auto-draft. Gutenberg then copies those fields into $initial_edits for auto-drafts (after preload already fired this hook); classic editor renders the same $post in the textarea. A Contributor can therefore open /wp-admin/post-new.php?from_post={private_or_other_users_draft_id}&new_lang=fr and read unpublished/private/password-protected content, including pages or other types, then save a copy as their own pending post. The success admin notice also prints the source post_title unescaped. Subscriber/customer cannot reach post-new.php. Not unauth.

    polylang-copy-content.php:40-84

    Recommendation

    Before copying, require current_user_can('read_post', $from_post_id) (and preferably current_user_can('edit_post', $from_post_id) so only users who could edit the source can spawn a translation). Bail if get_post() or get_language() is empty. Restrict from_post to the same post type. Escape the admin notice with esc_html().

  • medium CSRF: GET post-new.php clones attachments and sets the featured image without a nonce

    csrf

    The same handler is a state-changing GET with no wp_verify_nonce. Auth cookies are SameSite=Lax, which still attach on top-level navigations, so a Contributor+ who follows a cross-site link to /wp-admin/post-new.php?from_post=ID&new_lang=SLUG causes: (1) WordPress to insert an auto-draft, (2) copy_featured_image() → set_post_thumbnail() writing _thumbnail_id immediately, (3) translate_attachment() → wp_insert_attachment() plus add_post_meta for _wp_attachment_metadata/_wp_attached_file/_wp_attachment_image_alt, PLL language, and save_translations — even when the victim lacks upload_files (default Contributor). copy_attached_media() runs WP_Query with 'parent' => $from_post_id, which is only an orderby alias in WP_Query, not a post_parent filter; with posts_per_page=-1 and Polylang lang= it can create a translated attachment row for every item in the source language on first use. Persistent effect is media-library pollution and an auto-draft with a thumbnail, not site takeover. No unauth path.

    polylang-copy-content.php:43-84,426-467,513-531

    Recommendation

    Do not insert attachments or set thumbnails on a mere GET of post-new.php. Require a Polylang-issued nonce (or POST) plus current_user_can('upload_files') before wp_insert_attachment. Change the WP_Query arg from parent to post_parent so only media attached to the source post is considered.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.