403Webshell
Server IP : 46.105.57.169  /  Your IP : 216.73.217.35
Web Server : Apache
System : Linux webm002.cluster120.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User : verseaumee ( 152031)
PHP Version : 8.5.7
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/verseaumee/123click/assets/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/verseaumee/123click/assets/duplicate-post.zip
PK!�*��
readme.txtnu�[���=== Yoast Duplicate Post ===
Contributors: 		yoast, lopo
Donate link: 		https://yoast.com/wordpress/plugins/duplicate-post/
Tags: 				duplicate post, copy, clone
Requires at least: 	6.4
Tested up to: 		6.6
Stable tag: 		4.5
Requires PHP:		5.6.20
License: 			GPLv2 or later
License URI: 		http://www.gnu.org/licenses/gpl-2.0.html

The go-to tool for cloning posts and pages, including the powerful Rewrite & Republish feature.

== Description ==

This plugin allows users to clone posts of any type, or copy them to new drafts for further editing.

How it works:

1. In 'Edit Posts'/'Edit Pages', you can click on 'Clone' link below the post/page title: this will immediately create a copy and return to the list.

2. In 'Edit Posts'/'Edit Pages', you can select one or more items, then choose 'Clone' in the 'Bulk Actions' dropdown to copy them all at once.

3. In 'Edit Posts'/'Edit Pages', you can click on 'New Draft' link below the post/page title.

4. On the post edit screen, you can click on 'Copy to a new draft' above "Cancel"/"Move to trash" or in the admin bar.

5. While viewing a post as a logged in user, you can click on 'Copy to a new draft' in the admin bar.

3, 4 and 5 will lead to the edit page for the new draft: change what you want, click on 'Publish' and you're done.

There is also a **template tag**, so you can put it in your templates and clone your posts/pages from the front-end. Clicking on the link will lead you to the edit page for the new draft, just like the admin bar link.

Duplicate Post has many useful settings to customize its behavior and restrict its use to certain roles or post types. Check out the extensive documentation on [yoast.com](https://yoast.com/wordpress/plugins/duplicate-post/) and our [developer docs](https://developer.yoast.com/duplicate-post/overview/).

== Installation ==

Use WordPress' Add New Plugin feature, searching "Duplicate Post", or download the archive and:

1. Unzip the archive on your computer
2. Upload `duplicate-post` directory to the `/wp-content/plugins/` directory
3. Activate the plugin through the 'Plugins' menu in WordPress
4. Go to Settings -> Duplicate Post and customize behaviour as needed

== Frequently Asked Questions ==

= The plugin doesn't work, why? =

First, check your version of WordPress: the plugin is not supposed to work on old versions anymore. Make sure also to upgrade to the last version of the plugin!

Then try to deactivate and re-activate it, some user have reported that this fixes some problems.

Pay also attention to the "Permissions" tab in the Settings: make sure the plugin is enabled for the desired roles and post types.

If it still doesn't work, maybe there is some kind of conflict with other plugins: feel free [to write in the forum](https://wordpress.org/support/plugin/duplicate-post) and we'll try to discover a solution (it will be *really* helpful if you try to deactivate all your other plugins one by one to see which one conflicts with mine... But do it only if you know what you're doing, I will not be responsible of any problem you may experience).

= The plugin is not translated in my language! =

From version 3.0 the plugin's translations are managed by the WordPress.org platform and the plugin is shipped without language files, so first of all update translations under Dashboard->Updates.

If Duplicate Post is still in English, or if there are some untranslated strings, you can [help translating to your language](https://translate.wordpress.org/projects/wp-plugins/duplicate-post): you only need a WordPress.org account.

== Screenshots ==

1. Classic editor.
2. Block editor.
3. Post list.
4. Admin bar menu.
5. Bulk actions.
6. The options page.

== Changelog ==

= 4.5 =
Release Date: June 28th, 2022

Enhancements:

* Improves the impact of the plugin on the performance of the site by avoiding useless calls on the `gettext` filter.

Bugfixes:

* Fixes a bug where a section in the Classic Editor's submitbox would be displayed with incorrect margins.

Other:

* Sets the WordPress tested up to version to 6.0.

= 4.4 =
Release Date: January 25th, 2022

Enhancements:

* Converts the upgrade notice into a welcome notice for first-time users.

Bugfixes:

* Fixes a bug where HTML tags in a Custom HTML block would be removed when republishing a scheduled Rewrite & Republish copy.
* Fixes a bug where the button style would be broken in the Classic Editor.
* Fixes a bug where a fatal error would be triggered in the Widgets page in combination with some themes or plugins.

Other:

* Sets the WordPress tested up to version to 5.9.

= Earlier versions =
For the changelog of earlier versions, please refer to [the changelog on yoast.com](https://yoa.st/duplicate-post-changelog).

== Contribute ==

If you find this useful and if you want to contribute, there are two ways:

   1. Submit your bug reports, suggestions and requests for features on [GitHub](https://github.com/Yoast/duplicate-post);
   2. If you want to translate it to your language (there are just a few lines of text), you can use the [translation project](https://translate.wordpress.org/projects/wp-plugins/duplicate-post);
PK!E�\k

options.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

use Yoast\WP\Duplicate_Post\Admin\Options;
use Yoast\WP\Duplicate_Post\Admin\Options_Form_Generator;
use Yoast\WP\Duplicate_Post\Admin\Options_Inputs;
use Yoast\WP\Duplicate_Post\Admin\Options_Page;
use Yoast\WP\Duplicate_Post\UI\Asset_Manager;

if ( ! \defined( 'ABSPATH' ) ) {
	exit();
}

$duplicate_post_options_page = new Options_Page(
	new Options(),
	new Options_Form_Generator( new Options_Inputs() ),
	new Asset_Manager()
);

$duplicate_post_options_page->register_hooks();
PK!iL��common-functions.phpnu�[���<?php
/**
 * Common functions.
 *
 * @package Yoast\WP\Duplicate_Post
 * @since   2.0
 */

use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\UI\Link_Builder;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Tests if post type is enabled to be copied.
 *
 * @param string $post_type The post type to check.
 * @return bool
 */
function duplicate_post_is_post_type_enabled( $post_type ) {
	$duplicate_post_types_enabled = get_option( 'duplicate_post_types_enabled', [ 'post', 'page' ] );
	if ( ! is_array( $duplicate_post_types_enabled ) ) {
		$duplicate_post_types_enabled = [ $duplicate_post_types_enabled ];
	}

	/** This filter is documented in src/permissions-helper.php */
	$duplicate_post_types_enabled = apply_filters( 'duplicate_post_enabled_post_types', $duplicate_post_types_enabled );
	return in_array( $post_type, $duplicate_post_types_enabled, true );
}

/**
 * Template tag to retrieve/display duplicate post link for post.
 *
 * @param int    $id      Optional. Post ID.
 * @param string $context Optional, default to display. How to write the '&', defaults to '&amp;'.
 * @param bool   $draft   Optional, default to true.
 * @return string
 */
function duplicate_post_get_clone_post_link( $id = 0, $context = 'display', $draft = true ) {
	$post = get_post( $id );
	if ( ! $post ) {
		return '';
	}

	$link_builder       = new Link_Builder();
	$permissions_helper = new Permissions_Helper();

	if ( ! $permissions_helper->should_links_be_displayed( $post ) ) {
		return '';
	}

	if ( $draft ) {
		return $link_builder->build_new_draft_link( $post, $context );
	}
	else {
		return $link_builder->build_clone_link( $post, $context );
	}
}

/**
 * Displays duplicate post link for post.
 *
 * @param string|null $link   Optional. Anchor text.
 * @param string      $before Optional. Display before edit link.
 * @param string      $after  Optional. Display after edit link.
 * @param int         $id     Optional. Post ID.
 */
function duplicate_post_clone_post_link( $link = null, $before = '', $after = '', $id = 0 ) {
	$post = get_post( $id );
	if ( ! $post ) {
		return;
	}

	$url = duplicate_post_get_clone_post_link( $post->ID );
	if ( ! $url ) {
		return;
	}

	if ( $link === null ) {
		$link = __( 'Copy to a new draft', 'duplicate-post' );
	}

	$link = '<a class="post-clone-link" href="' . esc_url( $url ) . '">' . esc_html( $link ) . '</a>';

	/**
	 * Filter on the clone link HTML.
	 *
	 * @param string $link The full HTML tag of the link.
	 * @param int    $ID   The ID of the post.
	 *
	 * @return string
	 */
	echo $before . apply_filters( 'duplicate_post_clone_post_link', $link, $post->ID ) . $after; // phpcs:ignore WordPress.Security.EscapeOutput
}

/**
 * Gets the original post.
 *
 * @param int|null $post   Optional. Post ID or Post object.
 * @param string   $output Optional, default is Object. Either OBJECT, ARRAY_A, or ARRAY_N.
 * @return mixed Post data.
 */
function duplicate_post_get_original( $post = null, $output = OBJECT ) {
	return Utils::get_original( $post, $output );
}
PK!f��(js/dist/duplicate-post-quick-edit-450.jsnu�[���!function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=9)}({9:function(t,e,n){"use strict";var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};!function(t){var e=inlineEditPost.edit;inlineEditPost.edit=function(n){e.apply(this,arguments);var o=0;if("object"==(void 0===n?"undefined":i(n))&&(o=parseInt(this.getId(n))),o>0){var r=t("#edit-"+o),u=t("#post-"+o),l=1!==t(".duplicate_post_original_item span",u).data("noOriginal"),a=t(".duplicate_post_original_item span",u).html(),p=1===t(".duplicate_post_original_item span",u).data("copyIsForRewriteAndRepublish");l&&!p?(t(".duplicate_post_original_item_title_span",r).html(a),t("#duplicate_post_quick_edit_fieldset",r).show()):(t("#duplicate_post_quick_edit_fieldset",r).hide(),t(".duplicate_post_original_item_title_span",r).html(""))}}}(jQuery)}});PK!LG�."js/dist/duplicate-post-edit-450.jsnu�[���!function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(i,n,function(t){return e[t]}.bind(null,n));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=5)}([function(e,t){e.exports=window.wp.data},function(e,t){e.exports=window.wp.element},function(e,t){e.exports=window.wp.components},function(e,t){e.exports=window.wp.i18n},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.redirectOnSaveCompletion=void 0;var i=r(0),n=function(e){var t=(0,i.select)("core/editor").getCurrentPostAttribute("status"),r=(0,i.select)("core/editor").getEditedPostAttribute("status");"dp-rewrite-republish"===t&&"publish"===r&&(0,i.dispatch)("core/editor").editPost({status:t}),window.location.assign(e)};t.redirectOnSaveCompletion=function(e,t){var r=(0,i.select)("core/editor").isSavingPost(),o=(0,i.select)("core/editor").isAutosavingPost(),s=(0,i.select)("core/edit-post").hasMetaBoxes(),a=(0,i.select)("core/edit-post").isSavingMetaBoxes();return s&&!a&&t.wasSavingMetaboxes&&n(e),s||r||!t.wasSavingPost||t.wasAutoSavingPost||n(e),{isSavingPost:r,isSavingMetaBoxes:a,isAutosavingPost:o}}},function(e,t,r){"use strict";var i=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var r=[],i=!0,n=!1,o=void 0;try{for(var s,a=e[Symbol.iterator]();!(i=(s=a.next()).done)&&(r.push(s.value),!t||r.length!==t);i=!0);}catch(e){n=!0,o=e}finally{try{!i&&a.return&&a.return()}finally{if(n)throw o}}return r}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},n=function(){function e(e,t){for(var r=0;r<t.length;r++){var i=t[r];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,r,i){return r&&e(t.prototype,r),i&&e(t,i),t}}(),o=r(6),s=r(7),a=r(1),u=r(2),l=r(3),c=r(0),d=r(4);var p=new(function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.renderNotices(),this.removeSlugSidebarPanel()}return n(e,[{key:"handleRedirect",value:function(){var e=this;if(parseInt(duplicatePost.rewriting,10)){var t=!1,r=!1,i=!1;(0,c.subscribe)((function(){if(e.isSafeRedirectURL(duplicatePost.originalEditURL)&&e.isCopyAllowedToBeRepublished()){var n=(0,d.redirectOnSaveCompletion)(duplicatePost.originalEditURL,{wasSavingPost:t,wasSavingMetaboxes:r,wasAutoSavingPost:i});t=n.isSavingPost,r=n.isSavingMetaBoxes,i=n.isAutosavingPost}}))}}},{key:"isSafeRedirectURL",value:function(e){var t=document.createElement("a");return t.href=e,!!(/^https?:$/.test(t.protocol)&&/\/wp-admin\/post\.php$/.test(t.pathname)&&/\?action=edit&post=[0-9]+&dprepublished=1&dpcopy=[0-9]+&dpnonce=[a-z0-9]+/i.test(t.search))}},{key:"isCopyAllowedToBeRepublished",value:function(){var e=(0,c.select)("core/editor").getCurrentPostAttribute("status");return"dp-rewrite-republish"===e||"private"===e}},{key:"renderNotices",value:function(){if(duplicatePostNotices&&duplicatePostNotices instanceof Object){var e=!0,t=!1,r=void 0;try{for(var n,o=Object.entries(duplicatePostNotices)[Symbol.iterator]();!(e=(n=o.next()).done);e=!0){var s=n.value,a=i(s,2),u=(a[0],a[1]),l=JSON.parse(u);l.status&&l.text&&(0,c.dispatch)("core/notices").createNotice(l.status,l.text,{isDismissible:l.isDismissible||!0})}}catch(e){t=!0,r=e}finally{try{!e&&o.return&&o.return()}finally{if(t)throw r}}}}},{key:"removeSlugSidebarPanel",value:function(){parseInt(duplicatePost.rewriting,10)&&(0,c.dispatch)("core/edit-post").removeEditorPanel("post-link")}},{key:"render",value:function(){if(!(0,c.select)("core/editor")||!wp.editPost||!wp.editPost.PluginPostStatusInfo)return null;var e=(0,c.select)("core/editor").getEditedPostAttribute("status");return"1"===duplicatePost.showLinksIn.submitbox&&wp.element.createElement(a.Fragment,null,""!==duplicatePost.newDraftLink&&"1"===duplicatePost.showLinks.new_draft&&wp.element.createElement(s.PluginPostStatusInfo,null,wp.element.createElement(u.Button,{isTertiary:!0,className:"dp-editor-post-copy-to-draft",href:duplicatePost.newDraftLink},(0,l.__)("Copy to a new draft","duplicate-post"))),"publish"===e&&""!==duplicatePost.rewriteAndRepublishLink&&"1"===duplicatePost.showLinks.rewrite_republish&&wp.element.createElement(s.PluginPostStatusInfo,null,wp.element.createElement(u.Button,{isTertiary:!0,className:"dp-editor-post-rewrite-republish",href:duplicatePost.rewriteAndRepublishLink},(0,l.__)("Rewrite & Republish","duplicate-post"))))}}]),e}());p.handleRedirect(),(0,o.registerPlugin)("duplicate-post",{render:p.render})},function(e,t){e.exports=window.wp.plugins},function(e,t){e.exports=window.wp.editPost}]);PK!kb<+�
�
%js/dist/duplicate-post-options-450.jsnu�[���!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=10)}({10:function(e,t,n){"use strict";var r=void 0,o=void 0,i=35,u=36,a=37,c=38,d=39,l=40,s={37:-1,38:-1,39:1,40:1};function f(e){r[e].addEventListener("click",(function(e){v(e.target,!1)})),r[e].addEventListener("keydown",(function(e){switch(e.keyCode){case i:e.preventDefault(),v(r[r.length-1]);break;case u:e.preventDefault(),v(r[0])}})),r[e].addEventListener("keyup",(function(e){switch(e.keyCode){case a:case d:!function(e){for(var t=e.keyCode,n=0;n<r.length;n++)r[n].addEventListener("focus",p);if(s[t]){var o=e.target;void 0!==o.index&&(r[o.index+s[t]]?r[o.index+s[t]].focus():t===a||t===c?r[r.length-1].focus():t!==d&&t!==l||r[0].focus())}}(e)}})),r[e].index=e}function v(e,t){t=t||!0,function(){for(var e=0;e<r.length;e++)r[e].setAttribute("tabindex","-1"),r[e].setAttribute("aria-selected","false"),r[e].classList.remove("nav-tab-active"),r[e].removeEventListener("focus",p);for(var t=0;t<o.length;t++)o[t].setAttribute("hidden","hidden")}(),e.removeAttribute("tabindex"),e.setAttribute("aria-selected","true"),e.classList.add("nav-tab-active");var n=e.getAttribute("aria-controls");document.getElementById(n).removeAttribute("hidden"),t&&e.focus()}function p(e){!function(e){var t=document.activeElement;e===t&&v(e,!1)}(e.target)}document.addEventListener("DOMContentLoaded",(function(){document.querySelectorAll('#duplicate_post_settings_form [role="tablist"]')[0],r=document.querySelectorAll('#duplicate_post_settings_form [role="tab"]'),o=document.querySelectorAll('#duplicate_post_settings_form [role="tabpanel"]');for(var e=0;e<r.length;++e)f(e)})),jQuery((function(){jQuery(".taxonomy_private").hide(),jQuery(".toggle-private-taxonomies").on("click",(function(){var e=jQuery(this);jQuery(".taxonomy_private").toggle(300,(function(){e.attr("aria-expanded",jQuery(this).is(":visible"))}))}))}))}});PK!<M��

'js/dist/duplicate-post-elementor-450.jsnu�[���!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=11)}({11:function(e,t,n){"use strict";var r=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}();function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function u(){var e=function(e){function t(){return o(this,t),i(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,$e.modules.hookUI.After),r(t,[{key:"getCommand",value:function(){return"document/save/save"}},{key:"getConditions",value:function(e){return"publish"===e.status}},{key:"getId",value:function(){return"redirect-after-republish"}},{key:"apply",value:function(e){"publish"===e.status&&duplicatePost.originalEditURL&&"1"===duplicatePost.rewriting&&window.location.assign(duplicatePost.originalEditURL)}}]),t}();$e.hooks.registerUIAfter(new e)}jQuery(window).on("elementor:init",(function(){window.elementor.on("panel:init",(function(){u(),"0"!==duplicatePost.rewriting&&elementor.getPanelView().footer.currentView.removeSubMenuItem("saver-options",{name:"save-template"})}))}))}});PK!����%js/dist/duplicate-post-strings-450.jsnu�[���!function(e){var t={};function o(i){if(t[i])return t[i].exports;var r=t[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.m=e,o.c=t,o.d=function(e,t,i){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(i,r,function(t){return e[t]}.bind(null,r));return i},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=8)}([function(e,t){e.exports=window.wp.data},function(e,t){e.exports=window.wp.element},function(e,t){e.exports=window.wp.components},function(e,t){e.exports=window.wp.i18n},function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.redirectOnSaveCompletion=void 0;var i=o(0),r=function(e){var t=(0,i.select)("core/editor").getCurrentPostAttribute("status"),o=(0,i.select)("core/editor").getEditedPostAttribute("status");"dp-rewrite-republish"===t&&"publish"===o&&(0,i.dispatch)("core/editor").editPost({status:t}),window.location.assign(e)};t.redirectOnSaveCompletion=function(e,t){var o=(0,i.select)("core/editor").isSavingPost(),n=(0,i.select)("core/editor").isAutosavingPost(),s=(0,i.select)("core/edit-post").hasMetaBoxes(),a=(0,i.select)("core/edit-post").isSavingMetaBoxes();return s&&!a&&t.wasSavingMetaboxes&&r(e),s||o||!t.wasSavingPost||t.wasAutoSavingPost||r(e),{isSavingPost:o,isSavingMetaBoxes:a,isAutosavingPost:n}}},,,,function(e,t,o){"use strict";var i=o(1),r=o(2),n=o(3),s=o(0),a=o(4);var u,l,c,p=function(){(0,s.dispatch)("core/editor").savePost();var e=!1,t=!1,o=!1;(0,s.subscribe)((function(){var i=(0,a.redirectOnSaveCompletion)(duplicatePostStrings.checkLink,{wasSavingPost:e,wasSavingMetaboxes:t,wasAutoSavingPost:o});e=i.isSavingPost,t=i.isSavingMetaBoxes,o=i.isAutosavingPost}))},d={Publish:(0,n.__)("Republish","duplicate-post"),"Publish:":(0,n.__)("Republish:","duplicate-post"),"Publish on:":(0,n.__)("Republish on:","duplicate-post"),"Are you ready to publish?":(0,n.__)("Are you ready to republish your post?","duplicate-post"),"Double-check your settings before publishing.":(0,i.createInterpolateElement)((0,n.__)("After republishing your changes will be merged into the original post and you'll be redirected there.<br /><br />Do you want to compare your changes with the original version before merging?<br /><br /><button>Save changes and compare</button>","duplicate-post"),{button:wp.element.createElement(r.Button,{isSecondary:!0,onClick:p}),br:wp.element.createElement("br",null)}),Schedule:(0,n.__)("Schedule republish","duplicate-post"),"Schedule…":(0,n.__)("Schedule republish…","duplicate-post"),"post action/button labelSchedule":(0,n.__)("Schedule republish","duplicate-post"),"Are you ready to schedule?":(0,n.__)("Are you ready to schedule the republishing of your post?","duplicate-post"),"Your work will be published at the specified date and time.":(0,i.createInterpolateElement)((0,n.__)("You're about to replace the original with this rewritten post at the specified date and time.<br /><br />Do you want to compare your changes with the original version before merging?<br /><br /><button>Save changes and compare</button>","duplicate-post"),{button:wp.element.createElement(r.Button,{isSecondary:!0,onClick:p}),br:wp.element.createElement("br",null)}),"is now scheduled. It will go live on":(0,n.__)(", the rewritten post, is now scheduled to replace the original post. It will be published on","duplicate-post")};for(var b in d)(0,n.setLocaleData)((c=[d[b],"duplicate-post"],(l=b)in(u={})?Object.defineProperty(u,l,{value:c,enumerable:!0,configurable:!0,writable:!0}):u[l]=c,u))}]);PK!�=�[css/duplicate-post.cssnu�[���#wp-admin-bar-root-default>#wp-admin-bar-duplicate-post>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-new-draft>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-rewrite-republish>.ab-item .ab-icon::before{
	content:
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'><path d='M18.9 4.3c0.6 0 1.1 0.5 1.1 1.1v13.6c0 0.6-0.5 1.1-1.1 1.1h-10.7c-0.6 0-1.1-0.5-1.1-1.1v-3.2h-6.1c-0.6 0-1.1-0.5-1.1-1.1v-7.5c0-0.6 0.3-1.4 0.8-1.8l4.6-4.6c0.4-0.4 1.2-0.8 1.8-0.8h4.6c0.6 0 1.1 0.5 1.1 1.1v3.7c0.4-0.3 1-0.4 1.4-0.4h4.6zM12.9 6.7l-3.3 3.3h3.3v-3.3zM5.7 2.4l-3.3 3.3h3.3v-3.3zM7.9 9.6l3.5-3.5v-4.6h-4.3v4.6c0 0.6-0.5 1.1-1.1 1.1h-4.6v7.1h5.7v-2.9c0-0.6 0.3-1.4 0.8-1.8zM18.6 18.6v-12.9h-4.3v4.6c0 0.6-0.5 1.1-1.1 1.1h-4.6v7.1h10z' fill='rgba(240,245,250,.6)'/></svg>");
	top: 2px;
}

#wp-admin-bar-root-default>#wp-admin-bar-duplicate-post:hover>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-new-draft:hover>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-rewrite-republish:hover>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-duplicate-post:focus>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-new-draft:focus>.ab-item .ab-icon::before,
#wp-admin-bar-root-default>#wp-admin-bar-rewrite-republish:focus>.ab-item .ab-icon::before{
	content:
		url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'><path d='M18.9 4.3c0.6 0 1.1 0.5 1.1 1.1v13.6c0 0.6-0.5 1.1-1.1 1.1h-10.7c-0.6 0-1.1-0.5-1.1-1.1v-3.2h-6.1c-0.6 0-1.1-0.5-1.1-1.1v-7.5c0-0.6 0.3-1.4 0.8-1.8l4.6-4.6c0.4-0.4 1.2-0.8 1.8-0.8h4.6c0.6 0 1.1 0.5 1.1 1.1v3.7c0.4-0.3 1-0.4 1.4-0.4h4.6zM12.9 6.7l-3.3 3.3h3.3v-3.3zM5.7 2.4l-3.3 3.3h3.3v-3.3zM7.9 9.6l3.5-3.5v-4.6h-4.3v4.6c0 0.6-0.5 1.1-1.1 1.1h-4.6v7.1h5.7v-2.9c0-0.6 0.3-1.4 0.8-1.8zM18.6 18.6v-12.9h-4.3v4.6c0 0.6-0.5 1.1-1.1 1.1h-4.6v7.1h10z' fill='rgba(0, 185, 235, 1)'/></svg>");
}

/* Copy links in the classic editor. */
#duplicate-action {
	margin-bottom: 12px;
}

#rewrite-republish-action {
	margin-bottom: -2px;
}

#rewrite-republish-action + #delete-action {
	margin-top: 8px;
}

/* Copy links in the block editor. */
.components-button.dp-editor-post-copy-to-draft,
.components-button.dp-editor-post-rewrite-republish {
	margin-left: -6px;
	text-decoration: underline;
}

#check-changes-action  {
	padding: 6px 10px 8px;
}

@media screen and (max-width: 782px){
	#wp-admin-bar-root-default>#wp-admin-bar-duplicate-post,
	#wp-admin-bar-root-default>#wp-admin-bar-new-draft,
	#wp-admin-bar-root-default>#wp-admin-bar-rewrite-republish {
		display: block;
		position: static;
	}
	#wp-admin-bar-root-default>#wp-admin-bar-duplicate-post>.ab-item,
	#wp-admin-bar-root-default>#wp-admin-bar-new-draft>.ab-item,
	#wp-admin-bar-root-default>#wp-admin-bar-rewrite-republish>.ab-item {
		text-indent: 100%;
		white-space: nowrap;
		overflow: hidden;
		width: 52px;
		padding: 0;
		color: #999;
		position: static;
	}
	#wp-admin-bar-root-default>#wp-admin-bar-duplicate-post>.ab-item .ab-icon::before,
	#wp-admin-bar-root-default>#wp-admin-bar-new-draft>.ab-item .ab-icon::before,
	#wp-admin-bar-root-default>#wp-admin-bar-rewrite-republish>.ab-item .ab-icon::before {
		display: block;
		text-indent: 0;
		font: 400 32px/1 dashicons;
		speak: none;
		top: 0px;
		width: 52px;
		text-align: center;
		-webkit-font-smoothing: antialiased;
		-moz-osx-font-smoothing: grayscale;
	}
	#rewrite-republish-action + #delete-action {
		margin-top: 0;
	}
}

fieldset#duplicate_post_quick_edit_fieldset{
	clear: both;
}

fieldset#duplicate_post_quick_edit_fieldset label{
	display: inline;
	margin: 0;
	vertical-align: unset;
}

fieldset#duplicate_post_quick_edit_fieldset a{
	text-decoration: underline;
}
PK!�v�6@@css/duplicate-post-options.cssnu�[���#duplicate_post_settings_form header.nav-tab-wrapper {
	margin: 22px 0 0 0;
}

#duplicate_post_settings_form header .nav-tab{
	cursor: pointer;
}

#duplicate_post_settings_form header .nav-tab:focus {
	color: #555;
	box-shadow: none;
	outline: 1px dotted #000000;
}

.no-js #duplicate_post_settings_form header.nav-tab-wrapper {
	display: none;
}

.no-js #duplicate_post_settings_form section {
	border-top: 1px dashed #aaa;
	margin-top: 22px;
	padding-top: 22px;
}

.no-js #duplicate_post_settings_form section:first-of-type {
	margin: 0;
	padding: 0;
	border: 0;
}

.no-js #duplicate_post_settings_form section[hidden] {
	display: block;
}

#duplicate_post_settings_form label.taxonomy_private {
	font-style: italic;
}

#duplicate_post_settings_form .toggle-private-taxonomies.button-link {
	font-size: small;
	margin-top: 1em;
}
PK!�FFsrc/duplicate-post.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

use Yoast\WP\Duplicate_Post\Handlers\Handler;
use Yoast\WP\Duplicate_Post\UI\User_Interface;
use Yoast\WP\Duplicate_Post\Watchers\Watchers;

/**
 * Duplicate Post main class.
 *
 * @since 4.0
 */
class Duplicate_Post {

	/**
	 * Permissions_Helper object.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * User_Interface object.
	 *
	 * @var User_Interface
	 */
	protected $user_interface;

	/**
	 * Post_Duplicator object.
	 *
	 * @var Post_Duplicator
	 */
	protected $post_duplicator;

	/**
	 * Handler object.
	 *
	 * @var Handler
	 */
	protected $handler;

	/**
	 * Post_Republisher object.
	 *
	 * @var Post_Republisher
	 */
	protected $post_republisher;

	/**
	 * Revisions_Migrator object.
	 *
	 * @var Revisions_Migrator
	 */
	protected $revisions_migrator;

	/**
	 * Watchers object.
	 *
	 * @var Watchers
	 */
	protected $watchers;

	/**
	 * Initializes the main class.
	 */
	public function __construct() {
		$this->permissions_helper = new Permissions_Helper();
		$this->user_interface     = new User_Interface( $this->permissions_helper );
		$this->post_duplicator    = new Post_Duplicator();
		$this->handler            = new Handler( $this->post_duplicator, $this->permissions_helper );
		$this->post_republisher   = new Post_Republisher( $this->post_duplicator, $this->permissions_helper );
		$this->revisions_migrator = new Revisions_Migrator();
		$this->watchers           = new Watchers( $this->permissions_helper );

		$this->post_republisher->register_hooks();
		$this->revisions_migrator->register_hooks();
	}
}
PK!��F22src/post-republisher.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

use WP_Post;

/**
 * Duplicate Post class to republish a rewritten post.
 *
 * @since 4.0
 */
class Post_Republisher {

	/**
	 * Post_Duplicator object.
	 *
	 * @var Post_Duplicator
	 */
	protected $post_duplicator;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Post_Duplicator    $post_duplicator    The Post_Duplicator object.
	 * @param Permissions_Helper $permissions_helper The Permissions Helper object.
	 */
	public function __construct( Post_Duplicator $post_duplicator, Permissions_Helper $permissions_helper ) {
		$this->post_duplicator    = $post_duplicator;
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'init', [ $this, 'register_post_statuses' ] );
		\add_filter( 'wp_insert_post_data', [ $this, 'change_post_copy_status' ], 1, 2 );

		$enabled_post_types = $this->permissions_helper->get_enabled_post_types();
		foreach ( $enabled_post_types as $enabled_post_type ) {
			/**
			 * Called in the REST API when submitting the post copy in the Block Editor.
			 * Runs the republishing of the copy onto the original.
			 */
			\add_action( "rest_after_insert_{$enabled_post_type}", [ $this, 'republish_after_rest_api_request' ] );
		}

		/**
		 * Called by `wp_insert_post()` when submitting the post copy, which runs in two cases:
		 * - In the Classic Editor, where there's only one request that updates everything.
		 * - In the Block Editor, only when there are custom meta boxes.
		 */
		\add_action( 'wp_insert_post', [ $this, 'republish_after_post_request' ], \PHP_INT_MAX, 2 );

		// Clean up after the redirect to the original post.
		\add_action( 'load-post.php', [ $this, 'clean_up_after_redirect' ] );
		// Clean up the original when the copy is manually deleted from the trash.
		\add_action( 'before_delete_post', [ $this, 'clean_up_when_copy_manually_deleted' ] );
		// Ensure scheduled Rewrite and Republish posts are properly handled.
		\add_action( 'future_to_publish', [ $this, 'republish_scheduled_post' ] );
	}

	/**
	 * Adds custom post statuses.
	 *
	 * These post statuses are meant for internal use. However, we can't use the
	 * `internal` status because the REST API posts controller allows all registered
	 * statuses but the `internal` one.
	 *
	 * @return void
	 */
	public function register_post_statuses() {
		$options = [
			'label'                     => \__( 'Republish', 'duplicate-post' ),
			'exclude_from_search'       => false,
			'show_in_admin_all_list'    => false,
			'show_in_admin_status_list' => false,
		];

		\register_post_status( 'dp-rewrite-republish', $options );
	}

	/**
	 * Changes the post copy status.
	 *
	 * Runs on the `wp_insert_post_data` hook in `wp_insert_post()` when
	 * submitting the post copy.
	 *
	 * @param array $data    An array of slashed, sanitized, and processed post data.
	 * @param array $postarr An array of sanitized (and slashed) but otherwise unmodified post data.
	 *
	 * @return array An array of slashed, sanitized, and processed attachment post data.
	 */
	public function change_post_copy_status( $data, $postarr ) {
		if ( ! \array_key_exists( 'ID', $postarr ) || empty( $postarr['ID'] ) ) {
			return $data;
		}

		$post = \get_post( $postarr['ID'] );

		if ( ! $post || ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return $data;
		}

		if ( $data['post_status'] === 'publish' ) {
			$data['post_status'] = 'dp-rewrite-republish';
		}

		return $data;
	}

	/**
	 * Executes the republish request.
	 *
	 * @param WP_Post $post The copy's post object.
	 *
	 * @return void
	 */
	public function republish_request( $post ) {
		if (
			! $post instanceof WP_Post
			|| ! $this->permissions_helper->is_rewrite_and_republish_copy( $post )
			|| ! $this->permissions_helper->is_copy_allowed_to_be_republished( $post )
		) {
			return;
		}

		$original_post = Utils::get_original( $post->ID );

		if ( ! $original_post ) {
			return;
		}

		$this->republish( $post, $original_post );

		// Trigger the redirect in the Classic Editor.
		if ( $this->is_classic_editor_post_request() ) {
			$this->redirect( $original_post->ID, $post->ID );
		}
	}

	/**
	 * Republishes the original post with the passed post, when using the Block Editor.
	 *
	 * @param WP_Post $post The copy's post object.
	 *
	 * @return void
	 */
	public function republish_after_rest_api_request( $post ) {
		$this->republish_request( $post );
	}

	/**
	 * Republishes the original post with the passed post, when using the Classic Editor.
	 *
	 * Runs also in the Block Editor to save the custom meta data only when there
	 * are custom meta boxes.
	 *
	 * @param int     $post_id The copy's post ID.
	 * @param WP_Post $post    The copy's post object.
	 *
	 * @return void
	 */
	public function republish_after_post_request( $post_id, $post ) {
		if ( $this->is_rest_request() ) {
			return;
		}

		$this->republish_request( $post );
	}

	/**
	 * Republishes the scheduled Rewrited and Republish post.
	 *
	 * @param WP_Post $copy The scheduled copy.
	 *
	 * @return void
	 */
	public function republish_scheduled_post( $copy ) {
		if ( ! $copy instanceof WP_Post || ! $this->permissions_helper->is_rewrite_and_republish_copy( $copy ) ) {
			return;
		}

		$original_post = Utils::get_original( $copy->ID );

		// If the original post was permanently deleted, we don't want to republish, so trash instead.
		if ( ! $original_post ) {
			$this->delete_copy( $copy->ID, null, false );

			return;
		}

		\kses_remove_filters();
		$this->republish( $copy, $original_post );
		\kses_init_filters();
		$this->delete_copy( $copy->ID, $original_post->ID );
	}

	/**
	 * Cleans up the copied post and temporary metadata after the user has been redirected.
	 *
	 * @return void
	 */
	public function clean_up_after_redirect() {
		if ( ! empty( $_GET['dprepublished'] ) && ! empty( $_GET['dpcopy'] ) && ! empty( $_GET['post'] ) ) {
			$copy_id = \intval( \wp_unslash( $_GET['dpcopy'] ) );
			$post_id = \intval( \wp_unslash( $_GET['post'] ) );

			\check_admin_referer( 'dp-republish', 'dpnonce' );

			if ( \intval( \get_post_meta( $copy_id, '_dp_has_been_republished', true ) ) === 1 ) {
				$this->delete_copy( $copy_id, $post_id );
			}
			else {
				\wp_die( \esc_html__( 'An error occurred while deleting the Rewrite & Republish copy.', 'duplicate-post' ) );
			}
		}
	}

	/**
	 * Checks whether a request is the Classic Editor POST request.
	 *
	 * @return bool Whether the request is the Classic Editor POST request.
	 */
	public function is_classic_editor_post_request() {
		if ( $this->is_rest_request() || \wp_doing_ajax() ) {
			return false;
		}

		return isset( $_GET['meta-box-loader'] ) === false;
	}

	/**
	 * Determines whether the current request is a REST request.
	 *
	 * @return bool Whether or not the request is a REST request.
	 */
	public function is_rest_request() {
		return \defined( 'REST_REQUEST' ) && \REST_REQUEST;
	}

	/**
	 * Republishes the post by overwriting the original post.
	 *
	 * @param WP_Post $post          The Rewrite & Republish copy.
	 * @param WP_Post $original_post The original post.
	 *
	 * @return void
	 */
	public function republish( WP_Post $post, WP_Post $original_post ) {
		// Remove WordPress default filter so a new revision is not created on republish.
		\remove_action( 'post_updated', 'wp_save_post_revision', 10 );

		// Republish taxonomies and meta.
		$this->republish_post_taxonomies( $post );
		$this->republish_post_meta( $post );

		// Republish the post.
		$this->republish_post_elements( $post, $original_post );

		// Mark the copy as already published.
		\update_post_meta( $post->ID, '_dp_has_been_republished', '1' );

		// Re-enable the creation of a new revision.
		\add_action( 'post_updated', 'wp_save_post_revision', 10, 1 );
	}

	/**
	 * Deletes the copy and associated post meta, if applicable.
	 *
	 * @param int      $copy_id            The copy's ID.
	 * @param int|null $post_id            The original post's ID. Optional.
	 * @param bool     $permanently_delete Whether to permanently delete the copy. Defaults to true.
	 *
	 * @return void
	 */
	public function delete_copy( $copy_id, $post_id = null, $permanently_delete = true ) {
		/**
		 * Fires before deleting a Rewrite & Republish copy.
		 *
		 * @param int $copy_id The copy's ID.
		 * @param int $post_id The original post's ID..
		 */
		\do_action( 'duplicate_post_after_rewriting', $copy_id, $post_id );

		// Delete the copy bypassing the trash so it also deletes the copy post meta.
		\wp_delete_post( $copy_id, $permanently_delete );

		if ( ! \is_null( $post_id ) ) {
			// Delete the meta that marks the original post has having a copy.
			\delete_post_meta( $post_id, '_dp_has_rewrite_republish_copy' );
		}
	}

	/**
	 * Republishes the post elements overwriting the original post.
	 *
	 * @param WP_Post $post          The post object.
	 * @param WP_Post $original_post The original post.
	 *
	 * @return void
	 */
	protected function republish_post_elements( $post, $original_post ) {
		// Cast to array and not alter the copy's original object.
		$post_to_be_rewritten = clone $post;

		// Prepare post data for republishing.
		$post_to_be_rewritten->ID          = $original_post->ID;
		$post_to_be_rewritten->post_name   = $original_post->post_name;
		$post_to_be_rewritten->post_status = $this->determine_post_status( $post, $original_post );

		/**
		 * Yoast SEO and other plugins prevent from accidentally updating another post's
		 * data (e.g. the Yoast SEO metadata by checking the $_POST data ID with the post object ID.
		 * We need to overwrite the $_POST data ID to allow updating the original post.
		 */
		$_POST['ID'] = $original_post->ID;

		// Republish the original post.
		$rewritten_post_id = \wp_update_post( $post_to_be_rewritten );

		if ( $rewritten_post_id === 0 ) {
			\wp_die( \esc_html__( 'An error occurred while republishing the post.', 'duplicate-post' ) );
		}
	}

	/**
	 * Republishes the post taxonomies overwriting the ones of the original post.
	 *
	 * @param WP_Post $post The copy's post object.
	 *
	 * @return void
	 */
	protected function republish_post_taxonomies( $post ) {
		$original_post_id = Utils::get_original_post_id( $post->ID );

		$copy_taxonomies_options = [
			'taxonomies_excludelist' => [],
			'use_filters'            => false,
			'copy_format'            => true,
		];
		$this->post_duplicator->copy_post_taxonomies( $original_post_id, $post, $copy_taxonomies_options );
	}

	/**
	 * Republishes the post meta overwriting the ones of the original post.
	 *
	 * @param WP_Post $post The copy's post object.
	 *
	 * @return void
	 */
	protected function republish_post_meta( $post ) {
		$original_post_id = Utils::get_original_post_id( $post->ID );

		$copy_meta_options = [
			'meta_excludelist' => Utils::get_default_filtered_meta_names(),
			'use_filters'      => false,
			'copy_thumbnail'   => true,
			'copy_template'    => true,
		];
		$this->post_duplicator->copy_post_meta_info( $original_post_id, $post, $copy_meta_options );
	}

	/**
	 * Redirects the user to the original post.
	 *
	 * @param int $original_post_id The ID of the original post to redirect to.
	 * @param int $copy_id          The ID of the copy post.
	 *
	 * @return void
	 */
	protected function redirect( $original_post_id, $copy_id ) {
		\wp_safe_redirect(
			\add_query_arg(
				[
					'dprepublished' => 1,
					'dpcopy'        => $copy_id,
					'dpnonce'       => \wp_create_nonce( 'dp-republish' ),
				],
				\admin_url( 'post.php?action=edit&post=' . $original_post_id )
			)
		);
		exit();
	}

	/**
	 * Determines the post status to use when publishing the Rewrite & Republish copy.
	 *
	 * @param WP_Post $post          The post object.
	 * @param WP_Post $original_post The original post object.
	 *
	 * @return string The post status to use.
	 */
	protected function determine_post_status( $post, $original_post ) {
		if ( $original_post->post_status === 'trash' ) {
			return 'trash';
		}

		if ( $post->post_status === 'private' ) {
			return 'private';
		}

		return 'publish';
	}

	/**
	 * Deletes the original post meta that flags it as having a copy when the copy is manually deleted.
	 *
	 * @param int $post_id Post ID of a post that is going to be deleted.
	 *
	 * @return void
	 */
	public function clean_up_when_copy_manually_deleted( $post_id ) {
		$post = \get_post( $post_id );

		if ( ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return;
		}

		$original_post_id = Utils::get_original_post_id( $post_id );
		\delete_post_meta( $original_post_id, '_dp_has_rewrite_republish_copy' );
	}
}
PK!ǩxi##src/ui/link-builder.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;

/**
 * Duplicate Post link builder.
 */
class Link_Builder {

	/**
	 * Builds URL for duplication action for the Rewrite & Republish feature.
	 *
	 * @param int|WP_Post $post    The post object or ID.
	 * @param string      $context The context in which the URL will be used.
	 *
	 * @return string The URL for the link.
	 */
	public function build_rewrite_and_republish_link( $post, $context = 'display' ) {
		return $this->build_link( $post, $context, 'duplicate_post_rewrite' );
	}

	/**
	 * Builds URL for the "Clone" action.
	 *
	 * @param int|WP_Post $post    The post object or ID.
	 * @param string      $context The context in which the URL will be used.
	 *
	 * @return string The URL for the link.
	 */
	public function build_clone_link( $post, $context = 'display' ) {
		return $this->build_link( $post, $context, 'duplicate_post_clone' );
	}

	/**
	 * Builds URL for the "Copy to a new draft" action.
	 *
	 * @param int|WP_Post $post    The post object or ID.
	 * @param string      $context The context in which the URL will be used.
	 *
	 * @return string The URL for the link.
	 */
	public function build_new_draft_link( $post, $context = 'display' ) {
		return $this->build_link( $post, $context, 'duplicate_post_new_draft' );
	}

	/**
	 * Builds URL for the "Check Changes" action.
	 *
	 * @param int|WP_Post $post    The post object or ID.
	 * @param string      $context The context in which the URL will be used.
	 *
	 * @return string The URL for the link.
	 */
	public function build_check_link( $post, $context = 'display' ) {
		return $this->build_link( $post, $context, 'duplicate_post_check_changes' );
	}

	/**
	 * Builds URL for duplication action.
	 *
	 * @param int|WP_Post $post        The post object or ID.
	 * @param string      $context     The context in which the URL will be used.
	 * @param string      $action_name The action for the URL.
	 *
	 * @return string The URL for the link.
	 */
	public function build_link( $post, $context, $action_name ) {
		$post = \get_post( $post );
		if ( ! $post instanceof WP_Post ) {
			return '';
		}

		if ( $context === 'display' ) {
			$action = '?action=' . $action_name . '&amp;post=' . $post->ID;
		}
		else {
			$action = '?action=' . $action_name . '&post=' . $post->ID;
		}

		return \wp_nonce_url(
			/**
			 * Filter on the URL of the clone link
			 *
			 * @param string $url           The URL of the clone link.
			 * @param int    $ID            The ID of the post
			 * @param string $context       The context in which the URL is used.
			 * @param string $action_name   The action name.
			 *
			 * @return string
			 */
			\apply_filters( 'duplicate_post_get_clone_post_link', \admin_url( 'admin.php' . $action ), $post->ID, $context, $action_name ),
			$action_name . '_' . $post->ID
		);
	}
}
PK!#*
[src/ui/metabox.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the metabox.
 */
class Metabox {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \intval( \get_option( 'duplicate_post_show_original_meta_box' ) ) === 1 ) {
			\add_action( 'add_meta_boxes', [ $this, 'add_custom_metabox' ], 10, 2 );
		}
	}

	/**
	 * Adds a metabox to Edit screen.
	 *
	 * @param string  $post_type The post type.
	 * @param WP_Post $post      The current post object.
	 *
	 * @return void
	 */
	public function add_custom_metabox( $post_type, $post ) {
		$enabled_post_types = $this->permissions_helper->get_enabled_post_types();

		if ( \in_array( $post_type, $enabled_post_types, true )
			&& $post instanceof WP_Post ) {
			$original_item = Utils::get_original( $post );

			if ( $original_item instanceof WP_Post ) {
				\add_meta_box(
					'duplicate_post_show_original',
					\__( 'Duplicate Post', 'duplicate-post' ),
					[ $this, 'custom_metabox_html' ],
					$post_type,
					'side',
					'default',
					[ 'original' => $original_item ]
				);
			}
		}
	}

	/**
	 * Outputs the HTML for the metabox.
	 *
	 * @param WP_Post $post    The current post.
	 * @param array   $metabox The array containing the metabox data.
	 *
	 * @return void
	 */
	public function custom_metabox_html( $post, $metabox ) {
		$original_item = $metabox['args']['original'];
		if ( ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			?>
		<p>
			<input type="checkbox"
				name="duplicate_post_remove_original"
				id="duplicate-post-remove-original"
				value="duplicate_post_remove_original"
				aria-describedby="duplicate-post-remove-original-description">
			<label for="duplicate-post-remove-original">
				<?php \esc_html_e( 'Delete reference to original item.', 'duplicate-post' ); ?>
			</label>
		</p>
			<?php
		}
		?>
		<p id="duplicate-post-remove-original-description">
			<?php
			\printf(
				\wp_kses(
					/* translators: %s: post title */
					\__(
						'The original item this was copied from is: <span class="duplicate_post_original_item_title_span">%s</span>',
						'duplicate-post'
					),
					[
						'span' => [
							'class' => [],
						],
					]
				),
				Utils::get_edit_or_view_link( $original_item )  // phpcs:ignore WordPress.Security.EscapeOutput
			);
			?>
		</p>
		<?php
	}
}
PK!���bbsrc/ui/user-interface.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post user interface.
 */
class User_Interface {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the object to manage the row actions for the post.
	 *
	 * @var Row_Actions
	 */
	protected $row_actions;

	/**
	 * Holds the object to manage the classic editor UI.
	 *
	 * @var Classic_Editor
	 */
	protected $classic_editor;

	/**
	 * Holds the object to manage the block editor UI.
	 *
	 * @var Block_Editor
	 */
	protected $block_editor;

	/**
	 * Holds the object to manage the admin bar links.
	 *
	 * @var Admin_Bar
	 */
	protected $admin_bar;

	/**
	 * Holds the object to manage the bulk actions dropdown.
	 *
	 * @var Bulk_Actions
	 */
	protected $bulk_actions;

	/**
	 * Post states object.
	 *
	 * @var Post_States
	 */
	protected $post_states;

	/**
	 * Metabox object.
	 *
	 * @var Metabox
	 */
	protected $metabox;

	/**
	 * Newsletter object.
	 *
	 * @var Newsletter
	 */
	protected $newsletter;

	/**
	 * Column object.
	 *
	 * @var Column
	 */
	protected $column;

	/**
	 * Holds the object to create the action link to duplicate.
	 *
	 * @var Link_Builder
	 */
	protected $link_builder;

	/**
	 * Holds the object to create the action link to duplicate.
	 *
	 * @var Asset_Manager
	 */
	protected $asset_manager;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The permissions helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;
		$this->link_builder       = new Link_Builder();
		$this->asset_manager      = new Asset_Manager();
		$this->asset_manager->register_hooks();

		$this->admin_bar      = new Admin_Bar( $this->link_builder, $this->permissions_helper, $this->asset_manager );
		$this->block_editor   = new Block_Editor( $this->link_builder, $this->permissions_helper, $this->asset_manager );
		$this->bulk_actions   = new Bulk_Actions( $this->permissions_helper );
		$this->column         = new Column( $this->permissions_helper, $this->asset_manager );
		$this->metabox        = new Metabox( $this->permissions_helper );
		$this->newsletter     = new Newsletter();
		$this->post_states    = new Post_States( $this->permissions_helper );
		$this->classic_editor = new Classic_Editor( $this->link_builder, $this->permissions_helper, $this->asset_manager );
		$this->row_actions    = new Row_Actions( $this->link_builder, $this->permissions_helper );

		$this->admin_bar->register_hooks();
		$this->block_editor->register_hooks();
		$this->bulk_actions->register_hooks();
		$this->column->register_hooks();
		$this->metabox->register_hooks();
		$this->post_states->register_hooks();
		$this->classic_editor->register_hooks();
		$this->row_actions->register_hooks();
	}
}
PK!J��p��src/ui/post-states.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the post states display.
 */
class Post_States {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_filter( 'display_post_states', [ $this, 'show_original_in_post_states' ], 10, 2 );
	}

	/**
	 * Shows link to original post in the post states.
	 *
	 * @param array   $post_states The array of post states.
	 * @param WP_Post $post        The current post.
	 *
	 * @return array The updated post states array.
	 */
	public function show_original_in_post_states( $post_states, $post ) {
		if ( ! $post instanceof WP_Post
			|| ! \is_array( $post_states ) ) {
			return $post_states;
		}

		$original_item = Utils::get_original( $post );

		if ( ! $original_item ) {
			return $post_states;
		}

		if ( $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			/* translators: %s: Original item link (to view or edit) or title. */
			$post_states['duplicate_post_original_item'] = \sprintf( \esc_html__( 'Rewrite & Republish of %s', 'duplicate-post' ), Utils::get_edit_or_view_link( $original_item ) );
			return $post_states;
		}

		if ( \intval( \get_option( 'duplicate_post_show_original_in_post_states' ) ) === 1 ) {
			/* translators: %s: Original item link (to view or edit) or title. */
			$post_states['duplicate_post_original_item'] = \sprintf( \__( 'Original: %s', 'duplicate-post' ), Utils::get_edit_or_view_link( $original_item ) );
		}

		return $post_states;
	}
}
PK!�/wwsrc/ui/block-editor.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the block editor UI.
 */
class Block_Editor {

	/**
	 * Holds the object to create the action link to duplicate.
	 *
	 * @var Link_Builder
	 */
	protected $link_builder;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the asset manager.
	 *
	 * @var Asset_Manager
	 */
	protected $asset_manager;

	/**
	 * Initializes the class.
	 *
	 * @param Link_Builder       $link_builder       The link builder.
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 * @param Asset_Manager      $asset_manager      The asset manager.
	 */
	public function __construct( Link_Builder $link_builder, Permissions_Helper $permissions_helper, Asset_Manager $asset_manager ) {
		$this->link_builder       = $link_builder;
		$this->permissions_helper = $permissions_helper;
		$this->asset_manager      = $asset_manager;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'elementor/editor/after_enqueue_styles', [ $this, 'hide_elementor_post_status' ] );
		\add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue_elementor_script' ], 9 );
		\add_action( 'admin_enqueue_scripts', [ $this, 'should_previously_used_keyword_assessment_run' ], 9 );
		\add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_scripts' ] );
		\add_filter( 'wpseo_link_suggestions_indexables', [ $this, 'remove_original_from_wpseo_link_suggestions' ], 10, 3 );
	}

	/**
	 * Enqueues the necessary Elementor script for the current post.
	 *
	 * @return void
	 */
	public function enqueue_elementor_script() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post ) {
			return;
		}

		$edit_js_object = $this->generate_js_object( $post );
		$this->asset_manager->enqueue_elementor_script( $edit_js_object );
	}

	/**
	 * Hides the post status control if we're working on a Rewrite and Republish post.
	 *
	 * @return void
	 */
	public function hide_elementor_post_status() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post || ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return;
		}
		\wp_add_inline_style(
			'elementor-editor',
			'.elementor-control-post_status { display: none !important; }'
		);
	}

	/**
	 * Disables the Yoast SEO PreviouslyUsedKeyword assessment for Rewrite & Republish original and duplicate posts.
	 *
	 * @return void
	 */
	public function should_previously_used_keyword_assessment_run() {
		if ( $this->permissions_helper->is_edit_post_screen() || $this->permissions_helper->is_new_post_screen() ) {

			$post = \get_post();

			if (
				$post instanceof WP_Post
				&& (
					$this->permissions_helper->is_rewrite_and_republish_copy( $post )
					|| $this->permissions_helper->has_rewrite_and_republish_copy( $post )
				)
			) {
				\add_filter( 'wpseo_previously_used_keyword_active', '__return_false' );
			}
		}
	}

	/**
	 * Enqueues the necessary JavaScript code for the block editor.
	 *
	 * @return void
	 */
	public function enqueue_block_editor_scripts() {
		if ( ! $this->permissions_helper->is_edit_post_screen() && ! $this->permissions_helper->is_new_post_screen() ) {
			return;
		}

		$post = \get_post();

		if ( ! $post instanceof WP_Post ) {
			return;
		}

		$edit_js_object = $this->generate_js_object( $post );
		$this->asset_manager->enqueue_edit_script( $edit_js_object );

		if ( $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			$string_js_object = [
				'checkLink' => $this->get_check_permalink(),
			];
			$this->asset_manager->enqueue_strings_script( $string_js_object );
		}
	}

	/**
	 * Generates a New Draft permalink for the current post.
	 *
	 * @return string The permalink. Returns empty if the post can't be copied.
	 */
	public function get_new_draft_permalink() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post || ! $this->permissions_helper->should_links_be_displayed( $post ) ) {
			return '';
		}

		return $this->link_builder->build_new_draft_link( $post );
	}

	/**
	 * Generates a Rewrite & Republish permalink for the current post.
	 *
	 * @return string The permalink. Returns empty if the post cannot be copied for Rewrite & Republish.
	 */
	public function get_rewrite_republish_permalink() {
		$post = \get_post();

		if (
			! $post instanceof WP_Post
			|| $this->permissions_helper->is_rewrite_and_republish_copy( $post )
			|| $this->permissions_helper->has_rewrite_and_republish_copy( $post )
			|| ! $this->permissions_helper->should_links_be_displayed( $post )
		) {
			return '';
		}

		return $this->link_builder->build_rewrite_and_republish_link( $post );
	}

	/**
	 * Generates a Check Changes permalink for the current post, if it's intended for Rewrite & Republish.
	 *
	 * @return string The permalink. Returns empty if the post does not exist or it's not a Rewrite & Republish copy.
	 */
	public function get_check_permalink() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post || ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return '';
		}

		return $this->link_builder->build_check_link( $post );
	}

	/**
	 * Generates a URL to the original post edit screen.
	 *
	 * @return string The URL. Empty if the copy post doesn't have an original.
	 */
	public function get_original_post_edit_url() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post || ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return '';
		}

		$original_post_id = Utils::get_original_post_id( $post->ID );

		if ( ! $original_post_id ) {
			return '';
		}

		return \add_query_arg(
			[
				'dprepublished' => 1,
				'dpcopy'        => $post->ID,
				'dpnonce'       => \wp_create_nonce( 'dp-republish' ),
			],
			\admin_url( 'post.php?action=edit&post=' . $original_post_id )
		);
	}

	/**
	 * Generates an array of data to be passed as a localization object to JavaScript.
	 *
	 * @param WP_Post $post The current post object.
	 *
	 * @return array The data to pass to JavaScript.
	 */
	protected function generate_js_object( WP_Post $post ) {
		$is_rewrite_and_republish_copy = $this->permissions_helper->is_rewrite_and_republish_copy( $post );

		return [
			'newDraftLink'            => $this->get_new_draft_permalink(),
			'rewriteAndRepublishLink' => $this->get_rewrite_republish_permalink(),
			'showLinks'               => Utils::get_option( 'duplicate_post_show_link' ),
			'showLinksIn'             => Utils::get_option( 'duplicate_post_show_link_in' ),
			'rewriting'               => ( $is_rewrite_and_republish_copy ) ? 1 : 0,
			'originalEditURL'         => $this->get_original_post_edit_url(),
		];
	}

	/**
	 * Filters the Yoast SEO Premium link suggestions.
	 *
	 * Removes the original post from the Yoast SEO Premium link suggestions
	 * displayed on the Rewrite & Republish copy.
	 *
	 * @param array  $suggestions An array of suggestion indexables that can be filtered.
	 * @param int    $object_id   The object id for the current indexable.
	 * @param string $object_type The object type for the current indexable.
	 *
	 * @return array The filtered array of suggestion indexables.
	 */
	public function remove_original_from_wpseo_link_suggestions( $suggestions, $object_id, $object_type ) {
		if ( $object_type !== 'post' ) {
			return $suggestions;
		}

		// WordPress get_post already checks if the passed ID is valid and returns null if it's not.
		$post = \get_post( $object_id );

		if ( ! $post instanceof WP_Post || ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return $suggestions;
		}

		$original_post_id = Utils::get_original_post_id( $post->ID );

		return \array_filter(
			$suggestions,
			static function ( $suggestion ) use ( $original_post_id ) {
				return $suggestion->object_id !== $original_post_id;
			}
		);
	}
}
PK!)m5���src/ui/asset-manager.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage assets.
 */
class Asset_Manager {

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'init', [ $this, 'register_styles' ] );
		\add_action( 'init', [ $this, 'register_scripts' ] );
	}

	/**
	 * Registers the styles.
	 *
	 * @return void
	 */
	public function register_styles() {
		\wp_register_style( 'duplicate-post', \plugins_url( '/css/duplicate-post.css', \DUPLICATE_POST_FILE ), [], \DUPLICATE_POST_CURRENT_VERSION );
		\wp_register_style( 'duplicate-post-options', \plugins_url( '/css/duplicate-post-options.css', \DUPLICATE_POST_FILE ), [], \DUPLICATE_POST_CURRENT_VERSION );
	}

	/**
	 * Registers the scripts.
	 *
	 * @return void
	 */
	public function register_scripts() {
		$flattened_version = Utils::flatten_version( \DUPLICATE_POST_CURRENT_VERSION );

		\wp_register_script(
			'duplicate_post_edit_script',
			\plugins_url( \sprintf( 'js/dist/duplicate-post-edit-%s.js', $flattened_version ), \DUPLICATE_POST_FILE ),
			[
				'wp-components',
				'wp-element',
				'wp-i18n',
			],
			\DUPLICATE_POST_CURRENT_VERSION,
			true
		);

		\wp_register_script(
			'duplicate_post_strings',
			\plugins_url( \sprintf( 'js/dist/duplicate-post-strings-%s.js', $flattened_version ), \DUPLICATE_POST_FILE ),
			[
				'wp-components',
				'wp-element',
				'wp-i18n',
			],
			\DUPLICATE_POST_CURRENT_VERSION,
			true
		);

		\wp_register_script(
			'duplicate_post_quick_edit_script',
			\plugins_url( \sprintf( 'js/dist/duplicate-post-quick-edit-%s.js', $flattened_version ), \DUPLICATE_POST_FILE ),
			[ 'jquery' ],
			\DUPLICATE_POST_CURRENT_VERSION,
			true
		);

		\wp_register_script(
			'duplicate_post_options_script',
			\plugins_url( \sprintf( 'js/dist/duplicate-post-options-%s.js', $flattened_version ), \DUPLICATE_POST_FILE ),
			[ 'jquery' ],
			\DUPLICATE_POST_CURRENT_VERSION,
			true
		);
	}

	/**
	 * Enqueues the styles.
	 *
	 * @return void
	 */
	public function enqueue_styles() {
		\wp_enqueue_style( 'duplicate-post' );
	}

	/**
	 * Enqueues the styles for the options page.
	 *
	 * @return void
	 */
	public function enqueue_options_styles() {
		\wp_enqueue_style( 'duplicate-post-options' );
	}

	/**
	 * Enqueues the script for the Block editor and passes object via localization.
	 *
	 * @param array $data_object The object to pass to the script.
	 *
	 * @return void
	 */
	public function enqueue_edit_script( $data_object = [] ) {
		$handle = 'duplicate_post_edit_script';
		\wp_enqueue_script( $handle );
		\wp_add_inline_script(
			$handle,
			'let duplicatePostNotices = {};',
			'before'
		);
		\wp_localize_script(
			$handle,
			'duplicatePost',
			$data_object
		);
	}

	/**
	 * Enqueues the script for the Javascript strings and passes object via localization.
	 *
	 * @param array $data_object The object to pass to the script.
	 *
	 * @return void
	 */
	public function enqueue_strings_script( $data_object = [] ) {
		$handle = 'duplicate_post_strings';
		\wp_enqueue_script( $handle );
		\wp_localize_script(
			$handle,
			'duplicatePostStrings',
			$data_object
		);
	}

	/**
	 * Enqueues the script for the Quick Edit.
	 *
	 * @return void
	 */
	public function enqueue_quick_edit_script() {
		\wp_enqueue_script( 'duplicate_post_quick_edit_script' );
	}

	/**
	 * Enqueues the script for the Options page.
	 *
	 * @return void
	 */
	public function enqueue_options_script() {
		\wp_enqueue_script( 'duplicate_post_options_script' );
	}

	/**
	 * Enqueues the script for the Elementor plugin.
	 *
	 * @param array $data_object The object to pass to the script.
	 *
	 * @return void
	 */
	public function enqueue_elementor_script( $data_object = [] ) {
		$flattened_version = Utils::flatten_version( \DUPLICATE_POST_CURRENT_VERSION );
		$handle            = 'duplicate_post_elementor_script';

		\wp_register_script(
			$handle,
			\plugins_url( \sprintf( 'js/dist/duplicate-post-elementor-%s.js', $flattened_version ), \DUPLICATE_POST_FILE ),
			[ 'jquery' ],
			\DUPLICATE_POST_CURRENT_VERSION,
			true
		);
		\wp_enqueue_script( $handle );
		\wp_localize_script(
			$handle,
			'duplicatePost',
			$data_object
		);
	}
}
PK!�oH�src/ui/column.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the custom column + quick edit.
 */
class Column {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the asset manager.
	 *
	 * @var Asset_Manager
	 */
	protected $asset_manager;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 * @param Asset_Manager      $asset_manager      The asset manager.
	 */
	public function __construct( Permissions_Helper $permissions_helper, Asset_Manager $asset_manager ) {
		$this->permissions_helper = $permissions_helper;
		$this->asset_manager      = $asset_manager;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \intval( \get_option( 'duplicate_post_show_original_column' ) ) === 1 ) {
			$enabled_post_types = $this->permissions_helper->get_enabled_post_types();
			if ( \count( $enabled_post_types ) ) {
				foreach ( $enabled_post_types as $enabled_post_type ) {
					\add_filter( "manage_{$enabled_post_type}_posts_columns", [ $this, 'add_original_column' ] );
					\add_action( "manage_{$enabled_post_type}_posts_custom_column", [ $this, 'show_original_item' ], 10, 2 );
				}
				\add_action( 'quick_edit_custom_box', [ $this, 'quick_edit_remove_original' ], 10, 2 );
				\add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
				\add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_styles' ] );
			}
		}
	}

	/**
	 * Adds Original item column to the post list.
	 *
	 * @param array $post_columns The post columns array.
	 *
	 * @return array The updated array.
	 */
	public function add_original_column( $post_columns ) {
		if ( \is_array( $post_columns ) ) {
			$post_columns['duplicate_post_original_item'] = \__( 'Original item', 'duplicate-post' );
		}
		return $post_columns;
	}

	/**
	 * Sets the text to be displayed in the Original item column for the current post.
	 *
	 * @param string $column_name The name for the current column.
	 * @param int    $post_id     The ID for the current post.
	 *
	 * @return void
	 */
	public function show_original_item( $column_name, $post_id ) {
		if ( $column_name === 'duplicate_post_original_item' ) {
			$column_content = '-';
			$data_attr      = ' data-no-original="1"';
			$original_item  = Utils::get_original( $post_id );
			if ( $original_item ) {
				$post      = \get_post( $post_id );
				$data_attr = '';

				if ( $post instanceof WP_Post
					&& $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
					$data_attr = ' data-copy-is-for-rewrite-and-republish="1"';
				}

				$column_content = Utils::get_edit_or_view_link( $original_item );
			}
			echo \sprintf(
				'<span class="duplicate_post_original_link"%s>%s</span>',
				$data_attr, // phpcs:ignore WordPress.Security.EscapeOutput
				$column_content // phpcs:ignore WordPress.Security.EscapeOutput
			);
		}
	}

	/**
	 * Adds original item checkbox + edit link in the Quick Edit.
	 *
	 * @param string $column_name The name for the current column.
	 *
	 * @return void
	 */
	public function quick_edit_remove_original( $column_name ) {
		if ( $column_name !== 'duplicate_post_original_item' ) {
			return;
		}
		\printf(
			'<fieldset class="inline-edit-col-left" id="duplicate_post_quick_edit_fieldset">
			<div class="inline-edit-col">
				<input type="checkbox"
				name="duplicate_post_remove_original"
				id="duplicate-post-remove-original"
				value="duplicate_post_remove_original"
				aria-describedby="duplicate-post-remove-original-description">
				<label for="duplicate-post-remove-original">
					<span class="checkbox-title">%s</span>
				</label>
				<span id="duplicate-post-remove-original-description" class="checkbox-title">%s</span>
			</div>
		</fieldset>',
			\esc_html__(
				'Delete reference to original item.',
				'duplicate-post'
			),
			\wp_kses(
				\__(
					'The original item this was copied from is: <span class="duplicate_post_original_item_title_span"></span>',
					'duplicate-post'
				),
				[
					'span' => [
						'class' => [],
					],
				]
			)
		);
	}

	/**
	 * Enqueues the Javascript file to inject column data into the Quick Edit.
	 *
	 * @param string $hook The current admin page.
	 *
	 * @return void
	 */
	public function admin_enqueue_scripts( $hook ) {
		if ( $hook === 'edit.php' ) {
			$this->asset_manager->enqueue_quick_edit_script();
		}
	}

	/**
	 * Enqueues the CSS file to for the Quick edit
	 *
	 * @param string $hook The current admin page.
	 *
	 * @return void
	 */
	public function admin_enqueue_styles( $hook ) {
		if ( $hook === 'edit.php' ) {
			$this->asset_manager->enqueue_styles();
		}
	}
}
PK!@��--src/ui/classic-editor.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the classic editor UI.
 */
class Classic_Editor {

	/**
	 * Holds the object to create the action link to duplicate.
	 *
	 * @var Link_Builder
	 */
	protected $link_builder;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the asset manager.
	 *
	 * @var Asset_Manager
	 */
	protected $asset_manager;

	/**
	 * Initializes the class.
	 *
	 * @param Link_Builder       $link_builder       The link builder.
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 * @param Asset_Manager      $asset_manager      The asset manager.
	 */
	public function __construct( Link_Builder $link_builder, Permissions_Helper $permissions_helper, Asset_Manager $asset_manager ) {
		$this->link_builder       = $link_builder;
		$this->permissions_helper = $permissions_helper;
		$this->asset_manager      = $asset_manager;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'post_submitbox_misc_actions', [ $this, 'add_check_changes_link' ], 90 );

		if ( \intval( Utils::get_option( 'duplicate_post_show_link_in', 'submitbox' ) ) === 1 ) {
			if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'new_draft' ) ) === 1 ) {
				\add_action( 'post_submitbox_start', [ $this, 'add_new_draft_post_button' ] );
			}

			if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) ) === 1 ) {
				\add_action( 'post_submitbox_start', [ $this, 'add_rewrite_and_republish_post_button' ] );
			}
		}

		\add_action( 'load-post.php', [ $this, 'hook_translations' ] );
		\add_filter( 'post_updated_messages', [ $this, 'change_scheduled_notice_classic_editor' ] );

		\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_classic_editor_scripts' ] );
		if ( \intval( Utils::get_option( 'duplicate_post_show_link_in', 'submitbox' ) ) === 1 ) {
			if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'new_draft' ) ) === 1
				|| \intval( Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) ) === 1 ) {
				\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_classic_editor_styles' ] );
			}
		}

		// Remove slug editing from Classic Editor.
		\add_action( 'add_meta_boxes', [ $this, 'remove_slug_meta_box' ], 10, 2 );
		\add_filter( 'get_sample_permalink_html', [ $this, 'remove_sample_permalink_slug_editor' ], 10, 5 );
	}

	/**
	 * Hooks the functions to change the translations.
	 *
	 * @return void
	 */
	public function hook_translations() {
			\add_filter( 'gettext', [ $this, 'change_republish_strings_classic_editor' ], 10, 3 );
			\add_filter( 'gettext_with_context', [ $this, 'change_schedule_strings_classic_editor' ], 10, 4 );
	}

	/**
	 * Enqueues the necessary JavaScript code for the Classic editor.
	 *
	 * @return void
	 */
	public function enqueue_classic_editor_scripts() {
		if ( $this->permissions_helper->is_classic_editor() && isset( $_GET['post'] ) ) {
			$id   = \intval( \wp_unslash( $_GET['post'] ) );
			$post = \get_post( $id );

			if ( ! \is_null( $post ) && $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
				$this->asset_manager->enqueue_strings_script();
			}
		}
	}

	/**
	 * Enqueues the necessary styles for the Classic editor.
	 *
	 * @return void
	 */
	public function enqueue_classic_editor_styles() {
		if ( $this->permissions_helper->is_classic_editor()
			&& isset( $_GET['post'] ) ) {
			$id   = \intval( \wp_unslash( $_GET['post'] ) );
			$post = \get_post( $id );

			if ( ! \is_null( $post ) && $this->permissions_helper->should_links_be_displayed( $post ) ) {
				$this->asset_manager->enqueue_styles();
			}
		}
	}

	/**
	 * Adds a button in the post/page edit screen to create a clone
	 *
	 * @param WP_Post|null $post The post object that's being edited.
	 *
	 * @return void
	 */
	public function add_new_draft_post_button( $post = null ) {
		if ( \is_null( $post ) ) {
			if ( isset( $_GET['post'] ) ) {
				$id   = \intval( \wp_unslash( $_GET['post'] ) );
				$post = \get_post( $id );
			}
		}

		if ( $post instanceof WP_Post && $this->permissions_helper->should_links_be_displayed( $post ) ) {
			?>
			<div id="duplicate-action">
				<a class="submitduplicate duplication"
					href="<?php echo \esc_url( $this->link_builder->build_new_draft_link( $post ) ); ?>"><?php \esc_html_e( 'Copy to a new draft', 'duplicate-post' ); ?>
				</a>
			</div>
			<?php
		}
	}

	/**
	 * Adds a button in the post/page edit screen to create a clone for Rewrite & Republish.
	 *
	 * @param WP_Post|null $post The post object that's being edited.
	 *
	 * @return void
	 */
	public function add_rewrite_and_republish_post_button( $post = null ) {
		if ( \is_null( $post ) ) {
			if ( isset( $_GET['post'] ) ) {
				$id   = \intval( \wp_unslash( $_GET['post'] ) );
				$post = \get_post( $id );
			}
		}

		if (
			$post instanceof WP_Post
			&& $this->permissions_helper->should_rewrite_and_republish_be_allowed( $post )
			&& $this->permissions_helper->should_links_be_displayed( $post )
		) {
			?>
			<div id="rewrite-republish-action">
				<a class="submitduplicate duplication" href="<?php echo \esc_url( $this->link_builder->build_rewrite_and_republish_link( $post ) ); ?>"><?php \esc_html_e( 'Rewrite & Republish', 'duplicate-post' ); ?>
				</a>
			</div>
			<?php
		}
	}

	/**
	 * Adds a message in the post/page edit screen to create a clone for Rewrite & Republish.
	 *
	 * @param WP_Post|null $post The post object that's being edited.
	 *
	 * @return void
	 */
	public function add_check_changes_link( $post = null ) {
		if ( \is_null( $post ) ) {
			if ( isset( $_GET['post'] ) ) {
				$id   = \intval( \wp_unslash( $_GET['post'] ) );
				$post = \get_post( $id );
			}
		}

		if ( $post instanceof WP_Post && $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			?>
				<div id="check-changes-action" class="misc-pub-section">
					<?php \esc_html_e( 'Do you want to compare your changes with the original version before merging? Please save any changes first.', 'duplicate-post' ); ?>
					<br><br>
					<a class='button' href=<?php echo \esc_url( $this->link_builder->build_check_link( $post ) ); ?>>
						<?php \esc_html_e( 'Compare', 'duplicate-post' ); ?>
					</a>
				</div>
				<?php
		}
	}

	/**
	 * Changes the 'Publish' copies in the submitbox to 'Republish' if a post is intended for republishing.
	 *
	 * @param string $translation The translated text.
	 * @param string $text        The text to translate.
	 * @param string $domain      The translation domain.
	 *
	 * @return string The to-be-used copy of the text.
	 */
	public function change_republish_strings_classic_editor( $translation, $text, $domain ) {
		if ( $domain !== 'default' ) {
			return $translation;
		}

		if ( $text === 'Publish'
			&& $this->should_change_rewrite_republish_copy( \get_post() ) ) {
				return \__( 'Republish', 'duplicate-post' );
		}
		elseif ( $text === 'Publish on: %s'
			&& $this->should_change_rewrite_republish_copy( \get_post() ) ) {
			/* translators: %s: Date on which the post is to be republished. */
			return \__( 'Republish on: %s', 'duplicate-post' );
		}

		return $translation;
	}

	/**
	 * Changes the 'Schedule' copy in the submitbox to 'Schedule republish' if a post is intended for republishing.
	 *
	 * @param string $translation The translated text.
	 * @param string $text        The text to translate.
	 * @param string $context     The translation context.
	 * @param string $domain      The translation domain.
	 *
	 * @return string The to-be-used copy of the text.
	 */
	public function change_schedule_strings_classic_editor( $translation, $text, $context, $domain ) {
		if ( $domain !== 'default' || $context !== 'post action/button label' ) {
			return $translation;
		}

		if ( $text === 'Schedule'
			&& $this->should_change_rewrite_republish_copy( \get_post() ) ) {
			return \__( 'Schedule republish', 'duplicate-post' );
		}

		return $translation;
	}

	/**
	 * Changes the post-scheduled notice when a post or page intended for republishing is scheduled.
	 *
	 * @param array[] $messages Post updated messaged.
	 *
	 * @return array[] The to-be-used messages.
	 */
	public function change_scheduled_notice_classic_editor( $messages ) {
		$post = \get_post();
		if ( ! $this->should_change_rewrite_republish_copy( $post ) ) {
			return $messages;
		}

		$permalink      = \get_permalink( $post->ID );
		$scheduled_date = \get_the_time( \get_option( 'date_format' ), $post );
		$scheduled_time = \get_the_time( \get_option( 'time_format' ), $post );

		if ( $post->post_type === 'post' ) {
			$messages['post'][9] = \sprintf(
				/* translators: 1: The post title with a link to the frontend page, 2: The scheduled date and time. */
				\esc_html__(
					'This rewritten post %1$s is now scheduled to replace the original post. It will be published on %2$s.',
					'duplicate-post'
				),
				'<a href="' . $permalink . '">' . $post->post_title . '</a>',
				'<strong>' . $scheduled_date . ' ' . $scheduled_time . '</strong>'
			);
			return $messages;
		}

		if ( $post->post_type === 'page' ) {
			$messages['page'][9] = \sprintf(
				/* translators: 1: The page title with a link to the frontend page, 2: The scheduled date and time. */
				\esc_html__(
					'This rewritten page %1$s is now scheduled to replace the original page. It will be published on %2$s.',
					'duplicate-post'
				),
				'<a href="' . $permalink . '">' . $post->post_title . '</a>',
				'<strong>' . $scheduled_date . ' ' . $scheduled_time . '</strong>'
			);
		}

		return $messages;
	}

	/**
	 * Determines if the Rewrite & Republish copies for the post should be used.
	 *
	 * @param WP_Post $post The current post object.
	 *
	 * @return bool True if the Rewrite & Republish copies should be used.
	 */
	public function should_change_rewrite_republish_copy( $post ) {
		global $pagenow;
		if ( ! \in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) ) {
			return false;
		}

		if ( ! $post instanceof WP_Post ) {
			return false;
		}

		return $this->permissions_helper->is_rewrite_and_republish_copy( $post );
	}

	/**
	 * Removes the slug meta box in the Classic Editor when the post is a Rewrite & Republish copy.
	 *
	 * @param string  $post_type Post type.
	 * @param WP_Post $post      Post object.
	 *
	 * @return void
	 */
	public function remove_slug_meta_box( $post_type, $post ) {
		if ( $post instanceof WP_Post && $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			\remove_meta_box( 'slugdiv', $post_type, 'normal' );
		}
	}

	/**
	 * Removes the sample permalink slug editor in the Classic Editor when the post is a Rewrite & Republish copy.
	 *
	 * @param string  $html      Sample permalink HTML markup.
	 * @param int     $post_id   Post ID.
	 * @param string  $new_title New sample permalink title.
	 * @param string  $new_slug  New sample permalink slug.
	 * @param WP_Post $post      Post object.
	 *
	 * @return string The filtered HTML of the sample permalink slug editor.
	 */
	public function remove_sample_permalink_slug_editor( $html, $post_id, $new_title, $new_slug, $post ) {
		if ( ! $post instanceof WP_Post ) {
			return $html;
		}

		if ( $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			return '';
		}

		return $html;
	}
}
PK!�GK���src/ui/admin-bar.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the admin bar.
 */
class Admin_Bar {

	/**
	 * Holds the object to create the action link to duplicate.
	 *
	 * @var Link_Builder
	 */
	protected $link_builder;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the asset manager.
	 *
	 * @var Asset_Manager
	 */
	protected $asset_manager;

	/**
	 * Initializes the class.
	 *
	 * @param Link_Builder       $link_builder       The link builder.
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 * @param Asset_Manager      $asset_manager      The asset manager.
	 */
	public function __construct( Link_Builder $link_builder, Permissions_Helper $permissions_helper, Asset_Manager $asset_manager ) {
		$this->link_builder       = $link_builder;
		$this->permissions_helper = $permissions_helper;
		$this->asset_manager      = $asset_manager;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \intval( Utils::get_option( 'duplicate_post_show_link_in', 'adminbar' ) ) === 1 ) {
			\add_action( 'wp_before_admin_bar_render', [ $this, 'admin_bar_render' ] );
			\add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] );
			\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_styles' ] );
		}
	}

	/**
	 * Shows Rewrite & Republish link in the Toolbar.
	 *
	 * @global \WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance.
	 *
	 * @return void
	 */
	public function admin_bar_render() {
		global $wp_admin_bar;

		if ( ! \is_admin_bar_showing() ) {
			return;
		}

		$post = $this->get_current_post();

		if ( ! $post ) {
			return;
		}

		$show_new_draft             = ( \intval( Utils::get_option( 'duplicate_post_show_link', 'new_draft' ) ) === 1 );
		$show_rewrite_and_republish = ( \intval( Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) ) === 1 )
									&& $this->permissions_helper->should_rewrite_and_republish_be_allowed( $post );

		if ( $show_new_draft && $show_rewrite_and_republish ) {
			$wp_admin_bar->add_menu(
				[
					'id'    => 'duplicate-post',
					'title' => '<span class="ab-icon"></span><span class="ab-label">' . \__( 'Duplicate Post', 'duplicate-post' ) . '</span>',
					'href'  => $this->link_builder->build_new_draft_link( $post ),
				]
			);
			$wp_admin_bar->add_menu(
				[
					'id'     => 'new-draft',
					'parent' => 'duplicate-post',
					'title'  => \__( 'Copy to a new draft', 'duplicate-post' ),
					'href'   => $this->link_builder->build_new_draft_link( $post ),
				]
			);
			$wp_admin_bar->add_menu(
				[
					'id'     => 'rewrite-republish',
					'parent' => 'duplicate-post',
					'title'  => \__( 'Rewrite & Republish', 'duplicate-post' ),
					'href'   => $this->link_builder->build_rewrite_and_republish_link( $post ),
				]
			);
		}
		else {
			if ( $show_new_draft ) {
				$wp_admin_bar->add_menu(
					[
						'id'     => 'new-draft',
						'title'  => '<span class="ab-icon"></span><span class="ab-label">' . \__( 'Copy to a new draft', 'duplicate-post' ) . '</span>',
						'href'   => $this->link_builder->build_new_draft_link( $post ),
					]
				);
			}

			if ( $show_rewrite_and_republish ) {
				$wp_admin_bar->add_menu(
					[
						'id'     => 'rewrite-republish',
						'title'  => '<span class="ab-icon"></span><span class="ab-label">' . \__( 'Rewrite & Republish', 'duplicate-post' ) . '</span>',
						'href'   => $this->link_builder->build_rewrite_and_republish_link( $post ),
					]
				);
			}
		}
	}

	/**
	 * Links stylesheet for Toolbar link.
	 *
	 * @global \WP_Query $wp_the_query.
	 *
	 * @return void
	 */
	public function enqueue_styles() {
		if ( ! \is_admin_bar_showing() ) {
			return;
		}

		$post = $this->get_current_post();

		if ( ! $post ) {
			return;
		}

		$this->asset_manager->enqueue_styles();
	}

	/**
	 * Returns the current post object (both if it's displayed or being edited).
	 *
	 * @global \WP_Query $wp_the_query
	 *
	 * @return false|WP_Post The Post object, false if we are not on a post.
	 */
	public function get_current_post() {
		global $wp_the_query;

		if ( \is_admin() ) {
			$post = \get_post();
		}
		else {
			$post = $wp_the_query->get_queried_object();
		}

		if ( empty( $post ) || ! $post instanceof WP_Post ) {
			return false;
		}

		if (
			( ! $this->permissions_helper->is_edit_post_screen() && ! \is_singular( $post->post_type ) )
			|| ! $this->permissions_helper->post_type_has_admin_bar( $post->post_type )
		) {
			return false;
		}

		if ( ! $this->permissions_helper->should_links_be_displayed( $post ) ) {
			return false;
		}

		return $post;
	}
}
PK!M�©�src/ui/bulk-actions.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the bulk actions menu.
 */
class Bulk_Actions {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \intval( Utils::get_option( 'duplicate_post_show_link_in', 'bulkactions' ) ) === 0 ) {
			return;
		}

		\add_action( 'admin_init', [ $this, 'add_bulk_filters' ] );
	}

	/**
	 * Hooks the function to add the Rewrite & Republish option in the bulk actions for the selected post types.
	 *
	 * @return void
	 */
	public function add_bulk_filters() {
		if ( ! $this->permissions_helper->is_current_user_allowed_to_copy() ) {
			return;
		}

		$duplicate_post_types_enabled = $this->permissions_helper->get_enabled_post_types();
		foreach ( $duplicate_post_types_enabled as $duplicate_post_type_enabled ) {
			\add_filter( "bulk_actions-edit-{$duplicate_post_type_enabled}", [ $this, 'register_bulk_action' ] );
		}
	}

	/**
	 * Adds 'Rewrite & Republish' to the bulk action dropdown.
	 *
	 * @param array $bulk_actions The bulk actions array.
	 *
	 * @return array The bulk actions array.
	 */
	public function register_bulk_action( $bulk_actions ) {
		$is_draft_or_trash = isset( $_REQUEST['post_status'] ) && \in_array( $_REQUEST['post_status'], [ 'draft', 'trash' ], true );

		if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'clone' ) ) === 1 ) {
			$bulk_actions['duplicate_post_bulk_clone'] = \esc_html__( 'Clone', 'duplicate-post' );
		}

		if ( ! $is_draft_or_trash
			&& \intval( Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) ) === 1 ) {
			$bulk_actions['duplicate_post_bulk_rewrite_republish'] = \esc_html__( 'Rewrite & Republish', 'duplicate-post' );
		}

		return $bulk_actions;
	}
}
PK!�_�<??src/ui/row-actions.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post class to manage the row actions.
 */
class Row_Actions {

	/**
	 * Holds the object to create the action link to duplicate.
	 *
	 * @var Link_Builder
	 */
	protected $link_builder;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Link_Builder       $link_builder       The link builder.
	 * @param Permissions_Helper $permissions_helper The permissions helper.
	 */
	public function __construct( Link_Builder $link_builder, Permissions_Helper $permissions_helper ) {
		$this->link_builder       = $link_builder;
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \intval( Utils::get_option( 'duplicate_post_show_link_in', 'row' ) ) === 0 ) {
			return;
		}

		if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'clone' ) ) === 1 ) {
			\add_filter( 'post_row_actions', [ $this, 'add_clone_action_link' ], 10, 2 );
			\add_filter( 'page_row_actions', [ $this, 'add_clone_action_link' ], 10, 2 );
		}

		if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'new_draft' ) ) === 1 ) {
			\add_filter( 'post_row_actions', [ $this, 'add_new_draft_action_link' ], 10, 2 );
			\add_filter( 'page_row_actions', [ $this, 'add_new_draft_action_link' ], 10, 2 );
		}

		if ( \intval( Utils::get_option( 'duplicate_post_show_link', 'rewrite_republish' ) ) === 1 ) {
			\add_filter( 'post_row_actions', [ $this, 'add_rewrite_and_republish_action_link' ], 10, 2 );
			\add_filter( 'page_row_actions', [ $this, 'add_rewrite_and_republish_action_link' ], 10, 2 );
		}
	}

	/**
	 * Hooks in the `post_row_actions` and `page_row_actions` filters to add a 'Clone' link.
	 *
	 * @param array   $actions The array of actions from the filter.
	 * @param WP_Post $post    The post object.
	 *
	 * @return array The updated array of actions.
	 */
	public function add_clone_action_link( $actions, $post ) {
		if ( ! $post instanceof WP_Post
			|| ! $this->permissions_helper->should_links_be_displayed( $post )
			|| ! \is_array( $actions ) ) {
			return $actions;
		}

		$title = \_draft_or_post_title( $post );

		$actions['clone'] = '<a href="' . $this->link_builder->build_clone_link( $post->ID )
			. '" aria-label="' . \esc_attr(
				/* translators: %s: Post title. */
				\sprintf( \__( 'Clone &#8220;%s&#8221;', 'duplicate-post' ), $title )
			) . '">'
			. \esc_html_x( 'Clone', 'verb', 'duplicate-post' ) . '</a>';

		return $actions;
	}

	/**
	 * Hooks in the `post_row_actions` and `page_row_actions` filters to add a 'New Draft' link.
	 *
	 * @param array   $actions The array of actions from the filter.
	 * @param WP_Post $post    The post object.
	 *
	 * @return array The updated array of actions.
	 */
	public function add_new_draft_action_link( $actions, $post ) {
		if ( ! $post instanceof WP_Post
			|| ! $this->permissions_helper->should_links_be_displayed( $post )
			|| ! \is_array( $actions ) ) {
			return $actions;
		}

		$title = \_draft_or_post_title( $post );

		$actions['edit_as_new_draft'] = '<a href="' . $this->link_builder->build_new_draft_link( $post->ID )
			. '" aria-label="' . \esc_attr(
				/* translators: %s: Post title. */
				\sprintf( \__( 'New draft of &#8220;%s&#8221;', 'duplicate-post' ), $title )
			) . '">'
			. \esc_html__( 'New Draft', 'duplicate-post' )
			. '</a>';

		return $actions;
	}

	/**
	 * Hooks in the `post_row_actions` and `page_row_actions` filters to add a 'Rewrite & Republish' link.
	 *
	 * @param array   $actions The array of actions from the filter.
	 * @param WP_Post $post    The post object.
	 *
	 * @return array The updated array of actions.
	 */
	public function add_rewrite_and_republish_action_link( $actions, $post ) {
		if (
			! $post instanceof WP_Post
			|| ! $this->permissions_helper->should_rewrite_and_republish_be_allowed( $post )
			|| ! $this->permissions_helper->should_links_be_displayed( $post )
			|| ! \is_array( $actions )
		) {
			return $actions;
		}

		$title = \_draft_or_post_title( $post );

		$actions['rewrite'] = '<a href="' . $this->link_builder->build_rewrite_and_republish_link( $post->ID )
			. '" aria-label="' . \esc_attr(
				/* translators: %s: Post title. */
				\sprintf( \__( 'Rewrite & Republish &#8220;%s&#8221;', 'duplicate-post' ), $title )
			) . '">'
			. \esc_html_x( 'Rewrite & Republish', 'verb', 'duplicate-post' ) . '</a>';

		return $actions;
	}
}
PK!
�?:ffsrc/ui/newsletter.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\UI;

/**
 * Newsletter class.
 */
class Newsletter {

	/**
	 * Renders the newsletter signup form.
	 *
	 * @return string The HTML of the newsletter signup form (escaped).
	 */
	public static function newsletter_signup_form() {

		$newsletter_form_response = self::newsletter_handle_form();


		$copy = \sprintf(
		/* translators: 1: Yoast */
			\esc_html__(
				'If you want to stay up to date about all the exciting developments around Duplicate Post, subscribe to the %1$s newsletter!',
				'duplicate-post'
			),
			'Yoast'
		);

		$email_label = \esc_html__( 'Email address', 'duplicate-post' );

		$copy_privacy_policy = \sprintf(
			/* translators: %1$s and %2$s are replaced by opening and closing anchor tags. */
			\esc_html__(
				'Yoast respects your privacy. Read %1$sour privacy policy%2$s on how we handle your personal information.',
				'duplicate-post'
			),
			'<a href="https://yoa.st/4jf" target="_blank">',
			'</a>'
		);

		$response_html = '';
		if ( \is_array( $newsletter_form_response ) ) {
			$response_status  = $newsletter_form_response['status'];
			$response_message = $newsletter_form_response['message'];

			$response_html = '<div class="newsletter-response-' . $response_status . ' clear" id="newsletter-response" style="margin-top: 6px;">' . $response_message . '</div>';
		}

		$html = '
		<!-- Begin Newsletter Signup Form -->
		<form method="post" id="newsletter-subscribe-form" name="newsletter-subscribe-form" novalidate>
		' . \wp_nonce_field( 'newsletter', 'newsletter_nonce' ) . '
		<p>' . $copy . '</p>
		<div class="newsletter-field-group" style="display: flex; flex-direction: column">
			<label for="newsletter-email" style="margin: 0 0 4px 0;"><strong>' . $email_label . '</strong></label>
			<div>
				<input type="email" value="" name="EMAIL" class="required email" id="newsletter-email" style="margin-right: 4px;">
				<input type="submit" value="' . \esc_attr__( 'Subscribe', 'duplicate-post' ) . '" name="subscribe" id="newsletter-subscribe" class="button">
			</div>
			<p style="font-size: 10px;">' . $copy_privacy_policy . '</p>
		</div>
		' . $response_html . '
		</form>
		<!--End Newsletter Signup Form-->
		';

		return $html;
	}

	/**
	 * Handles and validates Newsletter form.
	 *
	 * @return array|null
	 */
	private static function newsletter_handle_form() {

		//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Already sanitized.
		if ( isset( $_POST['newsletter_nonce'] ) && ! \wp_verify_nonce( \wp_unslash( $_POST['newsletter_nonce'] ), 'newsletter' ) ) {
			return [
				'status'    => 'error',
				'message'   => \esc_html__( 'Something went wrong. Please try again later.', 'duplicate-post' ),
			];
		}

		$email = null;
		if ( isset( $_POST['EMAIL'] ) ) {
			$email = \sanitize_email( \wp_unslash( $_POST['EMAIL'] ) );
		}

		if ( $email === null ) {
			return null;
		}

		if ( ! \is_email( $email ) ) {
			return [
				'status'    => 'error',
				'message'   => \esc_html__( 'Please enter valid e-mail address.', 'duplicate-post' ),
			];
		}

		return self::newsletter_subscribe_to_mailblue( $email );
	}

	/**
	 * Handles subscription request and provides feedback response.
	 *
	 * @param string $email Subscriber email.
	 *
	 * @return array Feedback response.
	 */
	private static function newsletter_subscribe_to_mailblue( $email ) {
		$response = \wp_remote_post(
			'https://my.yoast.com/api/Mailing-list/subscribe',
			[
				'method'      => 'POST',
				'body'        => [
					'customerDetails' => [
						'email'     => $email,
						'firstName' => '',
					],
					'list'            => 'Yoast newsletter',
				],
			]
		);

		$wp_remote_retrieve_response_code = \wp_remote_retrieve_response_code( $response );

		if ( $wp_remote_retrieve_response_code <= 200 || $wp_remote_retrieve_response_code >= 300 ) {
			return [
				'status'    => 'error',
				'message'   => \esc_html__( 'Something went wrong. Please try again later.', 'duplicate-post' ),
			];
		}

		return [
			'status'    => 'success',
			'message'   => \esc_html__( 'You have successfully subscribed to the newsletter. Please check your inbox.', 'duplicate-post' ),
		];
	}
}
PK!��sSsrc/permissions-helper.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

use WP_Post;

/**
 * Permissions helper for Duplicate Post.
 *
 * @since 4.0
 */
class Permissions_Helper {

	/**
	 * Returns the array of the enabled post types.
	 *
	 * @return array The array of post types.
	 */
	public function get_enabled_post_types() {
		$enabled_post_types = \get_option( 'duplicate_post_types_enabled', [ 'post', 'page' ] );
		if ( ! \is_array( $enabled_post_types ) ) {
			$enabled_post_types = [ $enabled_post_types ];
		}

		if ( Utils::is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
			$enabled_post_types = \array_diff( $enabled_post_types, [ 'product' ] );
		}

		/**
		 * Filters the list of post types for which the plugin is enabled.
		 *
		 * @param array $enabled_post_types The array of post type names for which the plugin is enabled.
		 *
		 * @return array The filtered array of post types names.
		 */
		return \apply_filters( 'duplicate_post_enabled_post_types', $enabled_post_types );
	}

	/**
	 * Determines if post type is enabled to be copied.
	 *
	 * @param string $post_type The post type to check.
	 *
	 * @return bool Whether the post type is enabled to be copied.
	 */
	public function is_post_type_enabled( $post_type ) {
		return \in_array( $post_type, $this->get_enabled_post_types(), true );
	}

	/**
	 * Determines if the current user can copy posts.
	 *
	 * @return bool Whether the current user can copy posts.
	 */
	public function is_current_user_allowed_to_copy() {
		return \current_user_can( 'copy_posts' );
	}

	/**
	 * Determines if the post is a copy intended for Rewrite & Republish.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the post is a copy intended for Rewrite & Republish.
	 */
	public function is_rewrite_and_republish_copy( WP_Post $post ) {
		return ( \intval( \get_post_meta( $post->ID, '_dp_is_rewrite_republish_copy', true ) ) === 1 );
	}

	/**
	 * Gets the Rewrite & Republish copy ID for the passed post.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return int The Rewrite & Republish copy ID.
	 */
	public function get_rewrite_and_republish_copy_id( WP_Post $post ) {
		return \get_post_meta( $post->ID, '_dp_has_rewrite_republish_copy', true );
	}

	/**
	 * Gets the copy post object for the passed post.
	 *
	 * @param WP_Post $post The post to get the copy for.
	 *
	 * @return WP_Post|null The copy's post object or null if it doesn't exist.
	 */
	public function get_rewrite_and_republish_copy( WP_Post $post ) {
		$copy_id = $this->get_rewrite_and_republish_copy_id( $post );

		if ( empty( $copy_id ) ) {
			return null;
		}

		return \get_post( $copy_id );
	}

	/**
	 * Determines if the post has a copy intended for Rewrite & Republish.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the post has a copy intended for Rewrite & Republish.
	 */
	public function has_rewrite_and_republish_copy( WP_Post $post ) {
		return ( ! empty( $this->get_rewrite_and_republish_copy_id( $post ) ) );
	}

	/**
	 * Determines if the post has a copy intended for Rewrite & Republish which is scheduled to be published.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool|WP_Post The scheduled copy if present, false if the post has no scheduled copy.
	 */
	public function has_scheduled_rewrite_and_republish_copy( WP_Post $post ) {
		$copy = $this->get_rewrite_and_republish_copy( $post );

		if ( ! empty( $copy ) && $copy->post_status === 'future' ) {
			return $copy;
		}

		return false;
	}

	/**
	 * Determines whether the current screen is an edit post screen.
	 *
	 * @return bool Whether or not the current screen is editing an existing post.
	 */
	public function is_edit_post_screen() {
		if ( ! \is_admin() ) {
			return false;
		}

		$current_screen = \get_current_screen();

		return $current_screen->base === 'post' && $current_screen->action !== 'add';
	}

	/**
	 * Determines whether the current screen is an new post screen.
	 *
	 * @return bool Whether or not the current screen is editing an new post.
	 */
	public function is_new_post_screen() {
		if ( ! \is_admin() ) {
			return false;
		}

		$current_screen = \get_current_screen();

		return $current_screen->base === 'post' && $current_screen->action === 'add';
	}

	/**
	 * Determines if we are currently editing a post with Classic editor.
	 *
	 * @return bool Whether we are currently editing a post with Classic editor.
	 */
	public function is_classic_editor() {
		if ( ! $this->is_edit_post_screen() && ! $this->is_new_post_screen() ) {
			return false;
		}

		$screen = \get_current_screen();
		if ( $screen->is_block_editor() ) {
			return false;
		}

		return true;
	}

	/**
	 * Determines if the original post has changed since the creation of the copy.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the original post has changed since the creation of the copy.
	 */
	public function has_original_changed( WP_Post $post ) {
		if ( ! $this->is_rewrite_and_republish_copy( $post ) ) {
			return false;
		}

		$original               = Utils::get_original( $post );
		$copy_creation_date_gmt = \get_post_meta( $post->ID, '_dp_creation_date_gmt', true );

		if ( $original && $copy_creation_date_gmt ) {
			if ( \strtotime( $original->post_modified_gmt ) > \strtotime( $copy_creation_date_gmt ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Determines if duplicate links for the post can be displayed.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the links can be displayed.
	 */
	public function should_links_be_displayed( WP_Post $post ) {
		/**
		 * Filter allowing displaying duplicate post links for current post.
		 *
		 * @param bool    $display_links Whether the duplicate links will be displayed.
		 * @param WP_Post $post          The post object.
		 *
		 * @return bool Whether or not to display the duplicate post links.
		 */
		$display_links = \apply_filters( 'duplicate_post_show_link', $this->is_current_user_allowed_to_copy() && $this->is_post_type_enabled( $post->post_type ), $post );

		return ! $this->is_rewrite_and_republish_copy( $post ) && $display_links;
	}

	/**
	 * Determines if the Rewrite & Republish link for the post should be displayed.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the links should be displayed.
	 */
	public function should_rewrite_and_republish_be_allowed( WP_Post $post ) {
		return $post->post_status === 'publish'
			&& ! $this->is_rewrite_and_republish_copy( $post )
			&& ! $this->has_rewrite_and_republish_copy( $post );
	}

	/**
	 * Determines whether the passed post type is public and shows an admin bar.
	 *
	 * @param string $post_type The post_type to copy.
	 *
	 * @return bool Whether or not the post can be copied to a new draft.
	 */
	public function post_type_has_admin_bar( $post_type ) {
		$post_type_object = \get_post_type_object( $post_type );

		if ( empty( $post_type_object ) ) {
			return false;
		}

		return $post_type_object->public && $post_type_object->show_in_admin_bar;
	}

	/**
	 * Determines whether a Rewrite & Republish copy can be republished.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the Rewrite & Republish copy can be republished.
	 */
	public function is_copy_allowed_to_be_republished( WP_Post $post ) {
		return \in_array( $post->post_status, [ 'dp-rewrite-republish', 'private' ], true );
	}

	/**
	 * Determines if the post has a trashed copy intended for Rewrite & Republish.
	 *
	 * @param WP_Post $post The post object.
	 *
	 * @return bool Whether the post has a trashed copy intended for Rewrite & Republish.
	 */
	public function has_trashed_rewrite_and_republish_copy( WP_Post $post ) {
		$copy_id = \get_post_meta( $post->ID, '_dp_has_rewrite_republish_copy', true );

		if ( ! $copy_id ) {
			return false;
		}

		$copy = \get_post( $copy_id );

		return ( $copy && $copy->post_status === 'trash' );
	}
}
PK!!tA��
src/utils.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

use WP_Post;

/**
 * Utility methods for Duplicate Post.
 *
 * @since 4.0
 */
class Utils {

	/**
	 * Flattens a version number for use in a filename.
	 *
	 * @param string $version The original version number.
	 *
	 * @return string The flattened version number.
	 */
	public static function flatten_version( $version ) {
		$parts = \explode( '.', $version );

		if ( \count( $parts ) === 2 && \preg_match( '/^\d+$/', $parts[1] ) === 1 ) {
			$parts[] = '0';
		}

		return \implode( '', $parts );
	}

	/**
	 * Adds slashes only to strings.
	 *
	 * @param mixed $value Value to slash only if string.
	 *
	 * @return string|mixed
	 */
	public static function addslashes_to_strings_only( $value ) {
		return \is_string( $value ) ? \addslashes( $value ) : $value;
	}

	/**
	 * Replaces faulty core wp_slash().
	 *
	 * Until WP 5.5 wp_slash() recursively added slashes not just to strings in array/objects, leading to errors.
	 *
	 * @param mixed $value What to add slashes to.
	 *
	 * @return mixed
	 */
	public static function recursively_slash_strings( $value ) {
		return \map_deep( $value, [ self::class, 'addslashes_to_strings_only' ] );
	}

	/**
	 * Gets the original post.
	 *
	 * @param int|WP_Post|null $post   Optional. Post ID or Post object.
	 * @param string           $output Optional, default is Object. Either OBJECT, ARRAY_A, or ARRAY_N.
	 *
	 * @return WP_Post|null Post data if successful, null otherwise.
	 */
	public static function get_original( $post = null, $output = \OBJECT ) {
		$post = \get_post( $post );
		if ( ! $post ) {
			return null;
		}

		$original_id = self::get_original_post_id( $post->ID );

		if ( empty( $original_id ) ) {
			return null;
		}

		return \get_post( $original_id, $output );
	}

	/**
	 * Determines if the post has ancestors marked for copy.
	 *
	 * If we are copying children, and the post has already an ancestor marked for copy, we have to filter it out.
	 *
	 * @param WP_Post $post     The post object.
	 * @param array   $post_ids The array of marked post IDs.
	 *
	 * @return bool Whether the post has ancestors marked for copy.
	 */
	public static function has_ancestors_marked( $post, $post_ids ) {
		$ancestors_in_array = 0;
		$parent             = \wp_get_post_parent_id( $post->ID );
		while ( $parent ) {
			if ( \in_array( $parent, $post_ids, true ) ) {
				++$ancestors_in_array;
			}
			$parent = \wp_get_post_parent_id( $parent );
		}
		return ( $ancestors_in_array !== 0 );
	}

	/**
	 * Returns a link to edit, preview or view a post, in accordance to user capabilities.
	 *
	 * @param WP_Post $post Post ID or Post object.
	 *
	 * @return string|null The link to edit, preview or view a post.
	 */
	public static function get_edit_or_view_link( $post ) {
		$post = \get_post( $post );
		if ( ! $post ) {
			return null;
		}

		$can_edit_post    = \current_user_can( 'edit_post', $post->ID );
		$title            = \_draft_or_post_title( $post );
		$post_type_object = \get_post_type_object( $post->post_type );

		if ( $can_edit_post && $post->post_status !== 'trash' ) {
			return \sprintf(
				'<a href="%s" aria-label="%s">%s</a>',
				\esc_url( \get_edit_post_link( $post->ID ) ),
				/* translators: %s: post title */
				\esc_attr( \sprintf( \__( 'Edit &#8220;%s&#8221;', 'duplicate-post' ), $title ) ),
				$title
			);
		}
		elseif ( \is_post_type_viewable( $post_type_object ) ) {
			if ( \in_array( $post->post_status, [ 'pending', 'draft', 'future' ], true ) ) {
				if ( $can_edit_post ) {
					$preview_link = \get_preview_post_link( $post );
					return \sprintf(
						'<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
						\esc_url( $preview_link ),
						/* translators: %s: post title */
						\esc_attr( \sprintf( \__( 'Preview &#8220;%s&#8221;', 'duplicate-post' ), $title ) ),
						$title
					);
				}
			}
			elseif ( $post->post_status !== 'trash' ) {
				return \sprintf(
					'<a href="%s" rel="bookmark" aria-label="%s">%s</a>',
					\esc_url( \get_permalink( $post->ID ) ),
					/* translators: %s: post title */
					\esc_attr( \sprintf( \__( 'View &#8220;%s&#8221;', 'duplicate-post' ), $title ) ),
					$title
				);
			}
		}

		return $title;
	}

	/**
	 * Gets the ID of the original post intended to be rewritten with the copy for Rewrite & Republish.
	 *
	 * @param int $post_id The copy post ID.
	 *
	 * @return int The original post id of a copy for Rewrite & Republish.
	 */
	public static function get_original_post_id( $post_id ) {
		return (int) \get_post_meta( $post_id, '_dp_original', true );
	}

	/**
	 * Gets the registered WordPress roles.
	 *
	 * @codeCoverageIgnore As this is a simple wrapper method for a built-in WordPress method, we don't have to test it.
	 *
	 * @return array The roles.
	 */
	public static function get_roles() {
		global $wp_roles;

		return $wp_roles->get_names();
	}

	/**
	 * Gets the default meta field names to be filtered out.
	 *
	 * @return array The names of the meta fields to filter out by default.
	 */
	public static function get_default_filtered_meta_names() {
		return [
			'_edit_lock',
			'_edit_last',
			'_dp_original',
			'_dp_is_rewrite_republish_copy',
			'_dp_has_rewrite_republish_copy',
			'_dp_has_been_republished',
			'_dp_creation_date_gmt',
		];
	}

	/**
	 * Gets a Duplicate Post option from the database.
	 *
	 * @param string $option The option to get.
	 * @param string $key    The key to retrieve, if the option is an array.
	 *
	 * @return mixed The option.
	 */
	public static function get_option( $option, $key = '' ) {
		$option = \get_option( $option );

		if ( ! \is_array( $option ) || empty( $key ) ) {
			return $option;
		}

		if ( ! \array_key_exists( $key, $option ) ) {
			return '';
		}

		return $option[ $key ];
	}

	/**
	 * Determines if a plugin is active.
	 *
	 * We can't use is_plugin_active because this must work on the frontend too.
	 *
	 * @param string $plugin Path to the plugin file relative to the plugins directory.
	 *
	 * @return bool Whether a plugin is currently active.
	 */
	public static function is_plugin_active( $plugin ) {
		if ( \in_array( $plugin, (array) \get_option( 'active_plugins', [] ), true ) ) {
			return true;
		}

		if ( ! \is_multisite() ) {
			return false;
		}

		$plugins = \get_site_option( 'active_sitewide_plugins' );
		return isset( $plugins[ $plugin ] );
	}
}
PK!ř�$0$0src/post-duplicator.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

use WP_Error;
use WP_Post;

/**
 * Duplicate Post class to create copies.
 *
 * @since 4.0
 */
class Post_Duplicator {

	/**
	 * Returns an array with the default option values.
	 *
	 * @return array The default options values.
	 */
	public function get_default_options() {
		return [
			'copy_title'             => true,
			'copy_date'              => false,
			'copy_status'            => false,
			'copy_name'              => false,
			'copy_excerpt'           => true,
			'copy_content'           => true,
			'copy_thumbnail'         => true,
			'copy_template'          => true,
			'copy_format'            => true,
			'copy_author'            => false,
			'copy_password'          => false,
			'copy_attachments'       => false,
			'copy_children'          => false,
			'copy_comments'          => false,
			'copy_menu_order'        => true,
			'title_prefix'           => '',
			'title_suffix'           => '',
			'increase_menu_order_by' => null,
			'parent_id'              => null,
			'meta_excludelist'       => [],
			'taxonomies_excludelist' => [],
			'use_filters'            => true,
		];
	}

	/**
	 * Creates a copy of a post object, accordingly to an options array.
	 *
	 * @param WP_Post $post    The original post object.
	 * @param array   $options The options overriding the default ones.
	 *
	 * @return int|WP_Error The copy ID, or a WP_Error object on failure.
	 */
	public function create_duplicate( WP_Post $post, array $options = [] ) {
		$defaults = $this->get_default_options();
		$options  = \wp_parse_args( $options, $defaults );

		$title           = '';
		$new_post_status = $post->post_status;
		if ( $post->post_type !== 'attachment' ) {
			$title           = $this->generate_copy_title( $post, $options );
			$new_post_status = $this->generate_copy_status( $post, $options );
		}

		$new_post_author_id = $this->generate_copy_author( $post, $options );

		$menu_order = 0;
		if ( $options['copy_menu_order'] ) {
			$menu_order = $post->menu_order;
		}

		if ( ! empty( $options['increase_menu_order_by'] ) && \is_numeric( $options['increase_menu_order_by'] ) ) {
			$menu_order += \intval( $options['increase_menu_order_by'] );
		}

		$new_post = [
			'post_author'           => $new_post_author_id,
			'post_content'          => ( $options['copy_content'] ) ? $post->post_content : '',
			'post_content_filtered' => ( $options['copy_content'] ) ? $post->post_content_filtered : '',
			'post_title'            => $title,
			'post_excerpt'          => ( $options['copy_excerpt'] ) ? $post->post_excerpt : '',
			'post_status'           => $new_post_status,
			'post_type'             => $post->post_type,
			'comment_status'        => $post->comment_status,
			'ping_status'           => $post->ping_status,
			'post_password'         => ( $options['copy_password'] ) ? $post->post_password : '',
			'post_name'             => ( $options['copy_name'] ) ? $post->post_name : '',
			'post_parent'           => empty( $options['parent_id'] ) ? $post->post_parent : $options['parent_id'],
			'menu_order'            => $menu_order,
			'post_mime_type'        => $post->post_mime_type,
		];

		if ( $options['copy_date'] ) {
			$new_post_date             = $post->post_date;
			$new_post['post_date']     = $new_post_date;
			$new_post['post_date_gmt'] = \get_gmt_from_date( $new_post_date );
			\add_filter( 'wp_insert_post_data', [ $this, 'set_modified' ], 1, 1 );
		}

		if ( $options['use_filters'] ) {
			/**
			 * Filter new post values.
			 *
			 * @param array   $new_post New post values.
			 * @param WP_Post $post     Original post object.
			 *
			 * @return array
			 */
			$new_post = \apply_filters( 'duplicate_post_new_post', $new_post, $post );
		}

		$new_post_id = \wp_insert_post( \wp_slash( $new_post ), true );

		if ( $options['copy_date'] ) {
			\remove_filter( 'wp_insert_post_data', [ $this, 'set_modified' ], 1 );
		}

		if ( ! \is_wp_error( $new_post_id ) ) {
			\delete_post_meta( $new_post_id, '_dp_original' );
			\add_post_meta( $new_post_id, '_dp_original', $post->ID );
		}

		return $new_post_id;
	}

	/**
	 * Modifies the post data to set the modified date to now.
	 *
	 * This is needed for the Block editor when a post is copied with its date,
	 * so that the current publish date is shown instead of "Immediately".
	 *
	 * @param array $data The array of post data.
	 *
	 * @return array The updated array of post data.
	 */
	public function set_modified( $data ) {
		$data['post_modified']     = \current_time( 'mysql' );
		$data['post_modified_gmt'] = \current_time( 'mysql', 1 );

		return $data;
	}

	/**
	 * Wraps the function to create a copy for the Rewrite & Republish feature.
	 *
	 * @param WP_Post $post The original post object.
	 *
	 * @return int|WP_Error The copy ID, or a WP_Error object on failure.
	 */
	public function create_duplicate_for_rewrite_and_republish( WP_Post $post ) {
		$options  = [
			'copy_title'      => true,
			'copy_date'       => true,
			'copy_name'       => false,
			'copy_content'    => true,
			'copy_excerpt'    => true,
			'copy_author'     => true,
			'copy_menu_order' => true,
			'use_filters'     => false,
		];
		$defaults = $this->get_default_options();
		$options  = \wp_parse_args( $options, $defaults );

		$new_post_id = $this->create_duplicate( $post, $options );

		if ( ! \is_wp_error( $new_post_id ) ) {
			$this->copy_post_taxonomies( $new_post_id, $post, $options );
			$this->copy_post_meta_info( $new_post_id, $post, $options );

			\update_post_meta( $new_post_id, '_dp_is_rewrite_republish_copy', 1 );
			\update_post_meta( $post->ID, '_dp_has_rewrite_republish_copy', $new_post_id );
			\update_post_meta( $new_post_id, '_dp_creation_date_gmt', \current_time( 'mysql', 1 ) );
		}

		return $new_post_id;
	}

	/**
	 * Copies the taxonomies of a post to another post.
	 *
	 * @param int     $new_id  New post ID.
	 * @param WP_Post $post    The original post object.
	 * @param array   $options The options array.
	 *
	 * @return void
	 */
	public function copy_post_taxonomies( $new_id, $post, $options ) {
		// Clear default category (added by wp_insert_post).
		\wp_set_object_terms( $new_id, null, 'category' );

		$post_taxonomies = \get_object_taxonomies( $post->post_type );
		// Several plugins just add support to post-formats but don't register post_format taxonomy.
		if ( \post_type_supports( $post->post_type, 'post-formats' ) && ! \in_array( 'post_format', $post_taxonomies, true ) ) {
			$post_taxonomies[] = 'post_format';
		}

		$taxonomies_excludelist = $options['taxonomies_excludelist'];
		if ( ! \is_array( $taxonomies_excludelist ) ) {
			$taxonomies_excludelist = [];
		}

		if ( ! $options['copy_format'] ) {
			$taxonomies_excludelist[] = 'post_format';
		}

		if ( $options['use_filters'] ) {
			/**
			 * Filters the taxonomy excludelist when copying a post.
			 *
			 * @param array $taxonomies_excludelist The taxonomy excludelist from the options.
			 *
			 * @return array
			 */
			$taxonomies_excludelist = \apply_filters( 'duplicate_post_taxonomies_excludelist_filter', $taxonomies_excludelist );
		}

		$post_taxonomies = \array_diff( $post_taxonomies, $taxonomies_excludelist );

		foreach ( $post_taxonomies as $taxonomy ) {
			$post_terms = \wp_get_object_terms( $post->ID, $taxonomy, [ 'orderby' => 'term_order' ] );
			$terms      = [];
			$num_terms  = \count( $post_terms );
			for ( $i = 0; $i < $num_terms; $i++ ) {
				$terms[] = $post_terms[ $i ]->slug;
			}
			\wp_set_object_terms( $new_id, $terms, $taxonomy );
		}
	}

	/**
	 * Copies the meta information of a post to another post.
	 *
	 * @param int     $new_id  The new post ID.
	 * @param WP_Post $post    The original post object.
	 * @param array   $options The options array.
	 *
	 * @return void
	 */
	public function copy_post_meta_info( $new_id, $post, $options ) {
		$post_meta_keys = \get_post_custom_keys( $post->ID );
		if ( empty( $post_meta_keys ) ) {
			return;
		}
		$meta_excludelist = $options['meta_excludelist'];
		if ( ! \is_array( $meta_excludelist ) ) {
			$meta_excludelist = [];
		}
		$meta_excludelist = \array_merge( $meta_excludelist, Utils::get_default_filtered_meta_names() );
		if ( ! $options['copy_template'] ) {
			$meta_excludelist[] = '_wp_page_template';
		}
		if ( ! $options['copy_thumbnail'] ) {
			$meta_excludelist[] = '_thumbnail_id';
		}

		if ( $options['use_filters'] ) {
			/**
			 * Filters the meta fields excludelist when copying a post.
			 *
			 * @param array $meta_excludelist The meta fields excludelist from the options.
			 *
			 * @return array
			 */
			$meta_excludelist = \apply_filters( 'duplicate_post_excludelist_filter', $meta_excludelist );
		}

		$meta_excludelist_string = '(' . \implode( ')|(', $meta_excludelist ) . ')';
		if ( \strpos( $meta_excludelist_string, '*' ) !== false ) {
			$meta_excludelist_string = \str_replace( [ '*' ], [ '[a-zA-Z0-9_]*' ], $meta_excludelist_string );

			$meta_keys = [];
			foreach ( $post_meta_keys as $meta_key ) {
				if ( ! \preg_match( '#^' . $meta_excludelist_string . '$#', $meta_key ) ) {
					$meta_keys[] = $meta_key;
				}
			}
		}
		else {
			$meta_keys = \array_diff( $post_meta_keys, $meta_excludelist );
		}

		if ( $options['use_filters'] ) {
			/**
			 * Filters the list of meta fields names when copying a post.
			 *
			 * @param array $meta_keys The list of meta fields name, with the ones in the excludelist already removed.
			 *
			 * @return array
			 */
			$meta_keys = \apply_filters( 'duplicate_post_meta_keys_filter', $meta_keys );
		}

		foreach ( $meta_keys as $meta_key ) {
			$meta_values = \get_post_custom_values( $meta_key, $post->ID );

			// Clear existing meta data so that add_post_meta() works properly with non-unique keys.
			\delete_post_meta( $new_id, $meta_key );

			foreach ( $meta_values as $meta_value ) {
				$meta_value = \maybe_unserialize( $meta_value );
				\add_post_meta( $new_id, $meta_key, Utils::recursively_slash_strings( $meta_value ) );
			}
		}
	}

	/**
	 * Generates and returns the title for the copy.
	 *
	 * @param WP_Post $post    The original post object.
	 * @param array   $options The options array.
	 *
	 * @return string The calculated title for the copy.
	 */
	public function generate_copy_title( WP_Post $post, array $options ) {
		$prefix = \sanitize_text_field( $options['title_prefix'] );
		$suffix = \sanitize_text_field( $options['title_suffix'] );
		if ( $options['copy_title'] ) {
			$title = $post->post_title;
			if ( ! empty( $prefix ) ) {
				$prefix .= ' ';
			}
			if ( ! empty( $suffix ) ) {
				$suffix = ' ' . $suffix;
			}
		}
		else {
			$title = '';
		}
		return \trim( $prefix . $title . $suffix );
	}

	/**
	 * Generates and returns the status for the copy.
	 *
	 * @param WP_Post $post    The original post object.
	 * @param array   $options The options array.
	 *
	 * @return string The calculated status for the copy.
	 */
	public function generate_copy_status( WP_Post $post, array $options ) {
		$new_post_status = 'draft';

		if ( $options['copy_status'] ) {
			$new_post_status = $post->post_status;
			if ( $new_post_status === 'publish' || $new_post_status === 'future' ) {
				// Check if the user has the right capability.
				if ( \is_post_type_hierarchical( $post->post_type ) ) {
					if ( ! \current_user_can( 'publish_pages' ) ) {
						$new_post_status = 'pending';
					}
				}
				elseif ( ! \current_user_can( 'publish_posts' ) ) {
					$new_post_status = 'pending';
				}
			}
		}

		return $new_post_status;
	}

	/**
	 * Generates and returns the author ID for the copy.
	 *
	 * @param WP_Post $post    The original post object.
	 * @param array   $options The options array.
	 *
	 * @return int|string The calculated author ID for the copy.
	 */
	public function generate_copy_author( WP_Post $post, array $options ) {
		$new_post_author    = \wp_get_current_user();
		$new_post_author_id = $new_post_author->ID;
		if ( $options['copy_author'] ) {
			// Check if the user has the right capability.
			if ( \is_post_type_hierarchical( $post->post_type ) ) {
				if ( \current_user_can( 'edit_others_pages' ) ) {
					$new_post_author_id = $post->post_author;
				}
			}
			elseif ( \current_user_can( 'edit_others_posts' ) ) {
				$new_post_author_id = $post->post_author;
			}
		}

		return $new_post_author_id;
	}
}
PK!|L� " "src/admin/views/options.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Admin\Views;

if ( ! \defined( 'DUPLICATE_POST_CURRENT_VERSION' ) ) {
	\header( 'Status: 403 Forbidden' );
	\header( 'HTTP/1.1 403 Forbidden' );
	exit();
}

?>
<div class="wrap">
	<h1>
		<?php \esc_html_e( 'Duplicate Post Options', 'duplicate-post' ); ?>
	</h1>

	<form id="duplicate_post_settings_form" method="post" action="options.php" style="clear: both">
		<?php \settings_fields( 'duplicate_post_group' ); ?>

		<header role="tablist" aria-label="<?php \esc_attr_e( 'Settings sections', 'duplicate-post' ); ?>"
				class="nav-tab-wrapper">
			<button
					type="button"
					role="tab"
					class="nav-tab nav-tab-active"
					aria-selected="true"
					aria-controls="what-tab"
					id="what"><?php \esc_html_e( 'What to copy', 'duplicate-post' ); ?>
			</button>
			<button
					type="button"
					role="tab"
					class="nav-tab"
					aria-selected="false"
					aria-controls="who-tab"
					id="who"
					tabindex="-1"><?php \esc_html_e( 'Permissions', 'duplicate-post' ); ?>
			</button>
			<button
					type="button"
					role="tab"
					class="nav-tab"
					aria-selected="false"
					aria-controls="where-tab"
					id="where"
					tabindex="-1"><?php \esc_html_e( 'Display', 'duplicate-post' ); ?>
			</button>
		</header>

		<section
				tabindex="0"
				role="tabpanel"
				id="what-tab"
				aria-labelledby="what">
			<h2 class="hide-if-js"><?php \esc_html_e( 'What to copy', 'duplicate-post' ); ?></h2>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><?php \esc_html_e( 'Post/page elements to copy', 'duplicate-post' ); ?></th>
					<td>
						<fieldset>
							<legend class="screen-reader-text"><?php \esc_html_e( 'Post/page elements to copy', 'duplicate-post' ); ?></legend>
							<?php
							// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
							echo $this->generate_tab_inputs( 'what-to-copy', 'elements-to-copy' );
							?>
						</fieldset>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="duplicate-post-title-prefix"><?php \esc_html_e( 'Title prefix', 'duplicate-post' ); ?></label>
					</th>
					<td>
						<?php
						// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
						echo $this->generate_input( 'duplicate_post_title_prefix' );
						?>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="duplicate-post-title-suffix"><?php \esc_html_e( 'Title suffix', 'duplicate-post' ); ?></label>
					</th>
					<td>
						<?php
						// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
						echo $this->generate_input( 'duplicate_post_title_suffix' );
						?>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="duplicate-post-increase-menu-order-by"><?php \esc_html_e( 'Increase menu order by', 'duplicate-post' ); ?></label>
					</th>
					<td>
						<?php
						// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
						echo $this->generate_input( 'duplicate_post_increase_menu_order_by' );
						?>

					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="duplicate-post-blacklist"><?php \esc_html_e( 'Do not copy these fields', 'duplicate-post' ); ?></label>
					</th>
					<td id="textfield">
						<?php
						// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
						echo $this->generate_input( 'duplicate_post_blacklist' );
						?>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<?php \esc_html_e( 'Do not copy these taxonomies', 'duplicate-post' ); ?><br/>
					</th>
					<td>
						<fieldset>
							<legend class="screen-reader-text"><?php \esc_html_e( 'Do not copy these taxonomies', 'duplicate-post' ); ?></legend>
							<?php
							// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
							echo $this->generate_input( 'duplicate_post_taxonomies_blacklist' );
							?>
							<button type="button" class="button-link hide-if-no-js toggle-private-taxonomies"
									aria-expanded="false">
								<?php \esc_html_e( 'Show/hide private taxonomies', 'duplicate-post' ); ?>
							</button>
						</fieldset>
					</td>
				</tr>
			</table>
		</section>
		<section
				tabindex="0"
				role="tabpanel"
				id="who-tab"
				aria-labelledby="who"
				hidden="hidden">
			<h2 class="hide-if-js"><?php \esc_html_e( 'Permissions', 'duplicate-post' ); ?></h2>
			<table class="form-table" role="presentation">
				<?php if ( \current_user_can( 'promote_users' ) ) { ?>
					<tr>
						<th scope="row"><?php \esc_html_e( 'Roles allowed to copy', 'duplicate-post' ); ?></th>
						<td>
							<fieldset>
								<legend class="screen-reader-text"><?php \esc_html_e( 'Roles allowed to copy', 'duplicate-post' ); ?></legend>
								<?php
								// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
								echo $this->generate_input( 'duplicate_post_roles' );
								?>
								<p>
									<?php \esc_html_e( 'Warning: users will be able to copy, rewrite and republish all posts, even those of other users.', 'duplicate-post' ); ?>
									<br/>
									<?php \esc_html_e( 'Passwords and contents of password-protected posts may become visible to undesired users and visitors.', 'duplicate-post' ); ?>
								</p>
							</fieldset>
						</td>
					</tr>
				<?php } ?>
				<tr>
					<th scope="row"><?php \esc_html_e( 'Enable for these post types', 'duplicate-post' ); ?>
					</th>
					<td>
						<fieldset>
							<legend class="screen-reader-text"><?php \esc_html_e( 'Enable for these post types', 'duplicate-post' ); ?></legend>
							<?php
										// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
							echo $this->generate_input( 'duplicate_post_types_enabled' );
							?>
							<p>
								<?php \esc_html_e( 'Select the post types you want the plugin to be enabled for.', 'duplicate-post' ); ?>
								<br/>
								<?php \esc_html_e( 'Whether the links are displayed for custom post types registered by themes or plugins depends on their use of standard WordPress UI elements.', 'duplicate-post' ); ?>
							</p>
						</fieldset>
					</td>
				</tr>
			</table>
		</section>
		<section
				tabindex="0"
				role="tabpanel"
				id="where-tab"
				aria-labelledby="where"
				hidden="hidden">
			<h2 class="hide-if-js"><?php \esc_html_e( 'Display', 'duplicate-post' ); ?></h2>
			<table class="form-table" role="presentation">
				<tr>
					<th scope="row"><?php \esc_html_e( 'Show these links', 'duplicate-post' ); ?></th>
					<td>
						<fieldset>
							<?php
							// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
							echo $this->generate_tab_inputs( 'display', 'show-links' );
							?>
						</fieldset>
					</td>
				</tr>

				<tr>
					<th scope="row"><?php \esc_html_e( 'Show links in', 'duplicate-post' ); ?></th>
					<td>
						<fieldset>
							<?php
							// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
							echo $this->generate_tab_inputs( 'display', 'show-links-in' );
							?>
						</fieldset>
						<p>
							<?php \esc_html_e( 'Whether the links are displayed for custom post types registered by themes or plugins depends on their use of standard WordPress UI elements.', 'duplicate-post' ); ?>
							<br/>
							<?php
							\printf(
								/* translators: 1: Code start tag, 2: Code closing tag, 3: Link start tag to the template tag documentation, 4: Link closing tag. */
								\esc_html__( 'You can also use the template tag %1$sduplicate_post_clone_post_link( $link, $before, $after, $id )%2$s. %3$sMore info on the template tag%4$s.', 'duplicate-post' ),
								'<code>',
								'</code>',
								'<a href="' . \esc_url( 'https://developer.yoast.com/duplicate-post/functions-template-tags#duplicate_post_clone_post_link' ) . '">',
								'</a>'
							);
							?>
						</p>
					</td>
				</tr>
				<tr>
					<th scope="row"><?php \esc_html_e( 'Show original item:', 'duplicate-post' ); ?></th>
					<td>
						<?php
						// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
						echo $this->generate_tab_inputs( 'display', 'show-original' );
						?>
					</td>
				</tr>
				<tr>
					<th scope="row"><?php \esc_html_e( 'Welcome notice', 'duplicate-post' ); ?></th>
					<td>
						<?php
						// phpcs:ignore WordPress.Security.EscapeOutput -- Already escapes correctly.
						echo $this->generate_input( 'duplicate_post_show_notice' );
						?>
					</td>
				</tr>
			</table>
		</section>
		<p class="submit">
			<input type="submit" class="button button-primary" value="<?php \esc_html_e( 'Save changes', 'duplicate-post' ); ?>"/>
		</p>
	</form>
</div>
PK!�K&��src/admin/options-inputs.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Admin;

/**
 * Class Options_Inputs.
 */
class Options_Inputs {

	/**
	 * Creates a basic input based on the passed parameters.
	 *
	 * @param string $type       The type of input.
	 * @param string $name       The name of the input.
	 * @param string $value      The value of the input.
	 * @param string $id         The ID of the input.
	 * @param string $attributes The additional attributes to use. Optional.
	 *
	 * @return string The input's HTML output.
	 */
	protected function input( $type, $name, $value, $id, $attributes = '' ) {
		return \sprintf(
			'<input type="%s" name="%s" id="%s" value="%s" %s />',
			\esc_attr( $type ),
			\esc_attr( $name ),
			\esc_attr( $id ),
			\esc_attr( $value ),
			$attributes
		);
	}

	/**
	 * Creates a checkbox input.
	 *
	 * @param string $name    The name of the checkbox.
	 * @param string $value   The value of the checkbox.
	 * @param string $id      The ID of the checkbox.
	 * @param bool   $checked Whether or not the checkbox should be checked.
	 *
	 * @return string The checkbox' HTML output.
	 */
	public function checkbox( $name, $value, $id, $checked = false ) {
		$checked = \checked( $checked, true, false );

		return $this->input( 'checkbox', $name, $value, $id, $checked );
	}

	/**
	 * Creates a text field input.
	 *
	 * @param string $name  The name of the text field.
	 * @param string $value The value of the text field.
	 * @param string $id    The ID of the text field.
	 *
	 * @return string The text field's HTML output.
	 */
	public function text( $name, $value, $id ) {
		return $this->input( 'text', $name, $value, $id );
	}

	/**
	 * Creates a number input.
	 *
	 * @param string $name  The name of the number input.
	 * @param string $value The value of the number input.
	 * @param string $id    The ID of the number input.
	 *
	 * @return string The number input's HTML output.
	 */
	public function number( $name, $value, $id ) {
		return $this->input( 'number', $name, $value, $id, 'min="0" step="1"' );
	}
}
PK!�4W(W(src/admin/options.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Admin;

/**
 * Options class.
 *
 * @since 4.0
 */
class Options {

	/**
	 * Registers the settings.
	 *
	 * @return void
	 */
	public function register_settings() {
		foreach ( \array_keys( $this->get_options() ) as $option ) {
			\register_setting( 'duplicate_post_group', $option );
		}
	}

	/**
	 * Gets the options for the specified tab.
	 *
	 * Also allows filtering on a particular fieldset.
	 *
	 * @param string $tab      The tab to get the options for.
	 * @param string $fieldset The fieldset to get the options for. Optional.
	 *
	 * @return array The options for the specified tab.
	 */
	public function get_options_for_tab( $tab, $fieldset = '' ) {
		$options = $this->get_options();

		$options = \array_filter(
			$options,
			static function ( $option ) use ( $tab ) {
				return \array_key_exists( 'tab', $option ) && $option['tab'] === $tab;
			}
		);

		if ( empty( $options ) ) {
			return [];
		}

		// If a fieldset is specified, filter out the corresponding options.
		if ( ! empty( $fieldset ) ) {
			$options = \array_filter(
				$options,
				static function ( $option ) use ( $fieldset ) {
					return \array_key_exists( 'fieldset', $option ) && $option['fieldset'] === $fieldset;
				}
			);
		}

		return $options;
	}

	/**
	 * Gets an option from the options array, based on its name.
	 *
	 * @param string $name The name of the option to retrieve.
	 *
	 * @return array The option. Empty array if it does not exist.
	 */
	public function get_option( $name ) {
		$options = $this->get_options();

		return \array_key_exists( $name, $options ) ? [ $name => $options[ $name ] ] : [];
	}

	/**
	 * Gets the list of registered options.
	 *
	 * @codeCoverageIgnore
	 *
	 * @return array The options.
	 */
	public function get_options() {
		return [
			'duplicate_post_copytitle'                    => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Title', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copydate'                     => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Date', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copystatus'                   => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Status', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copyslug'                     => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Slug', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copyexcerpt'                  => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Excerpt', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copycontent'                  => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Content', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copythumbnail'                => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Featured Image', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copytemplate'                 => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Template', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copyformat'                   => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Post format', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copyauthor'                   => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Author', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copypassword'                 => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Password', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copyattachments'              => [
				'tab'         => 'what-to-copy',
				'fieldset'    => 'elements-to-copy',
				'type'        => 'checkbox',
				'label'       => \__( 'Attachments', 'duplicate-post' ),
				'value'       => 1,
				'description' => \__( 'you probably want this unchecked, unless you have very special requirements', 'duplicate-post' ),
			],
			'duplicate_post_copychildren'                 => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Children', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_copycomments'                 => [
				'tab'         => 'what-to-copy',
				'fieldset'    => 'elements-to-copy',
				'type'        => 'checkbox',
				'label'       => \__( 'Comments', 'duplicate-post' ),
				'value'       => 1,
				'description' => \__( 'except pingbacks and trackbacks', 'duplicate-post' ),
			],
			'duplicate_post_copymenuorder'                => [
				'tab'      => 'what-to-copy',
				'fieldset' => 'elements-to-copy',
				'type'     => 'checkbox',
				'label'    => \__( 'Menu order', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_title_prefix'                 => [
				'tab'         => 'what-to-copy',
				'type'        => 'text',
				'label'       => \__( 'Title prefix', 'duplicate-post' ),
				'value'       => \get_option( 'duplicate_post_title_prefix' ),
				'description' => [ \__( 'Prefix to be added before the title, e.g. "Copy of" (blank for no prefix)', 'duplicate-post' ) ],
			],
			'duplicate_post_title_suffix'                 => [
				'tab'         => 'what-to-copy',
				'type'        => 'text',
				'label'       => \__( 'Title suffix', 'duplicate-post' ),
				'value'       => \get_option( 'duplicate_post_title_suffix' ),
				'description' => [ \__( 'Suffix to be added after the title, e.g. "(dup)" (blank for no suffix)', 'duplicate-post' ) ],
			],
			'duplicate_post_increase_menu_order_by'       => [
				'tab'         => 'what-to-copy',
				'type'        => 'number',
				'label'       => \__( 'Increase menu order by', 'duplicate-post' ),
				'value'       => \get_option( 'duplicate_post_increase_menu_order_by' ),
				'description' => [ \__( 'Add this number to the original menu order (blank or zero to retain the value)', 'duplicate-post' ) ],
			],
			'duplicate_post_blacklist'                    => [
				'tab'         => 'what-to-copy',
				'type'        => 'text',
				'label'       => \__( 'Do not copy these fields', 'duplicate-post' ),
				'value'       => \get_option( 'duplicate_post_blacklist' ),
				'description' => [
					\__( 'Comma-separated list of meta fields that must not be copied.', 'duplicate-post' ),
					\__( 'You can use * to match zero or more alphanumeric characters or underscores: e.g. field*', 'duplicate-post' ),
				],
			],
			'duplicate_post_taxonomies_blacklist'         => [
				'tab'      => 'what-to-copy',
				'callback' => 'generate_taxonomy_exclusion_list',
			],
			'duplicate_post_roles'                        => [
				'tab'      => 'permissions',
				'callback' => 'generate_roles_permission_list',
			],
			'duplicate_post_types_enabled'                => [
				'tab'      => 'permissions',
				'callback' => 'generate_post_types_list',
			],
			'duplicate_post_show_original_meta_box'       => [
				'tab'         => 'display',
				'fieldset'    => 'show-original',
				'type'        => 'checkbox',
				'label'       => \__( 'In a metabox in the Edit screen', 'duplicate-post' ),
				'value'       => 1,
				'description' => [
					\__( "You'll also be able to delete the reference to the original item with a checkbox", 'duplicate-post' ),
				],
			],
			'duplicate_post_show_original_column'         => [
				'tab'         => 'display',
				'fieldset'    => 'show-original',
				'type'        => 'checkbox',
				'label'       => \__( 'In a column in the Post list', 'duplicate-post' ),
				'value'       => 1,
				'description' => [
					\__( "You'll also be able to delete the reference to the original item with a checkbox in Quick Edit", 'duplicate-post' ),
				],
			],
			'duplicate_post_show_original_in_post_states' => [
				'tab'      => 'display',
				'fieldset' => 'show-original',
				'type'     => 'checkbox',
				'label'    => \__( 'After the title in the Post list', 'duplicate-post' ),
				'value'    => 1,
			],
			'duplicate_post_show_notice'                  => [
				'tab'   => 'display',
				'type'  => 'checkbox',
				'label' => \__( 'Show welcome notice', 'duplicate-post' ),
				'value' => 1,
			],
			'duplicate_post_show_link'                    => [
				'tab'         => 'display',
				'fieldset'    => 'show-links',
				'sub_options' => [
					'new_draft'         => [
						'type'  => 'checkbox',
						'label' => \__( 'New Draft', 'duplicate-post' ),
						'value' => 1,
					],
					'clone'             => [
						'type'  => 'checkbox',
						'label' => \__( 'Clone', 'duplicate-post' ),
						'value' => 1,
					],
					'rewrite_republish' => [
						'type'  => 'checkbox',
						'label' => \__( 'Rewrite & Republish', 'duplicate-post' ),
						'value' => 1,
					],
				],
			],
			'duplicate_post_show_link_in' => [
				'tab'         => 'display',
				'fieldset'    => 'show-links-in',
				'sub_options' => [
					'row'         => [
						'type'     => 'checkbox',
						'label'    => \__( 'Post list', 'duplicate-post' ),
						'value'    => 1,
					],
					'adminbar' => [
						'type'        => 'checkbox',
						'label'       => \__( 'Admin bar', 'duplicate-post' ),
						'value'       => 1,
					],
					'submitbox' => [
						'type'  => 'checkbox',
						'label' => \__( 'Edit screen', 'duplicate-post' ),
						'value' => 1,
					],
					'bulkactions' => [
						'type'  => 'checkbox',
						'label' => \__( 'Bulk Actions', 'duplicate-post' ),
						'value' => 1,
					],
				],
			],
		];
	}
}
PK!�N
�``src/admin/options-page.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Admin;

use Yoast\WP\Duplicate_Post\UI\Asset_Manager;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Class Options_Page.
 */
class Options_Page {

	/**
	 * The Options instance.
	 *
	 * @var Options
	 */
	protected $options;

	/**
	 * The Options_Form_Generator instance.
	 *
	 * @var Options_Form_Generator
	 */
	protected $generator;

	/**
	 * Holds the asset manager.
	 *
	 * @var Asset_Manager
	 */
	protected $asset_manager;

	/**
	 * Options_Page constructor.
	 *
	 * @param Options                $options       The Options class instance.
	 * @param Options_Form_Generator $generator     The Options_Form_Generator class instance.
	 * @param Asset_Manager          $asset_manager The Asset_Manager class instance.
	 */
	public function __construct( Options $options, Options_Form_Generator $generator, Asset_Manager $asset_manager ) {
		$this->options       = $options;
		$this->generator     = $generator;
		$this->asset_manager = $asset_manager;
	}

	/**
	 * Registers the necessary hooks.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \is_admin() ) {
			\add_action( 'admin_menu', [ $this, 'register_menu' ] );
			\add_action( 'admin_init', [ $this->options, 'register_settings' ] );
		}
	}

	/**
	 * Enqueues the assets.
	 *
	 * @return void
	 */
	public function enqueue_assets() {
		$this->asset_manager->enqueue_options_styles();
		$this->asset_manager->enqueue_options_script();
	}

	/**
	 * Registers the menu item.
	 *
	 * @return void
	 */
	public function register_menu() {
		$page_hook = \add_options_page(
			\__( 'Duplicate Post Options', 'duplicate-post' ),
			\__( 'Duplicate Post', 'duplicate-post' ),
			'manage_options',
			'duplicatepost',
			[ $this, 'generate_page' ]
		);

		\add_action( $page_hook, [ $this, 'enqueue_assets' ] );
	}

	/**
	 * Generates the inputs for the specified tab / fieldset.
	 *
	 * @codeCoverageIgnore As this is a simple wrapper for two functions that are already tested elsewhere, we can skip testing.
	 *
	 * @param string $tab      The tab to get the configuration for.
	 * @param string $fieldset The fieldset to get the configuration for. Optional.
	 *
	 * @return string The HTML output for the controls present on the tab / fieldset.
	 */
	public function generate_tab_inputs( $tab, $fieldset = '' ) {
		$options = $this->options->get_options_for_tab( $tab, $fieldset );

		return $this->generator->generate_options_input( $options );
	}

	/**
	 * Generates an input for a single option.
	 *
	 * @codeCoverageIgnore As this is a simple wrapper for two functions that are already tested elsewhere, we can skip testing.
	 *
	 * @param string $option The option configuration to base the input on.
	 *
	 * @return string The input HTML.
	 */
	public function generate_input( $option ) {
		return $this->generator->generate_options_input( $this->options->get_option( $option ) );
	}

	/**
	 * Registers the proper capabilities.
	 *
	 * @return void
	 */
	public function register_capabilities() {
		if ( ! \current_user_can( 'promote_users' ) || ! $this->settings_updated() ) {
			return;
		}

		$roles = $this->get_duplicate_post_roles();

		foreach ( Utils::get_roles() as $name => $display_name ) {
			$role = \get_role( $name );

			if ( ! $role->has_cap( 'copy_posts' ) && \in_array( $name, $roles, true ) ) {
				/* If the role doesn't have the capability and it was selected, add it. */
				$role->add_cap( 'copy_posts' );
			}

			if ( $role->has_cap( 'copy_posts' ) && ! \in_array( $name, $roles, true ) ) {
				/* If the role has the capability and it wasn't selected, remove it. */
				$role->remove_cap( 'copy_posts' );
			}
		}
	}

	/**
	 * Generates the options page.
	 *
	 * @codeCoverageIgnore
	 *
	 * @return void
	 */
	public function generate_page() {
		$this->register_capabilities();

		require_once \DUPLICATE_POST_PATH . 'src/admin/views/options.php';
	}

	/**
	 * Checks whether settings have been updated.
	 *
	 * @return bool Whether or not the settings have been updated.
	 */
	protected function settings_updated() {
		return isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] === 'true';
	}

	/**
	 * Gets the registered custom roles.
	 *
	 * @return array The roles. Returns an empty array if there are none.
	 */
	protected function get_duplicate_post_roles() {
		$roles = \get_option( 'duplicate_post_roles' );

		if ( empty( $roles ) ) {
			$roles = [];
		}

		return $roles;
	}
}
PK!l7�P�%�%$src/admin/options-form-generator.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Admin;

use WP_Taxonomy;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Class Options_Form_Generator.
 */
class Options_Form_Generator {

	/**
	 * The Options_Inputs instance.
	 *
	 * @var Options_Inputs
	 */
	protected $options_inputs;

	/**
	 * Options_Form_Generator constructor.
	 *
	 * @param Options_Inputs $inputs The Options_Inputs instance.
	 */
	public function __construct( Options_Inputs $inputs ) {
		$this->options_inputs = $inputs;
	}

	/**
	 * Generates the HTML output of an input control, based on the passed options.
	 *
	 * @param array  $options       The options to base the input on.
	 * @param string $parent_option The parent option, used for grouped inputs. Optional.
	 *
	 * @return string The HTML output.
	 */
	public function generate_options_input( array $options, $parent_option = '' ) {
		$output = '';

		foreach ( $options as $option => $option_values ) {
			// Skip empty options.
			if ( empty( $option_values ) ) {
				continue;
			}

			// Check for support of the current WordPress version.
			if ( \array_key_exists( 'version', $option_values ) && \version_compare( \get_bloginfo( 'version' ), $option_values['version'] ) < 0 ) {
				continue;
			}

			if ( \array_key_exists( 'sub_options', $option_values ) ) {
				$output .= $this->generate_options_input( $option_values['sub_options'], $option );

				continue;
			}

			// If callback, call it.
			if ( \array_key_exists( 'callback', $option_values ) ) {
				$output .= $this->{$option_values['callback']}();

				continue;
			}

			if ( ! \array_key_exists( 'type', $option_values ) ) {
				continue;
			}

			$id = ( \array_key_exists( 'id', $option_values ) ? $option_values['id'] : $this->prepare_input_id( $option ) );

			if ( $parent_option !== '' ) {
				$id     = \sprintf( '%s-%s', $this->prepare_input_id( $parent_option ), $id );
				$option = \sprintf( '%s[%s]', $parent_option, $option );
			}

			switch ( $option_values['type'] ) {
				case 'checkbox':
					$output .= $this->options_inputs->checkbox(
						$option,
						$option_values['value'],
						$id,
						$this->is_checked( $option, $option_values, $parent_option )
					);

					$output .= \sprintf( '<label for="%s">%s</label>', $id, \esc_html( $option_values['label'] ) );
					break;
				case 'text':
					$output .= $this->options_inputs->text( $option, $option_values['value'], $id );
					break;
				case 'number':
					$output .= $this->options_inputs->number( $option, $option_values['value'], $id );

					break;
			}

			if ( \array_key_exists( 'description', $option_values ) ) {
				$output .= ' ' . $this->extract_description( $option_values['description'], $id );
			}

			$output .= '<br />';
		}

		return $output;
	}

	/**
	 * Sorts taxonomy objects based on being public, followed by being private
	 * and when the visibility is equal, on the taxonomy public name (case-sensitive).
	 *
	 * @param WP_Taxonomy $taxonomy1 First taxonomy object.
	 * @param WP_Taxonomy $taxonomy2 Second taxonomy object.
	 *
	 * @return int An integer less than, equal to, or greater than zero indicating respectively
	 *             the first taxonomy should be sorted before, at the same level or after the second taxonomy.
	 */
	public function sort_taxonomy_objects( $taxonomy1, $taxonomy2 ) {
		if ( $taxonomy1->public === true && $taxonomy2->public === false ) {
			return -1;
		}
		elseif ( $taxonomy1->public === false && $taxonomy2->public === true ) {
			return 1;
		}

		// Same visibility, sort by name.
		return \strnatcmp( $taxonomy1->labels->name, $taxonomy2->labels->name );
	}

	/**
	 * Extracts and formats the description associated with the input field.
	 *
	 * @param string|array $description The description string. Can be an array of strings.
	 * @param string       $id          The ID of the input field.
	 *
	 * @return string The description HTML for the input.
	 */
	public function extract_description( $description, $id ) {
		if ( ! \is_array( $description ) ) {
			return \sprintf( '<span id="%s-description">(%s)</span>', $id, \esc_html( $description ) );
		}

		return \sprintf( '<p id="%s-description">%s</p>', $id, \implode( '<br />', \array_map( '\esc_html', $description ) ) );
	}

	/**
	 * Generates a list of checkboxes for registered taxonomies.
	 *
	 * @return string The generated taxonomies list.
	 */
	public function generate_taxonomy_exclusion_list() {
		$taxonomies = \get_taxonomies( [], 'objects' );

		\usort( $taxonomies, [ $this, 'sort_taxonomy_objects' ] );

		$taxonomies_blacklist = \get_option( 'duplicate_post_taxonomies_blacklist' );

		if ( ! \is_array( $taxonomies_blacklist ) ) {
			$taxonomies_blacklist = [];
		}

		$output = '';

		foreach ( $taxonomies as $taxonomy ) {
			if ( $taxonomy->name === 'post_format' ) {
				continue;
			}

			$is_public = ( $taxonomy->public ) ? 'public' : 'private';
			$name      = \esc_attr( $taxonomy->name );

			$output .= \sprintf( '<div class="taxonomy_%s">', $is_public );
			$output .= $this->generate_options_input(
				[
					'duplicate_post_taxonomies_blacklist[]' => [
						'type'    => 'checkbox',
						'id'      => 'duplicate-post-' . $this->prepare_input_id( $name ),
						'value'   => $name,
						'checked' => \in_array( $taxonomy->name, $taxonomies_blacklist, true ),
						'label'   => $taxonomy->labels->name . ' [' . $taxonomy->name . ']',
					],
				]
			);
			$output .= '</div>';
		}

		return $output;
	}

	/**
	 * Generates a list of checkboxes for registered roles.
	 *
	 * @return string The generated roles list.
	 */
	public function generate_roles_permission_list() {
		$post_types        = \get_post_types( [ 'show_ui' => true ], 'objects' );
		$edit_capabilities = [ 'edit_posts' => true ];

		foreach ( $post_types as $post_type ) {
			$edit_capabilities[ $post_type->cap->edit_posts ] = true;
		}

		$output = '';

		foreach ( Utils::get_roles() as $name => $display_name ) {
			$role = \get_role( $name );

			if ( \count( \array_intersect_key( $role->capabilities, $edit_capabilities ) ) > 0 ) {
				$output .= $this->generate_options_input(
					[
						'duplicate_post_roles[]' => [
							'type'    => 'checkbox',
							'id'      => 'duplicate-post-' . $this->prepare_input_id( $name ),
							'value'   => $name,
							'checked' => $role->has_cap( 'copy_posts' ),
							'label'   => \translate_user_role( $display_name ),
						],
					]
				);
			}
		}

		return $output;
	}

	/**
	 * Generates a list of checkboxes for registered post types.
	 *
	 * @return string The generated post types list.
	 */
	public function generate_post_types_list() {
		$post_types        = \get_post_types( [ 'show_ui' => true ], 'objects' );
		$hidden_post_types = $this->get_hidden_post_types();
		$output            = '';

		foreach ( $post_types as $post_type_object ) {
			if ( \in_array( $post_type_object->name, $hidden_post_types, true ) ) {
				continue;
			}

			$name = \esc_attr( $post_type_object->name );

			$output .= $this->generate_options_input(
				[
					'duplicate_post_types_enabled[]' => [
						'type'    => 'checkbox',
						'id'      => 'duplicate-post-' . $this->prepare_input_id( $name ),
						'value'   => $name,
						'checked' => $this->is_post_type_enabled( $post_type_object->name ),
						'label'   => $post_type_object->labels->name,
					],
				]
			);
		}

		return $output;
	}

	/**
	 * Determines whether the passed option should result in a checked checkbox or not.
	 *
	 * @param string $option        The option to search for.
	 * @param array  $option_values The option's values.
	 * @param string $parent_option The parent option. Optional.
	 *
	 * @return bool Whether or not the checkbox should be checked.
	 */
	public function is_checked( $option, $option_values, $parent_option = '' ) {
		if ( \array_key_exists( 'checked', $option_values ) ) {
			return $option_values['checked'];
		}

		// Check for serialized options.
		$saved_option = ! empty( $parent_option ) ? \get_option( $parent_option ) : \get_option( $option );

		if ( ! \is_array( $saved_option ) ) {
			return (int) $saved_option === 1;
		}

		// Clean up the sub-option's name.
		$cleaned_option = \trim( \str_replace( $parent_option, '', $option ), '[]' );

		return \array_key_exists( $cleaned_option, $saved_option ) && (int) $saved_option[ $cleaned_option ] === 1;
	}

	/**
	 * Prepares the passed ID so it's properly formatted.
	 *
	 * @param string $id The ID to prepare.
	 *
	 * @return string The prepared input ID.
	 */
	public function prepare_input_id( $id ) {
		return \str_replace( '_', '-', $id );
	}

	/**
	 * Checks whether or not a post type is enabled.
	 *
	 * @codeCoverageIgnore As this is a simple wrapper for a function that is also being used elsewhere, we can skip testing for now.
	 *
	 * @param string $post_type The post type.
	 *
	 * @return bool Whether or not the post type is enabled.
	 */
	public function is_post_type_enabled( $post_type ) {
		$duplicate_post_types_enabled = \get_option( 'duplicate_post_types_enabled', [ 'post', 'page' ] );
		if ( ! \is_array( $duplicate_post_types_enabled ) ) {
			$duplicate_post_types_enabled = [ $duplicate_post_types_enabled ];
		}
		return \in_array( $post_type, $duplicate_post_types_enabled, true );
	}

	/**
	 * Generates a list of post types that should be hidden from the options page.
	 *
	 * @return array The array of names of the post types to hide.
	 */
	public function get_hidden_post_types() {
		$hidden_post_types = [
			'attachment',
			'wp_block',
		];

		if ( Utils::is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
			$hidden_post_types[] = 'product';
		}

		return $hidden_post_types;
	}
}
PK!�!�
^^src/revisions-migrator.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post;

/**
 * Duplicate Post class to migrate revisions from the Rewrite & Republish copy to the original post.
 *
 * @since 4.0
 */
class Revisions_Migrator {

	/**
	 * Adds hooks to integrate with the Post Republisher class.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'duplicate_post_after_rewriting', [ $this, 'migrate_revisions' ], 10, 2 );
	}

	/**
	 * Updates the revisions of the Rewrite & Republish copy to make them revisions of the original.
	 *
	 * It mimics the behaviour of wp_save_post_revision() in wp-includes/revision.php
	 * by deleting the revisions (except autosaves) exceeding the maximum allowed number.
	 *
	 * @param int $copy_id     The copy's ID.
	 * @param int $original_id The post's ID.
	 *
	 * @return void
	 */
	public function migrate_revisions( $copy_id, $original_id ) {
		$copy          = \get_post( $copy_id );
		$original_post = \get_post( $original_id );

		if ( \is_null( $copy ) || \is_null( $original_post ) || ! \wp_revisions_enabled( $original_post ) ) {
			return;
		}

		$copy_revisions = \wp_get_post_revisions( $copy );
		foreach ( $copy_revisions as $revision ) {
			$revision->post_parent = $original_post->ID;
			$revision->post_name   = "$original_post->ID-revision-v1";
			\wp_update_post( $revision );
		}

		$revisions_to_keep = \wp_revisions_to_keep( $original_post );
		if ( $revisions_to_keep < 0 ) {
			return;
		}

		$revisions = \wp_get_post_revisions( $original_post, [ 'order' => 'ASC' ] );
		$delete    = ( \count( $revisions ) - $revisions_to_keep );
		if ( $delete < 1 ) {
			return;
		}

		$revisions = \array_slice( $revisions, 0, $delete );

		for ( $i = 0; isset( $revisions[ $i ] ); $i++ ) {
			if ( \strpos( $revisions[ $i ]->post_name, 'autosave' ) !== false ) {
				continue;
			}
			\wp_delete_post_revision( $revisions[ $i ]->ID );
		}
	}
}
PK!����
�
%src/watchers/link-actions-watcher.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Watchers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post class to watch for the link actions and show notices.
 */
class Link_Actions_Watcher {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;

		$this->register_hooks();
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_filter( 'removable_query_args', [ $this, 'add_removable_query_args' ], 10, 1 );
		\add_action( 'admin_notices', [ $this, 'add_clone_admin_notice' ] );
		\add_action( 'admin_notices', [ $this, 'add_rewrite_and_republish_admin_notice' ] );
		\add_action( 'enqueue_block_editor_assets', [ $this, 'add_rewrite_and_republish_block_editor_notice' ] );
	}

	/**
	 * Adds vars to the removable query args.
	 *
	 * @param array $removable_query_args Array of query args keys.
	 *
	 * @return array The updated array of query args keys.
	 */
	public function add_removable_query_args( $removable_query_args ) {
		if ( \is_array( $removable_query_args ) ) {
			$removable_query_args[] = 'cloned';
			$removable_query_args[] = 'rewriting';
		}
		return $removable_query_args;
	}

	/**
	 * Shows a notice after the Clone link action has succeeded.
	 *
	 * @return void
	 */
	public function add_clone_admin_notice() {
		if ( ! empty( $_REQUEST['cloned'] ) ) {
			if ( ! $this->permissions_helper->is_classic_editor() ) {
				return;
			}

			$copied_posts = \intval( $_REQUEST['cloned'] );
			\printf(
				'<div id="message" class="notice notice-success fade"><p>'
				. \esc_html(
					/* translators: %s: Number of posts copied. */
					\_n(
						'%s item copied.',
						'%s items copied.',
						$copied_posts,
						'duplicate-post'
					)
				) . '</p></div>',
				\esc_html( $copied_posts )
			);
		}
	}

	/**
	 * Shows a notice in Classic editor after the Rewrite & Republish action via link has succeeded.
	 *
	 * @return void
	 */
	public function add_rewrite_and_republish_admin_notice() {
		if ( ! empty( $_REQUEST['rewriting'] ) ) {
			if ( ! $this->permissions_helper->is_classic_editor() ) {
				return;
			}

			print '<div id="message" class="notice notice-warning is-dismissible fade"><p>'
				. \esc_html__(
					'You can now start rewriting your post in this duplicate of the original post. If you click "Republish", your changes will be merged into the original post and you’ll be redirected there.',
					'duplicate-post'
				) . '</p></div>';
		}
	}

	/**
	 * Shows a notice on the Block editor after the Rewrite & Republish action via link has succeeded.
	 *
	 * @return void
	 */
	public function add_rewrite_and_republish_block_editor_notice() {
		if ( ! empty( $_REQUEST['rewriting'] ) ) {
			$notice = [
				'text'          => \wp_slash(
					\__(
						'You can now start rewriting your post in this duplicate of the original post. If you click "Republish", this rewritten post will replace the original post.',
						'duplicate-post'
					)
				),
				'status'        => 'warning',
				'isDismissible' => true,
			];

			\wp_add_inline_script(
				'duplicate_post_edit_script',
				"duplicatePostNotices.rewriting_notice = '" . \wp_json_encode( $notice ) . "';",
				'before'
			);
		}
	}
}
PK!.�e�

src/watchers/watchers.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Watchers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post user interface.
 */
class Watchers {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the original post watcher.
	 *
	 * @var Original_Post_Watcher
	 */
	protected $original_post_watcher;

	/**
	 * Holds the copied post watcher.
	 *
	 * @var Copied_Post_Watcher
	 */
	protected $copied_post_watcher;

	/**
	 * Holds the bulk actions watcher.
	 *
	 * @var Bulk_Actions_Watcher
	 */
	protected $bulk_actions_watcher;

	/**
	 * Holds the link actions watcher.
	 *
	 * @var Link_Actions_Watcher
	 */
	protected $link_actions_watcher;

	/**
	 * Holds the republished post watcher.
	 *
	 * @var Republished_Post_Watcher
	 */
	protected $republished_post_watcher;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The permissions helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper       = $permissions_helper;
		$this->copied_post_watcher      = new Copied_Post_Watcher( $this->permissions_helper );
		$this->original_post_watcher    = new Original_Post_Watcher( $this->permissions_helper );
		$this->bulk_actions_watcher     = new Bulk_Actions_Watcher();
		$this->link_actions_watcher     = new Link_Actions_Watcher( $this->permissions_helper );
		$this->republished_post_watcher = new Republished_Post_Watcher( $this->permissions_helper );
	}
}
PK!���w		&src/watchers/original-post-watcher.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Watchers;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post Original post watcher class.
 *
 * Watches the original post for changes.
 *
 * @since 4.0
 */
class Original_Post_Watcher {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;

		$this->register_hooks();
	}

	/**
	 * Registers the hooks.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'admin_notices', [ $this, 'add_admin_notice' ] );
		\add_action( 'enqueue_block_editor_assets', [ $this, 'add_block_editor_notice' ], 11 );
	}

	/**
	 * Generates the translated text for the notice.
	 *
	 * @return string The translated text for the notice.
	 */
	public function get_notice_text() {
		return \__(
			'The original post has been edited in the meantime. If you click "Republish", this rewritten post will replace the original post.',
			'duplicate-post'
		);
	}

	/**
	 * Shows a notice on the Classic editor.
	 *
	 * @return void
	 */
	public function add_admin_notice() {
		if ( ! $this->permissions_helper->is_classic_editor() ) {
			return;
		}

		$post = \get_post();

		if ( ! $post instanceof WP_Post ) {
			return;
		}

		if ( $this->permissions_helper->has_original_changed( $post ) ) {
			print '<div id="message" class="notice notice-warning is-dismissible fade"><p>'
				. \esc_html( $this->get_notice_text() )
				. '</p></div>';
		}
	}

	/**
	 * Shows a notice on the Block editor.
	 *
	 * @return void
	 */
	public function add_block_editor_notice() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post ) {
			return;
		}

		if ( $this->permissions_helper->has_original_changed( $post ) ) {

			$notice = [
				'text'          => \wp_slash( $this->get_notice_text() ),
				'status'        => 'warning',
				'isDismissible' => true,
			];

			\wp_add_inline_script(
				'duplicate_post_edit_script',
				"duplicatePostNotices.has_original_changed_notice = '" . \wp_json_encode( $notice ) . "';",
				'before'
			);
		}
	}
}
PK!��� ��$src/watchers/copied-post-watcher.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Watchers;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post class to watch if the current post has a Rewrite & Republish copy.
 */
class Copied_Post_Watcher {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions helper object.
	 */
	public function __construct( $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;

		$this->register_hooks();
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'admin_notices', [ $this, 'add_admin_notice' ] );
		\add_action( 'enqueue_block_editor_assets', [ $this, 'add_block_editor_notice' ], 11 );
	}

	/**
	 * Generates the translated text for the notice.
	 *
	 * @param WP_Post $post The current post object.
	 *
	 * @return string The translated text for the notice.
	 */
	public function get_notice_text( $post ) {
		if ( $this->permissions_helper->has_trashed_rewrite_and_republish_copy( $post ) ) {
			return \__(
				'You can only make one Rewrite & Republish duplicate at a time, and a duplicate of this post already exists in the trash. Permanently delete it if you want to make a new duplicate.',
				'duplicate-post'
			);
		}

		$scheduled_copy = $this->permissions_helper->has_scheduled_rewrite_and_republish_copy( $post );
		if ( ! $scheduled_copy ) {
			return \__(
				'A duplicate of this post was made. Please note that any changes you make to this post will be replaced when the duplicated version is republished.',
				'duplicate-post'
			);
		}

		return \sprintf(
			/* translators: %1$s: scheduled date of the copy, %2$s: scheduled time of the copy. */
			\__(
				'A duplicate of this post was made, which is scheduled to replace this post on %1$s at %2$s.',
				'duplicate-post'
			),
			\get_the_time( \get_option( 'date_format' ), $scheduled_copy ),
			\get_the_time( \get_option( 'time_format' ), $scheduled_copy )
		);
	}

	/**
	 * Shows a notice on the Classic editor.
	 *
	 * @return void
	 */
	public function add_admin_notice() {
		if ( ! $this->permissions_helper->is_classic_editor() ) {
			return;
		}

		$post = \get_post();

		if ( ! $post instanceof WP_Post ) {
			return;
		}

		if ( $this->permissions_helper->has_rewrite_and_republish_copy( $post ) ) {
			print '<div id="message" class="notice notice-warning is-dismissible fade"><p>'
				. \esc_html( $this->get_notice_text( $post ) )
				. '</p></div>';
		}
	}

	/**
	 * Shows a notice on the Block editor.
	 *
	 * @return void
	 */
	public function add_block_editor_notice() {
		$post = \get_post();

		if ( ! $post instanceof WP_Post ) {
			return;
		}

		if ( $this->permissions_helper->has_rewrite_and_republish_copy( $post ) ) {

			$notice = [
				'text'          => \wp_slash( $this->get_notice_text( $post ) ),
				'status'        => 'warning',
				'isDismissible' => true,
			];

			\wp_add_inline_script(
				'duplicate_post_edit_script',
				"duplicatePostNotices.has_rewrite_and_republish_notice = '" . \wp_json_encode( $notice ) . "';",
				'before'
			);
		}
	}
}
PK!\�	th
h
)src/watchers/republished-post-watcher.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Watchers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post class to watch if the post has been republished for Rewrite & Republish.
 *
 * @since 4.0
 */
class Republished_Post_Watcher {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;

		$this->register_hooks();
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_filter( 'removable_query_args', [ $this, 'add_removable_query_args' ] );
		\add_action( 'admin_notices', [ $this, 'add_admin_notice' ] );
		\add_action( 'enqueue_block_editor_assets', [ $this, 'add_block_editor_notice' ], 11 );
	}

	/**
	 * Adds vars to the removable query args.
	 *
	 * @param array $removable_query_args Array of query args keys.
	 *
	 * @return array The updated array of query args keys.
	 */
	public function add_removable_query_args( $removable_query_args ) {
		if ( \is_array( $removable_query_args ) ) {
			$removable_query_args[] = 'dprepublished';
			$removable_query_args[] = 'dpcopy';
			$removable_query_args[] = 'dpnonce';
		}
		return $removable_query_args;
	}

	/**
	 * Generates the translated text for the republished notice.
	 *
	 * @return string The translated text for the republished notice.
	 */
	public function get_notice_text() {
		return \__(
			'Your original post has been replaced with the rewritten post. You are now viewing the (rewritten) original post.',
			'duplicate-post'
		);
	}

	/**
	 * Shows a notice on the Classic editor.
	 *
	 * @return void
	 */
	public function add_admin_notice() {
		if ( ! $this->permissions_helper->is_classic_editor() ) {
			return;
		}

		if ( ! empty( $_REQUEST['dprepublished'] ) ) {
			echo '<div id="message" class="notice notice-success is-dismissible"><p>'
				. \esc_html( $this->get_notice_text() )
				. '</p></div>';
		}
	}

	/**
	 * Shows a notice on the Block editor.
	 *
	 * @return void
	 */
	public function add_block_editor_notice() {
		if ( ! empty( $_REQUEST['dprepublished'] ) ) {
			$notice = [
				'text'          => \wp_slash( $this->get_notice_text() ),
				'status'        => 'success',
				'isDismissible' => true,
			];

			\wp_add_inline_script(
				'duplicate_post_edit_script',
				"duplicatePostNotices.republished_notice = '" . \wp_json_encode( $notice ) . "';",
				'before'
			);
		}
	}
}
PK!�6$�

%src/watchers/bulk-actions-watcher.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Watchers;

/**
 * Duplicate Post class to watch for the bulk actions and show notices.
 */
class Bulk_Actions_Watcher {

	/**
	 * Initializes the class.
	 */
	public function __construct() {
		$this->register_hooks();
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_filter( 'removable_query_args', [ $this, 'add_removable_query_args' ] );
		\add_action( 'admin_notices', [ $this, 'add_bulk_clone_admin_notice' ] );
		\add_action( 'admin_notices', [ $this, 'add_bulk_rewrite_and_republish_admin_notice' ] );
	}

	/**
	 * Adds vars to the removable query args.
	 *
	 * @param array $removable_query_args Array of query args keys.
	 *
	 * @return array The updated array of query args keys.
	 */
	public function add_removable_query_args( $removable_query_args ) {
		if ( \is_array( $removable_query_args ) ) {
			$removable_query_args[] = 'bulk_cloned';
			$removable_query_args[] = 'bulk_rewriting';
		}
		return $removable_query_args;
	}

	/**
	 * Shows a notice after the Clone bulk action has succeeded.
	 *
	 * @return void
	 */
	public function add_bulk_clone_admin_notice() {
		if ( ! empty( $_REQUEST['bulk_cloned'] ) ) {
			$copied_posts = \intval( $_REQUEST['bulk_cloned'] );
			\printf(
				'<div id="message" class="notice notice-success fade"><p>'
				. \esc_html(
					/* translators: %s: Number of posts copied. */
					\_n(
						'%s item copied.',
						'%s items copied.',
						$copied_posts,
						'duplicate-post'
					)
				) . '</p></div>',
				\esc_html( $copied_posts )
			);
		}
	}

	/**
	 * Shows a notice after the Rewrite & Republish bulk action has succeeded.
	 *
	 * @return void
	 */
	public function add_bulk_rewrite_and_republish_admin_notice() {
		if ( ! empty( $_REQUEST['bulk_rewriting'] ) ) {
			$copied_posts = \intval( $_REQUEST['bulk_rewriting'] );
			\printf(
				'<div id="message" class="notice notice-success fade"><p>'
				. \esc_html(
					/* translators: %s: Number of posts copied. */
					\_n(
						'%s post duplicated. You can now start rewriting your post in the duplicate of the original post. Once you choose to republish it your changes will be merged back into the original post.',
						'%s posts duplicated. You can now start rewriting your posts in the duplicates of the original posts. Once you choose to republish them your changes will be merged back into the original post.',
						$copied_posts,
						'duplicate-post'
					)
				) . '</p></div>',
				\esc_html( $copied_posts )
			);
		}
	}
}
PK!�A#@&src/handlers/check-changes-handler.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Handlers;

use WP_Post;
use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post handler class for changes overview.
 *
 * Represents the handler for checking the changes between a copy and the original post.
 *
 * @since 4.0
 */
class Check_Changes_Handler {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Holds the current post object.
	 *
	 * @var WP_Post
	 */
	private $post;

	/**
	 * Holds the original post object.
	 *
	 * @var WP_Post
	 */
	private $original;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions Helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'admin_action_duplicate_post_check_changes', [ $this, 'check_changes_action_handler' ] );
	}

	/**
	 * Handles the action for displaying the changes between a copy and the original.
	 *
	 * @return void
	 */
	public function check_changes_action_handler() {
		global $wp_version;

		if ( ! ( isset( $_GET['post'] ) || isset( $_POST['post'] )
			|| ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'duplicate_post_check_changes' ) ) ) {
			\wp_die(
				\esc_html__( 'No post has been supplied!', 'duplicate-post' )
			);
			return;
		}

		$id = ( isset( $_GET['post'] ) ? \intval( \wp_unslash( $_GET['post'] ) ) : \intval( \wp_unslash( $_POST['post'] ) ) );

		\check_admin_referer( 'duplicate_post_check_changes_' . $id );

		$this->post = \get_post( $id );

		if ( ! $this->post ) {
			\wp_die(
				\esc_html(
					\sprintf(
						/* translators: %s: post ID. */
						\__( 'Changes overview failed, could not find post with ID %s.', 'duplicate-post' ),
						$id
					)
				)
			);
			return;
		}

		$this->original = Utils::get_original( $this->post );

		if ( ! $this->original ) {
			\wp_die(
				\esc_html(
					\__( 'Changes overview failed, could not find original post.', 'duplicate-post' )
				)
			);
			return;
		}
		$post_edit_link = \get_edit_post_link( $this->post->ID );

		$this->require_wordpress_header();
		?>
		<div class="wrap">
			<h1 class="long-header">
			<?php
				echo \sprintf(
					/* translators: %s: original item link (to view or edit) or title. */
					\esc_html__( 'Compare changes of duplicated post with the original (&#8220;%s&#8221;)', 'duplicate-post' ),
					Utils::get_edit_or_view_link( $this->original ) // phpcs:ignore WordPress.Security.EscapeOutput
				);
			?>
				</h1>
			<a href="<?php echo \esc_url( $post_edit_link ); ?>"><?php \esc_html_e( '&larr; Return to editor', 'duplicate-post' ); ?></a>
			<div class="revisions">
				<div class="revisions-control-frame">
					<div class="revisions-controls"></div>
				</div>
				<div class="revisions-diff-frame">
					<div class="revisions-diff">
						<div class="diff">
						<?php
						$fields = [
							'post_title'   => \__( 'Title', 'duplicate-post' ),
							'post_content' => \__( 'Content', 'duplicate-post' ),
							'post_excerpt' => \__( 'Excerpt', 'duplicate-post' ),
						];

						$args = [
							'show_split_view' => true,
							'title_left'      => \__( 'Removed', 'duplicate-post' ),
							'title_right'     => \__( 'Added', 'duplicate-post' ),
						];

						if ( \version_compare( $wp_version, '5.7' ) < 0 ) {
							unset( $args['title_left'] );
							unset( $args['title_right'] );
						}

						$post_array = \get_post( $this->post, \ARRAY_A );

						/** This filter is documented in wp-admin/includes/revision.php */
						// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reason: using WP core hook.
						$fields = \apply_filters( '_wp_post_revision_fields', $fields, $post_array );

						foreach ( $fields as $field => $name ) {
							/** This filter is documented in wp-admin/includes/revision.php */
							// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reason: using WP core hook.
							$content_from = \apply_filters( "_wp_post_revision_field_{$field}", $this->original->$field, $field, $this->original, 'from' );

							/** This filter is documented in wp-admin/includes/revision.php */
							// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reason: using WP core hook.
							$content_to = \apply_filters( "_wp_post_revision_field_{$field}", $this->post->$field, $field, $this->post, 'to' );

							$diff = \wp_text_diff( $content_from, $content_to, $args );

							if ( ! $diff && $field === 'post_title' ) {
								// It's a better user experience to still show the Title, even if it didn't change.
								$diff  = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>';
								$diff .= '<td>' . \esc_html( $this->original->post_title ) . '</td><td></td><td>' . \esc_html( $this->post->post_title ) . '</td>';
								$diff .= '</tr></tbody>';
								$diff .= '</table>';
							}

							if ( $diff ) {
								?>
								<h3><?php echo \esc_html( $name ); ?></h3>
								<?php
									echo $diff; // phpcs:ignore WordPress.Security.EscapeOutput
							}
						}
						?>

						</div>
					</div>
				</div>
			</div>
		</div>
		<?php
		$this->require_wordpress_footer();
	}

	/**
	 * Requires the WP admin header.
	 *
	 * @codeCoverageIgnore
	 *
	 * @return void
	 */
	public function require_wordpress_header() {
		global $post;
		\set_current_screen( 'revision' );
		// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- The revision screen expects $post to be set.
		$post = $this->post;
		require_once \ABSPATH . 'wp-admin/admin-header.php';
	}

	/**
	 * Requires the WP admin footer.
	 *
	 * @codeCoverageIgnore
	 *
	 * @return void
	 */
	public function require_wordpress_footer() {
		require_once \ABSPATH . 'wp-admin/admin-footer.php';
	}
}
PK!��*��"src/handlers/save-post-handler.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Handlers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;

/**
 * Duplicate Post handler class for save_post action.
 *
 * @since 4.0
 */
class Save_Post_Handler {

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Permissions_Helper $permissions_helper The Permissions Helper object.
	 */
	public function __construct( Permissions_Helper $permissions_helper ) {
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		if ( \intval( \get_option( 'duplicate_post_show_original_meta_box' ) ) === 1
			|| \intval( \get_option( 'duplicate_post_show_original_column' ) ) === 1 ) {
			\add_action( 'save_post', [ $this, 'delete_on_save_post' ] );
		}
	}

	/**
	 * Deletes the custom field with the ID of the original post.
	 *
	 * @param int $post_id The current post ID.
	 *
	 * @return void
	 */
	public function delete_on_save_post( $post_id ) {
		if ( ( \defined( 'DOING_AUTOSAVE' ) && \DOING_AUTOSAVE )
			|| empty( $_POST['duplicate_post_remove_original'] )
			|| ! \current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		$post = \get_post( $post_id );
		if ( ! $post ) {
			return;
		}
		if ( ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			\delete_post_meta( $post_id, '_dp_original' );
		}
	}
}
PK!�P!+src/handlers/handler.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Handlers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Post_Duplicator;

/**
 * Duplicate Post handler class for duplication actions.
 *
 * @since 4.0
 */
class Handler {

	/**
	 * Post_Duplicator object.
	 *
	 * @var Post_Duplicator
	 */
	protected $post_duplicator;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * The bulk actions handler.
	 *
	 * @var Bulk_Handler
	 */
	protected $bulk_handler;

	/**
	 * The link actions handler.
	 *
	 * @var Link_Handler
	 */
	protected $link_handler;

	/**
	 * The save_post action handler.
	 *
	 * @var Save_Post_Handler
	 */
	protected $save_post_handler;

	/**
	 * The link actions handler.
	 *
	 * @var Check_Changes_Handler
	 */
	protected $check_handler;

	/**
	 * Initializes the class.
	 *
	 * @param Post_Duplicator    $post_duplicator    The Post_Duplicator object.
	 * @param Permissions_Helper $permissions_helper The Permissions Helper object.
	 */
	public function __construct( Post_Duplicator $post_duplicator, Permissions_Helper $permissions_helper ) {
		$this->post_duplicator    = $post_duplicator;
		$this->permissions_helper = $permissions_helper;

		$this->bulk_handler      = new Bulk_Handler( $this->post_duplicator, $this->permissions_helper );
		$this->link_handler      = new Link_Handler( $this->post_duplicator, $this->permissions_helper );
		$this->check_handler     = new Check_Changes_Handler( $this->permissions_helper );
		$this->save_post_handler = new Save_Post_Handler( $this->permissions_helper );

		$this->bulk_handler->register_hooks();
		$this->link_handler->register_hooks();
		$this->check_handler->register_hooks();
		$this->save_post_handler->register_hooks();
	}
}
PK!�-mBBsrc/handlers/bulk-handler.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Handlers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Post_Duplicator;
use Yoast\WP\Duplicate_Post\Utils;

/**
 * Duplicate Post handler class for duplication bulk actions.
 *
 * @since 4.0
 */
class Bulk_Handler {

	/**
	 * Post_Duplicator object.
	 *
	 * @var Post_Duplicator
	 */
	protected $post_duplicator;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Post_Duplicator    $post_duplicator    The Post_Duplicator object.
	 * @param Permissions_Helper $permissions_helper The Permissions Helper object.
	 */
	public function __construct( Post_Duplicator $post_duplicator, Permissions_Helper $permissions_helper ) {
		$this->post_duplicator    = $post_duplicator;
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'admin_init', [ $this, 'add_bulk_handlers' ] );
	}

	/**
	 * Hooks the handler for the Rewrite & Republish action for all the selected post types.
	 *
	 * @return void
	 */
	public function add_bulk_handlers() {
		$duplicate_post_types_enabled = $this->permissions_helper->get_enabled_post_types();

		foreach ( $duplicate_post_types_enabled as $duplicate_post_type_enabled ) {
			\add_filter( "handle_bulk_actions-edit-{$duplicate_post_type_enabled}", [ $this, 'bulk_action_handler' ], 10, 3 );
		}
	}

	/**
	 * Handles the bulk actions.
	 *
	 * @param string $redirect_to The URL to redirect to.
	 * @param string $doaction    The action that has been called.
	 * @param array  $post_ids    The array of marked post IDs.
	 *
	 * @return string The URL to redirect to.
	 */
	public function bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
		$redirect_to = $this->clone_bulk_action_handler( $redirect_to, $doaction, $post_ids );
		return $this->rewrite_bulk_action_handler( $redirect_to, $doaction, $post_ids );
	}

	/**
	 * Handles the bulk action for the Rewrite & Republish feature.
	 *
	 * @param string $redirect_to The URL to redirect to.
	 * @param string $doaction    The action that has been called.
	 * @param array  $post_ids    The array of marked post IDs.
	 *
	 * @return string The URL to redirect to.
	 */
	public function rewrite_bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
		if ( $doaction !== 'duplicate_post_bulk_rewrite_republish' ) {
			return $redirect_to;
		}

		$counter = 0;
		if ( \is_array( $post_ids ) ) {
			foreach ( $post_ids as $post_id ) {
				$post = \get_post( $post_id );
				if ( ! empty( $post ) && $this->permissions_helper->should_rewrite_and_republish_be_allowed( $post ) ) {
					$new_post_id = $this->post_duplicator->create_duplicate_for_rewrite_and_republish( $post );
					if ( ! \is_wp_error( $new_post_id ) ) {
						++$counter;
					}
				}
			}
		}
		return \add_query_arg( 'bulk_rewriting', $counter, $redirect_to );
	}

	/**
	 * Handles the bulk action for the Clone feature.
	 *
	 * @param string $redirect_to The URL to redirect to.
	 * @param string $doaction    The action that has been called.
	 * @param array  $post_ids    The array of marked post IDs.
	 *
	 * @return string The URL to redirect to.
	 */
	public function clone_bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
		if ( $doaction !== 'duplicate_post_bulk_clone' ) {
			return $redirect_to;
		}

		$counter = 0;
		if ( \is_array( $post_ids ) ) {
			foreach ( $post_ids as $post_id ) {
				$post = \get_post( $post_id );
				if ( ! empty( $post ) && ! $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
					if ( \intval( \get_option( 'duplicate_post_copychildren' ) !== 1 )
						|| ! \is_post_type_hierarchical( $post->post_type )
						|| ( \is_post_type_hierarchical( $post->post_type ) && ! Utils::has_ancestors_marked( $post, $post_ids ) )
					) {
						if ( ! \is_wp_error( \duplicate_post_create_duplicate( $post ) ) ) {
							++$counter;
						}
					}
				}
			}
		}
		return \add_query_arg( 'bulk_cloned', $counter, $redirect_to );
	}
}
PK!��11src/handlers/link-handler.phpnu�[���<?php

namespace Yoast\WP\Duplicate_Post\Handlers;

use Yoast\WP\Duplicate_Post\Permissions_Helper;
use Yoast\WP\Duplicate_Post\Post_Duplicator;

/**
 * Duplicate Post handler class for duplication actions from links.
 *
 * @since 4.0
 */
class Link_Handler {

	/**
	 * Post_Duplicator object.
	 *
	 * @var Post_Duplicator
	 */
	protected $post_duplicator;

	/**
	 * Holds the permissions helper.
	 *
	 * @var Permissions_Helper
	 */
	protected $permissions_helper;

	/**
	 * Initializes the class.
	 *
	 * @param Post_Duplicator    $post_duplicator    The Post_Duplicator object.
	 * @param Permissions_Helper $permissions_helper The Permissions Helper object.
	 */
	public function __construct( Post_Duplicator $post_duplicator, Permissions_Helper $permissions_helper ) {
		$this->post_duplicator    = $post_duplicator;
		$this->permissions_helper = $permissions_helper;
	}

	/**
	 * Adds hooks to integrate with WordPress.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'admin_action_duplicate_post_rewrite', [ $this, 'rewrite_link_action_handler' ] );
		\add_action( 'admin_action_duplicate_post_clone', [ $this, 'clone_link_action_handler' ] );
		\add_action( 'admin_action_duplicate_post_new_draft', [ $this, 'new_draft_link_action_handler' ] );
	}

	/**
	 * Handles the action for copying a post to a new draft.
	 *
	 * @return void
	 */
	public function new_draft_link_action_handler() {
		if ( ! $this->permissions_helper->is_current_user_allowed_to_copy() ) {
			\wp_die( \esc_html__( 'Current user is not allowed to copy posts.', 'duplicate-post' ) );
		}

		if ( ! ( isset( $_GET['post'] ) || isset( $_POST['post'] )
			|| ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'duplicate_post_new_draft' ) ) ) {
			\wp_die( \esc_html__( 'No post to duplicate has been supplied!', 'duplicate-post' ) );
		}

		$id = ( isset( $_GET['post'] ) ? \intval( \wp_unslash( $_GET['post'] ) ) : \intval( \wp_unslash( $_POST['post'] ) ) );

		\check_admin_referer( 'duplicate_post_new_draft_' . $id );

		$post = \get_post( $id );

		if ( ! $post ) {
			\wp_die(
				\esc_html(
					\__( 'Copy creation failed, could not find original:', 'duplicate-post' ) . ' '
					. $id
				)
			);
		}

		if ( $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			\wp_die(
				\esc_html__( 'You cannot create a copy of a post which is intended for Rewrite & Republish.', 'duplicate-post' )
			);
		}

		$new_id = \duplicate_post_create_duplicate( $post, 'draft' );

		if ( \is_wp_error( $new_id ) ) {
			\wp_die(
				\esc_html__( 'Copy creation failed, could not create a copy.', 'duplicate-post' )
			);
		}

		\wp_safe_redirect(
			\add_query_arg(
				[
					'cloned' => 1,
					'ids'    => $post->ID,
				],
				\admin_url( 'post.php?action=edit&post=' . $new_id . ( isset( $_GET['classic-editor'] ) ? '&classic-editor' : '' ) )
			)
		);
		exit();
	}

	/**
	 * Handles the action for copying a post and redirecting to the post list.
	 *
	 * @return void
	 */
	public function clone_link_action_handler() {
		if ( ! $this->permissions_helper->is_current_user_allowed_to_copy() ) {
			\wp_die( \esc_html__( 'Current user is not allowed to copy posts.', 'duplicate-post' ) );
		}

		if ( ! ( isset( $_GET['post'] ) || isset( $_POST['post'] )
			|| ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'duplicate_post_clone' ) ) ) {
			\wp_die( \esc_html__( 'No post to duplicate has been supplied!', 'duplicate-post' ) );
		}

		$id = ( isset( $_GET['post'] ) ? \intval( \wp_unslash( $_GET['post'] ) ) : \intval( \wp_unslash( $_POST['post'] ) ) );

		\check_admin_referer( 'duplicate_post_clone_' . $id );

		$post = \get_post( $id );

		if ( ! $post ) {
			\wp_die(
				\esc_html(
					\__( 'Copy creation failed, could not find original:', 'duplicate-post' ) . ' '
					. $id
				)
			);
		}

		if ( $this->permissions_helper->is_rewrite_and_republish_copy( $post ) ) {
			\wp_die(
				\esc_html__( 'You cannot create a copy of a post which is intended for Rewrite & Republish.', 'duplicate-post' )
			);
		}

		$new_id = \duplicate_post_create_duplicate( $post );

		if ( \is_wp_error( $new_id ) ) {
			\wp_die(
				\esc_html__( 'Copy creation failed, could not create a copy.', 'duplicate-post' )
			);
		}

		$post_type = $post->post_type;
		$sendback  = \wp_get_referer();
		if ( ! $sendback || \strpos( $sendback, 'post.php' ) !== false || \strpos( $sendback, 'post-new.php' ) !== false ) {
			if ( $post_type === 'attachment' ) {
				$sendback = \admin_url( 'upload.php' );
			}
			else {
				$sendback = \admin_url( 'edit.php' );
				if ( ! empty( $post_type ) ) {
					$sendback = \add_query_arg( 'post_type', $post_type, $sendback );
				}
			}
		}
		else {
			$sendback = \remove_query_arg( [ 'trashed', 'untrashed', 'deleted', 'cloned', 'ids' ], $sendback );
		}

		// Redirect to the post list screen.
		\wp_safe_redirect(
			\add_query_arg(
				[
					'cloned' => 1,
					'ids'    => $post->ID,
				],
				$sendback
			)
		);
		exit();
	}

	/**
	 * Handles the action for copying a post for the Rewrite & Republish feature.
	 *
	 * @return void
	 */
	public function rewrite_link_action_handler() {
		if ( ! $this->permissions_helper->is_current_user_allowed_to_copy() ) {
			\wp_die( \esc_html__( 'Current user is not allowed to copy posts.', 'duplicate-post' ) );
		}

		if ( ! ( isset( $_GET['post'] ) || isset( $_POST['post'] )
			|| ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'duplicate_post_rewrite' ) ) ) {
			\wp_die( \esc_html__( 'No post to duplicate has been supplied!', 'duplicate-post' ) );
		}

		$id = ( isset( $_GET['post'] ) ? \intval( \wp_unslash( $_GET['post'] ) ) : \intval( \wp_unslash( $_POST['post'] ) ) );

		\check_admin_referer( 'duplicate_post_rewrite_' . $id );

		$post = \get_post( $id );

		if ( ! $post ) {
			\wp_die(
				\esc_html(
					\__( 'Copy creation failed, could not find original:', 'duplicate-post' ) . ' '
					. $id
				)
			);
		}

		if ( ! $this->permissions_helper->should_rewrite_and_republish_be_allowed( $post ) ) {
			\wp_die(
				\esc_html__( 'You cannot create a copy for Rewrite & Republish if the original is not published or if it already has a copy.', 'duplicate-post' )
			);
		}

		$new_id = $this->post_duplicator->create_duplicate_for_rewrite_and_republish( $post );

		if ( \is_wp_error( $new_id ) ) {
			\wp_die(
				\esc_html__( 'Copy creation failed, could not create a copy.', 'duplicate-post' )
			);
		}

		\wp_safe_redirect(
			\add_query_arg(
				[
					'rewriting' => 1,
					'ids'       => $post->ID,
				],
				\admin_url( 'post.php?action=edit&post=' . $new_id . ( isset( $_GET['classic-editor'] ) ? '&classic-editor' : '' ) )
			)
		);
		exit();
	}
}
PK!���
�
duplicate-post.phpnu�[���<?php
/**
 * Duplicate Post plugin.
 *
 * @package Yoast\WP\Duplicate_Post
 * @since   0.1
 *
 * @wordpress-plugin
 * Plugin Name: Yoast Duplicate Post
 * Plugin URI:  https://yoast.com/wordpress/plugins/duplicate-post/
 * Description: The go-to tool for cloning posts and pages, including the powerful Rewrite & Republish feature.
 * Version:     4.5
 * Author:      Enrico Battocchi & Team Yoast
 * Author URI:  https://yoast.com
 * Text Domain: duplicate-post
 *
 * Copyright 2020-2022 Yoast BV (email : info@yoast.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

use Yoast\WP\Duplicate_Post\Duplicate_Post;

if ( ! defined( 'ABSPATH' ) ) {
	exit();
}

if ( ! defined( 'DUPLICATE_POST_FILE' ) ) {
	define( 'DUPLICATE_POST_FILE', __FILE__ );
}

if ( ! defined( 'DUPLICATE_POST_PATH' ) ) {
	define( 'DUPLICATE_POST_PATH', plugin_dir_path( __FILE__ ) );
}

define( 'DUPLICATE_POST_CURRENT_VERSION', '4.5' );

$duplicate_post_autoload_file = DUPLICATE_POST_PATH . 'vendor/autoload.php';

if ( is_readable( $duplicate_post_autoload_file ) ) {
	require $duplicate_post_autoload_file;
}

if ( class_exists( Duplicate_Post::class ) ) {
	// Initialize the main autoloaded class.
	add_action( 'plugins_loaded', '__duplicate_post_main' );
}

/**
 * Loads the Duplicate Post main class.
 *
 * {@internal Function name change would be BC-break.}
 *
 * @phpcs:disable PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
 * @phpcs:disable WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore
 * @phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
 */
function __duplicate_post_main() {
	new Duplicate_Post();
}
// phpcs:enable

/**
 * Initialises the internationalisation domain.
 */
function duplicate_post_load_plugin_textdomain() {
	load_plugin_textdomain( 'duplicate-post', false, basename( __DIR__ ) . '/languages/' );
}
add_action( 'plugins_loaded', 'duplicate_post_load_plugin_textdomain' );

add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'duplicate_post_plugin_actions', 10 );

/**
 * Adds 'Settings' link to plugin entry in the Plugins list.
 *
 * @see 'plugin_action_links_$plugin_file'
 *
 * @param array $actions An array of plugin action links.
 * @return array
 */
function duplicate_post_plugin_actions( $actions ) {
	$settings_action = [
		'settings' => sprintf(
			'<a href="%1$s" %2$s>%3$s</a>',
			menu_page_url( 'duplicatepost', false ),
			'aria-label="' . __( 'Settings for Duplicate Post', 'duplicate-post' ) . '"',
			esc_html__( 'Settings', 'duplicate-post' )
		),
	];

	$actions = ( $settings_action + $actions );
	return $actions;
}

require_once DUPLICATE_POST_PATH . 'common-functions.php';

if ( is_admin() ) {
	include_once DUPLICATE_POST_PATH . 'admin-functions.php';
}
PK!��s��`�`admin-functions.phpnu�[���<?php
/**
 * Backend functions.
 *
 * @package Yoast\WP\Duplicate_Post
 * @since   2.0
 */

if ( ! is_admin() ) {
	return;
}

use Yoast\WP\Duplicate_Post\UI\Newsletter;

require_once DUPLICATE_POST_PATH . 'options.php';

require_once DUPLICATE_POST_PATH . 'compat/wpml-functions.php';
require_once DUPLICATE_POST_PATH . 'compat/jetpack-functions.php';

/**
 * Wrapper for the option 'duplicate_post_version'.
 */
function duplicate_post_get_installed_version() {
	return get_option( 'duplicate_post_version' );
}

/**
 * Wrapper for the defined constant DUPLICATE_POST_CURRENT_VERSION.
 */
function duplicate_post_get_current_version() {
	return DUPLICATE_POST_CURRENT_VERSION;
}

add_action( 'admin_init', 'duplicate_post_admin_init' );

/**
 * Adds handlers depending on the options.
 */
function duplicate_post_admin_init() {
	duplicate_post_plugin_upgrade();

	if ( intval( get_site_option( 'duplicate_post_show_notice' ) ) === 1 ) {
		if ( is_multisite() ) {
			add_action( 'network_admin_notices', 'duplicate_post_show_update_notice' );
		}
		else {
			add_action( 'admin_notices', 'duplicate_post_show_update_notice' );
		}
		add_action( 'wp_ajax_duplicate_post_dismiss_notice', 'duplicate_post_dismiss_notice' );
	}

	add_action( 'dp_duplicate_post', 'duplicate_post_copy_post_meta_info', 10, 2 );
	add_action( 'dp_duplicate_page', 'duplicate_post_copy_post_meta_info', 10, 2 );

	if ( intval( get_option( 'duplicate_post_copychildren' ) ) === 1 ) {
		add_action( 'dp_duplicate_post', 'duplicate_post_copy_children', 20, 3 );
		add_action( 'dp_duplicate_page', 'duplicate_post_copy_children', 20, 3 );
	}

	if ( intval( get_option( 'duplicate_post_copyattachments' ) ) === 1 ) {
		add_action( 'dp_duplicate_post', 'duplicate_post_copy_attachments', 30, 2 );
		add_action( 'dp_duplicate_page', 'duplicate_post_copy_attachments', 30, 2 );
	}

	if ( intval( get_option( 'duplicate_post_copycomments' ) ) === 1 ) {
		add_action( 'dp_duplicate_post', 'duplicate_post_copy_comments', 40, 2 );
		add_action( 'dp_duplicate_page', 'duplicate_post_copy_comments', 40, 2 );
	}

	add_action( 'dp_duplicate_post', 'duplicate_post_copy_post_taxonomies', 50, 2 );
	add_action( 'dp_duplicate_page', 'duplicate_post_copy_post_taxonomies', 50, 2 );

	add_filter( 'plugin_row_meta', 'duplicate_post_add_plugin_links', 10, 2 );
}

/**
 * Plugin upgrade.
 */
function duplicate_post_plugin_upgrade() {
	$installed_version = duplicate_post_get_installed_version();

	if ( duplicate_post_get_current_version() === $installed_version ) {
		return;
	}

	if ( empty( $installed_version ) ) {
		// Get default roles.
		$default_roles = [
			'editor',
			'administrator',
			'wpseo_manager',
			'wpseo_editor',
		];

		foreach ( $default_roles as $name ) {
			$role = get_role( $name );
			if ( ! empty( $role ) ) {
				$role->add_cap( 'copy_posts' );
			}
		}
		add_option( 'duplicate_post_show_notice', 1 );
	}
	else {
		update_option( 'duplicate_post_show_notice', 0 );
	}

	$show_links_in_defaults = [
		'row'         => '1',
		'adminbar'    => '1',
		'submitbox'   => '1',
		'bulkactions' => '1',
	];

	add_option( 'duplicate_post_copytitle', '1' );
	add_option( 'duplicate_post_copydate', '0' );
	add_option( 'duplicate_post_copystatus', '0' );
	add_option( 'duplicate_post_copyslug', '0' );
	add_option( 'duplicate_post_copyexcerpt', '1' );
	add_option( 'duplicate_post_copycontent', '1' );
	add_option( 'duplicate_post_copythumbnail', '1' );
	add_option( 'duplicate_post_copytemplate', '1' );
	add_option( 'duplicate_post_copyformat', '1' );
	add_option( 'duplicate_post_copyauthor', '0' );
	add_option( 'duplicate_post_copypassword', '0' );
	add_option( 'duplicate_post_copyattachments', '0' );
	add_option( 'duplicate_post_copychildren', '0' );
	add_option( 'duplicate_post_copycomments', '0' );
	add_option( 'duplicate_post_copymenuorder', '1' );
	add_option( 'duplicate_post_taxonomies_blacklist', [] );
	add_option( 'duplicate_post_blacklist', '' );
	add_option( 'duplicate_post_types_enabled', [ 'post', 'page' ] );
	add_option( 'duplicate_post_show_original_column', '0' );
	add_option( 'duplicate_post_show_original_in_post_states', '0' );
	add_option( 'duplicate_post_show_original_meta_box', '0' );
	add_option(
		'duplicate_post_show_link',
		[
			'new_draft'         => '1',
			'clone'             => '1',
			'rewrite_republish' => '1',
		]
	);
	add_option( 'duplicate_post_show_link_in', $show_links_in_defaults );

	$taxonomies_blacklist = get_option( 'duplicate_post_taxonomies_blacklist' );
	if ( $taxonomies_blacklist === '' ) {
		$taxonomies_blacklist = [];
	}
	if ( in_array( 'post_format', $taxonomies_blacklist, true ) ) {
		update_option( 'duplicate_post_copyformat', 0 );
		$taxonomies_blacklist = array_diff( $taxonomies_blacklist, [ 'post_format' ] );
		update_option( 'duplicate_post_taxonomies_blacklist', $taxonomies_blacklist );
	}

	$meta_blacklist = explode( ',', get_option( 'duplicate_post_blacklist' ) );
	if ( $meta_blacklist === '' ) {
		$meta_blacklist = [];
	}
	$meta_blacklist = array_map( 'trim', $meta_blacklist );
	if ( in_array( '_wp_page_template', $meta_blacklist, true ) ) {
		update_option( 'duplicate_post_copytemplate', 0 );
		$meta_blacklist = array_diff( $meta_blacklist, [ '_wp_page_template' ] );
	}
	if ( in_array( '_thumbnail_id', $meta_blacklist, true ) ) {
		update_option( 'duplicate_post_copythumbnail', 0 );
		$meta_blacklist = array_diff( $meta_blacklist, [ '_thumbnail_id' ] );
	}
	update_option( 'duplicate_post_blacklist', implode( ',', $meta_blacklist ) );

	if ( version_compare( $installed_version, '4.0.0' ) < 0 ) {
		// Migrate the 'Show links in' options to the new array-based structure.
		duplicate_post_migrate_show_links_in_options( $show_links_in_defaults );
	}

	delete_site_option( 'duplicate_post_version' );
	update_option( 'duplicate_post_version', duplicate_post_get_current_version() );
}

/**
 * Runs the upgrade routine for version 4.0 to update the options in the database.
 *
 * @param array $defaults The default options to fall back on.
 *
 * @return void
 */
function duplicate_post_migrate_show_links_in_options( $defaults ) {
	$options_to_migrate = [
		'duplicate_post_show_row'         => 'row',
		'duplicate_post_show_adminbar'    => 'adminbar',
		'duplicate_post_show_submitbox'   => 'submitbox',
		'duplicate_post_show_bulkactions' => 'bulkactions',
	];

	$new_options = [];
	foreach ( $options_to_migrate as $old => $new ) {
		$new_options[ $new ] = get_option( $old, $defaults[ $new ] );

		delete_option( $old );
	}

	update_option( 'duplicate_post_show_link_in', $new_options );
}

/**
 * Shows the welcome notice.
 *
 * @global string $wp_version The WordPress version string.
 */
function duplicate_post_show_update_notice() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}

	$current_screen = get_current_screen();
	if ( empty( $current_screen )
		|| empty( $current_screen->base )
		|| ( $current_screen->base !== 'dashboard' && $current_screen->base !== 'plugins' )
	) {
		return;
	}

	$title = sprintf(
		/* translators: %s: Yoast Duplicate Post. */
		esc_html__( 'You\'ve successfully installed %s!', 'duplicate-post' ),
		'Yoast Duplicate Post'
	);

	$img_path = plugins_url( '/duplicate_post_yoast_icon-125x125.png', __FILE__ );

	echo '<div id="duplicate-post-notice" class="notice is-dismissible" style="display: flex; align-items: flex-start;">
			<img src="' . esc_url( $img_path ) . '" alt="" style="margin: 1em 1em 1em 0; width: 130px; align-self: center;"/>
			<div stle="margin: 0.5em">
				<h1 style="font-size: 14px; color: #a4286a; font-weight: 600; margin-top: 8px;">' . $title . '</h1>' // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: escaped properly above.
				. Newsletter::newsletter_signup_form() // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: escaped in newsletter.php.
			. '</div>
		</div>';

	echo "<script>
			function duplicate_post_dismiss_notice(){
				var data = {
				'action': 'duplicate_post_dismiss_notice',
				};

				jQuery.post(ajaxurl, data, function(response) {
					jQuery('#duplicate-post-notice').hide();
				});
			}

			jQuery(document).ready(function(){
				jQuery('body').on('click', '.notice-dismiss', function(){
					duplicate_post_dismiss_notice();
				});
			});
			</script>";
}

/**
 * Dismisses the notice.
 *
 * @return bool
 */
function duplicate_post_dismiss_notice() {
	return update_site_option( 'duplicate_post_show_notice', 0 );
}

/**
 * Copies the taxonomies of a post to another post.
 *
 * @global wpdb $wpdb WordPress database abstraction object.
 *
 * @param int     $new_id New post ID.
 * @param WP_Post $post   The original post object.
 */
function duplicate_post_copy_post_taxonomies( $new_id, $post ) {
	global $wpdb;
	if ( isset( $wpdb->terms ) ) {
		// Clear default category (added by wp_insert_post).
		wp_set_object_terms( $new_id, null, 'category' );

		$post_taxonomies = get_object_taxonomies( $post->post_type );
		// Several plugins just add support to post-formats but don't register post_format taxonomy.
		if ( post_type_supports( $post->post_type, 'post-formats' ) && ! in_array( 'post_format', $post_taxonomies, true ) ) {
			$post_taxonomies[] = 'post_format';
		}

		$taxonomies_blacklist = get_option( 'duplicate_post_taxonomies_blacklist' );
		if ( $taxonomies_blacklist === '' ) {
			$taxonomies_blacklist = [];
		}
		if ( intval( get_option( 'duplicate_post_copyformat' ) ) === 0 ) {
			$taxonomies_blacklist[] = 'post_format';
		}

		/**
		 * Filters the taxonomy excludelist when copying a post.
		 *
		 * @param array $taxonomies_blacklist The taxonomy excludelist from the options.
		 *
		 * @return array
		 */
		$taxonomies_blacklist = apply_filters( 'duplicate_post_taxonomies_excludelist_filter', $taxonomies_blacklist );

		$taxonomies = array_diff( $post_taxonomies, $taxonomies_blacklist );
		foreach ( $taxonomies as $taxonomy ) {
			$post_terms = wp_get_object_terms( $post->ID, $taxonomy, [ 'orderby' => 'term_order' ] );
			$terms      = [];
			$num_terms  = count( $post_terms );
			for ( $i = 0; $i < $num_terms; $i++ ) {
				$terms[] = $post_terms[ $i ]->slug;
			}
			wp_set_object_terms( $new_id, $terms, $taxonomy );
		}
	}
}

/**
 * Copies the meta information of a post to another post
 *
 * @param int     $new_id The new post ID.
 * @param WP_Post $post   The original post object.
 */
function duplicate_post_copy_post_meta_info( $new_id, $post ) {
	$post_meta_keys = get_post_custom_keys( $post->ID );
	if ( empty( $post_meta_keys ) ) {
		return;
	}
	$meta_blacklist = get_option( 'duplicate_post_blacklist' );
	if ( $meta_blacklist === '' ) {
		$meta_blacklist = [];
	}
	else {
		$meta_blacklist = explode( ',', $meta_blacklist );
		$meta_blacklist = array_filter( $meta_blacklist );
		$meta_blacklist = array_map( 'trim', $meta_blacklist );
	}
	$meta_blacklist[] = '_edit_lock'; // Edit lock.
	$meta_blacklist[] = '_edit_last'; // Edit lock.
	$meta_blacklist[] = '_dp_is_rewrite_republish_copy';
	$meta_blacklist[] = '_dp_has_rewrite_republish_copy';
	if ( intval( get_option( 'duplicate_post_copytemplate' ) ) === 0 ) {
		$meta_blacklist[] = '_wp_page_template';
	}
	if ( intval( get_option( 'duplicate_post_copythumbnail' ) ) === 0 ) {
		$meta_blacklist[] = '_thumbnail_id';
	}

	$meta_blacklist = apply_filters_deprecated( 'duplicate_post_blacklist_filter', [ $meta_blacklist ], '3.2.5', 'duplicate_post_excludelist_filter' );

	/**
	 * Filters the meta fields excludelist when copying a post.
	 *
	 * @param array $meta_blacklist The meta fields excludelist from the options.
	 *
	 * @return array
	 */
	$meta_blacklist = apply_filters( 'duplicate_post_excludelist_filter', $meta_blacklist );

	$meta_blacklist_string = '(' . implode( ')|(', $meta_blacklist ) . ')';
	if ( strpos( $meta_blacklist_string, '*' ) !== false ) {
		$meta_blacklist_string = str_replace( [ '*' ], [ '[a-zA-Z0-9_]*' ], $meta_blacklist_string );

		$meta_keys = [];
		foreach ( $post_meta_keys as $meta_key ) {
			if ( ! preg_match( '#^' . $meta_blacklist_string . '$#', $meta_key ) ) {
				$meta_keys[] = $meta_key;
			}
		}
	}
	else {
		$meta_keys = array_diff( $post_meta_keys, $meta_blacklist );
	}

	/**
	 * Filters the list of meta fields names when copying a post.
	 *
	 * @param array $meta_keys The list of meta fields name, with the ones in the excludelist already removed.
	 *
	 * @return array
	 */
	$meta_keys = apply_filters( 'duplicate_post_meta_keys_filter', $meta_keys );

	foreach ( $meta_keys as $meta_key ) {
		$meta_values = get_post_custom_values( $meta_key, $post->ID );
		foreach ( $meta_values as $meta_value ) {
			$meta_value = maybe_unserialize( $meta_value );
			add_post_meta( $new_id, $meta_key, duplicate_post_wp_slash( $meta_value ) );
		}
	}
}

/**
 * Workaround for inconsistent wp_slash.
 * Works only with WP 4.4+ (map_deep)
 *
 * @param mixed $value Array or object to be recursively slashed.
 * @return string|mixed
 */
function duplicate_post_addslashes_deep( $value ) {
	if ( function_exists( 'map_deep' ) ) {
		return map_deep( $value, 'duplicate_post_addslashes_to_strings_only' );
	}
	else {
		return wp_slash( $value );
	}
}

/**
 * Adds slashes only to strings.
 *
 * @param mixed $value Value to slash only if string.
 * @return string|mixed
 */
function duplicate_post_addslashes_to_strings_only( $value ) {
	return Yoast\WP\Duplicate_Post\Utils::addslashes_to_strings_only( $value );
}

/**
 * Replacement function for faulty core wp_slash().
 *
 * @param mixed $value What to add slash to.
 * @return mixed
 */
function duplicate_post_wp_slash( $value ) {
	return duplicate_post_addslashes_deep( $value );
}

/**
 * Copies attachments, including physical files.
 *
 * @param int     $new_id The new post ID.
 * @param WP_Post $post   The original post object.
 */
function duplicate_post_copy_attachments( $new_id, $post ) {
	// Get thumbnail ID.
	$old_thumbnail_id = get_post_thumbnail_id( $post->ID );
	// Get children.
	$children = get_posts(
		[
			'post_type'   => 'any',
			'numberposts' => -1,
			'post_status' => 'any',
			'post_parent' => $post->ID,
		]
	);
	// Clone old attachments.
	foreach ( $children as $child ) {
		if ( $child->post_type !== 'attachment' ) {
			continue;
		}
		$url = wp_get_attachment_url( $child->ID );
		// Let's copy the actual file.
		$tmp = download_url( $url );
		if ( is_wp_error( $tmp ) ) {
			continue;
		}

		$desc = wp_slash( $child->post_content );

		$file_array             = [];
		$file_array['name']     = basename( $url );
		$file_array['tmp_name'] = $tmp;
		// "Upload" to the media collection
		$new_attachment_id = media_handle_sideload( $file_array, $new_id, $desc );

		if ( is_wp_error( $new_attachment_id ) ) {
			unlink( $file_array['tmp_name'] );
			continue;
		}
		$new_post_author = wp_get_current_user();
		$cloned_child    = [
			'ID'           => $new_attachment_id,
			'post_title'   => $child->post_title,
			'post_exceprt' => $child->post_title,
			'post_author'  => $new_post_author->ID,
		];
		wp_update_post( wp_slash( $cloned_child ) );

		$alt_title = get_post_meta( $child->ID, '_wp_attachment_image_alt', true );
		if ( $alt_title ) {
			update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $alt_title ) );
		}

		// If we have cloned the post thumbnail, set the copy as the thumbnail for the new post.
		if ( intval( get_option( 'duplicate_post_copythumbnail' ) ) === 1 && $old_thumbnail_id === $child->ID ) {
			set_post_thumbnail( $new_id, $new_attachment_id );
		}
	}
}

/**
 * Copies child posts.
 *
 * @param int     $new_id The new post ID.
 * @param WP_Post $post   The original post object.
 * @param string  $status Optional. The destination status.
 */
function duplicate_post_copy_children( $new_id, $post, $status = '' ) {
	// Get children.
	$children = get_posts(
		[
			'post_type'   => 'any',
			'numberposts' => -1,
			'post_status' => 'any',
			'post_parent' => $post->ID,
		]
	);

	foreach ( $children as $child ) {
		if ( $child->post_type === 'attachment' ) {
			continue;
		}
		duplicate_post_create_duplicate( $child, $status, $new_id );
	}
}

/**
 * Copies comments.
 *
 * @param int     $new_id The new post ID.
 * @param WP_Post $post   The original post object.
 */
function duplicate_post_copy_comments( $new_id, $post ) {
	$comments = get_comments(
		[
			'post_id' => $post->ID,
			'order'   => 'ASC',
			'orderby' => 'comment_date_gmt',
		]
	);

	$old_id_to_new = [];
	foreach ( $comments as $comment ) {
		// Do not copy pingbacks or trackbacks.
		if ( $comment->comment_type === 'pingback' || $comment->comment_type === 'trackback' ) {
			continue;
		}
		$parent      = ( $comment->comment_parent && $old_id_to_new[ $comment->comment_parent ] ) ? $old_id_to_new[ $comment->comment_parent ] : 0;
		$commentdata = [
			'comment_post_ID'      => $new_id,
			'comment_author'       => $comment->comment_author,
			'comment_author_email' => $comment->comment_author_email,
			'comment_author_url'   => $comment->comment_author_url,
			'comment_content'      => $comment->comment_content,
			'comment_type'         => $comment->comment_type,
			'comment_parent'       => $parent,
			'user_id'              => $comment->user_id,
			'comment_author_IP'    => $comment->comment_author_IP,
			'comment_agent'        => $comment->comment_agent,
			'comment_karma'        => $comment->comment_karma,
			'comment_approved'     => $comment->comment_approved,
		];
		if ( intval( get_option( 'duplicate_post_copydate' ) ) === 1 ) {
			$commentdata['comment_date']     = $comment->comment_date;
			$commentdata['comment_date_gmt'] = get_gmt_from_date( $comment->comment_date );
		}
		$new_comment_id = wp_insert_comment( $commentdata );
		$commentmeta    = get_comment_meta( $new_comment_id );
		foreach ( $commentmeta as $meta_key => $meta_value ) {
			add_comment_meta( $new_comment_id, $meta_key, duplicate_post_wp_slash( $meta_value ) );
		}
		$old_id_to_new[ $comment->comment_ID ] = $new_comment_id;
	}
}

/**
 * Creates a duplicate from a post.
 *
 * This is the main functions that does the cloning.
 *
 * @param WP_Post $post      The original post object.
 * @param string  $status    Optional. The intended destination status.
 * @param string  $parent_id Optional. The parent post ID if we are calling this recursively.
 * @return int|WP_Error
 */
function duplicate_post_create_duplicate( $post, $status = '', $parent_id = '' ) {
	/**
	 * Fires before duplicating a post.
	 *
	 * @param WP_Post $post      The original post object.
	 * @param bool    $status    The intended destination status.
	 * @param int     $parent_id The parent post ID if we are calling this recursively.
	 */
	do_action( 'duplicate_post_pre_copy', $post, $status, $parent_id );

	/**
	 * Filter allowing to copy post.
	 *
	 * @param bool    $can_duplicate Default to `true`.
	 * @param WP_Post $post          The original post object.
	 * @param bool    $status        The intended destination status.
	 * @param int     $parent_id     The parent post ID if we are calling this recursively.
	 *
	 * @return bool
	 */
	$can_duplicate = apply_filters( 'duplicate_post_allow', true, $post, $status, $parent_id );
	if ( ! $can_duplicate ) {
		wp_die( esc_html( __( 'You aren\'t allowed to duplicate this post', 'duplicate-post' ) ) );
	}

	if ( ! duplicate_post_is_post_type_enabled( $post->post_type ) && $post->post_type !== 'attachment' ) {
		wp_die(
			esc_html(
				__( 'Copy features for this post type are not enabled in options page', 'duplicate-post' ) . ': '
				. $post->post_type
			)
		);
	}

	$new_post_status = ( empty( $status ) ) ? $post->post_status : $status;
	$title           = ' ';

	if ( $post->post_type !== 'attachment' ) {
		$prefix = sanitize_text_field( get_option( 'duplicate_post_title_prefix' ) );
		$suffix = sanitize_text_field( get_option( 'duplicate_post_title_suffix' ) );
		if ( intval( get_option( 'duplicate_post_copytitle' ) ) === 1 ) {
			$title = $post->post_title;
			if ( ! empty( $prefix ) ) {
				$prefix .= ' ';
			}
			if ( ! empty( $suffix ) ) {
				$suffix = ' ' . $suffix;
			}
		}
		else {
			$title = ' ';
		}
		$title = trim( $prefix . $title . $suffix );

		/*
		 * Not sure we should force a title. Instead, we should respect what WP does.
		 * if ( '' === $title ) {
		 *  // empty title.
		 *  $title = __( 'Untitled', 'default' );
		 * }
		 */

		if ( intval( get_option( 'duplicate_post_copystatus' ) ) === 0 ) {
			$new_post_status = 'draft';
		}
		elseif ( $new_post_status === 'publish' || $new_post_status === 'future' ) {
			// Check if the user has the right capability.
			if ( is_post_type_hierarchical( $post->post_type ) ) {
				if ( ! current_user_can( 'publish_pages' ) ) {
					$new_post_status = 'pending';
				}
			}
			elseif ( ! current_user_can( 'publish_posts' ) ) {
				$new_post_status = 'pending';
			}
		}
	}

	$new_post_author    = wp_get_current_user();
	$new_post_author_id = $new_post_author->ID;
	if ( intval( get_option( 'duplicate_post_copyauthor' ) ) === 1 ) {
		// Check if the user has the right capability.
		if ( is_post_type_hierarchical( $post->post_type ) ) {
			if ( current_user_can( 'edit_others_pages' ) ) {
				$new_post_author_id = $post->post_author;
			}
		}
		elseif ( current_user_can( 'edit_others_posts' ) ) {
			$new_post_author_id = $post->post_author;
		}
	}

	$menu_order             = ( intval( get_option( 'duplicate_post_copymenuorder' ) ) === 1 ) ? $post->menu_order : 0;
	$increase_menu_order_by = get_option( 'duplicate_post_increase_menu_order_by' );
	if ( ! empty( $increase_menu_order_by ) && is_numeric( $increase_menu_order_by ) ) {
		$menu_order += intval( $increase_menu_order_by );
	}

	$post_name = $post->post_name;
	if ( intval( get_option( 'duplicate_post_copyslug' ) ) !== 1 ) {
		$post_name = '';
	}
	$new_post_parent = empty( $parent_id ) ? $post->post_parent : $parent_id;

	$new_post = [
		'menu_order'            => $menu_order,
		'comment_status'        => $post->comment_status,
		'ping_status'           => $post->ping_status,
		'post_author'           => $new_post_author_id,
		'post_content'          => ( intval( get_option( 'duplicate_post_copycontent' ) ) === 1 ) ? $post->post_content : '',
		'post_content_filtered' => ( intval( get_option( 'duplicate_post_copycontent' ) ) === 1 ) ? $post->post_content_filtered : '',
		'post_excerpt'          => ( intval( get_option( 'duplicate_post_copyexcerpt' ) ) === 1 ) ? $post->post_excerpt : '',
		'post_mime_type'        => $post->post_mime_type,
		'post_parent'           => $new_post_parent,
		'post_password'         => ( intval( get_option( 'duplicate_post_copypassword' ) ) === 1 ) ? $post->post_password : '',
		'post_status'           => $new_post_status,
		'post_title'            => $title,
		'post_type'             => $post->post_type,
		'post_name'             => $post_name,
	];

	if ( intval( get_option( 'duplicate_post_copydate' ) ) === 1 ) {
		$new_post_date             = $post->post_date;
		$new_post['post_date']     = $new_post_date;
		$new_post['post_date_gmt'] = get_gmt_from_date( $new_post_date );
	}

	/**
	 * Filter new post values.
	 *
	 * @param array   $new_post New post values.
	 * @param WP_Post $post     Original post object.
	 *
	 * @return array
	 */
	$new_post    = apply_filters( 'duplicate_post_new_post', $new_post, $post );
	$new_post_id = wp_insert_post( wp_slash( $new_post ), true );

	// If you have written a plugin which uses non-WP database tables to save
	// information about a post you can hook this action to dupe that data.
	if ( $new_post_id !== 0 && ! is_wp_error( $new_post_id ) ) {

		if ( $post->post_type === 'page' || is_post_type_hierarchical( $post->post_type ) ) {
			do_action( 'dp_duplicate_page', $new_post_id, $post, $status );
		}
		else {
			do_action( 'dp_duplicate_post', $new_post_id, $post, $status );
		}

		delete_post_meta( $new_post_id, '_dp_original' );
		add_post_meta( $new_post_id, '_dp_original', $post->ID );
	}

	/**
	 * Fires after duplicating a post.
	 *
	 * @param int|WP_Error $new_post_id The new post id or WP_Error object on error.
	 * @param WP_Post      $post        The original post object.
	 * @param bool         $status      The intended destination status.
	 * @param int          $parent_id   The parent post ID if we are calling this recursively.
	 */
	do_action( 'duplicate_post_post_copy', $new_post_id, $post, $status, $parent_id );

	return $new_post_id;
}

/**
 * Adds some links on the plugin page.
 *
 * @param array  $links The links array.
 * @param string $file  The file name.
 * @return array
 */
function duplicate_post_add_plugin_links( $links, $file ) {
	if ( plugin_basename( __DIR__ . '/duplicate-post.php' ) === $file ) {
		$links[] = '<a href="https://yoast.com/wordpress/plugins/duplicate-post">' . esc_html__( 'Documentation', 'duplicate-post' ) . '</a>';
	}
	return $links;
}
PK!(�B��vendor/autoload.phpnu�[���<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit54f1369b9135ce2e1472c9945cacd03c::getLoader();
PK!t�!ו�'vendor/composer/autoload_namespaces.phpnu�[���<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
);
PK!�5Ky�>�>vendor/composer/ClassLoader.phpnu�[���<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var ?string */
    private $vendorDir;

    // PSR-4
    /**
     * @var array[]
     * @psalm-var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array[]
     * @psalm-var array<string, array<int, string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var array[]
     * @psalm-var array<string, string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * @var array[]
     * @psalm-var array<string, array<string, string[]>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var array[]
     * @psalm-var array<string, string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var string[]
     * @psalm-var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var bool[]
     * @psalm-var array<string, bool>
     */
    private $missingClasses = array();

    /** @var ?string */
    private $apcuPrefix;

    /**
     * @var self[]
     */
    private static $registeredLoaders = array();

    /**
     * @param ?string $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
    }

    /**
     * @return string[]
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array[]
     * @psalm-return array<string, array<int, string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return array[]
     * @psalm-return array<string, string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return array[]
     * @psalm-return array<string, string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return string[] Array of classname => path
     * @psalm-return array<string, string>
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param string[] $classMap Class to filename map
     * @psalm-param array<string, string> $classMap
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string          $prefix  The prefix
     * @param string[]|string $paths   The PSR-0 root directories
     * @param bool            $prepend Whether to prepend the directories
     *
     * @return void
     */
    public function add($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    (array) $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = (array) $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                (array) $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string          $prefix  The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths   The PSR-4 base directories
     * @param bool            $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    (array) $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                (array) $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string          $prefix The prefix
     * @param string[]|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string          $prefix The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders indexed by their corresponding vendor directories.
     *
     * @return self[]
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }
}

/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 *
 * @param  string $file
 * @return void
 * @private
 */
function includeFile($file)
{
    include $file;
}
PK!)Ϥ�7J7J#vendor/composer/autoload_static.phpnu�[���<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInit54f1369b9135ce2e1472c9945cacd03c
{
    public static $prefixLengthsPsr4 = array (
        'C' => 
        array (
            'Composer\\Installers\\' => 20,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'Composer\\Installers\\' => 
        array (
            0 => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers',
        ),
    );

    public static $classMap = array (
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
        'Composer\\Installers\\AglInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AglInstaller.php',
        'Composer\\Installers\\AimeosInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AimeosInstaller.php',
        'Composer\\Installers\\AnnotateCmsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php',
        'Composer\\Installers\\AsgardInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AsgardInstaller.php',
        'Composer\\Installers\\AttogramInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/AttogramInstaller.php',
        'Composer\\Installers\\BaseInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/BaseInstaller.php',
        'Composer\\Installers\\BitrixInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/BitrixInstaller.php',
        'Composer\\Installers\\BonefishInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/BonefishInstaller.php',
        'Composer\\Installers\\CakePHPInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CakePHPInstaller.php',
        'Composer\\Installers\\ChefInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ChefInstaller.php',
        'Composer\\Installers\\CiviCrmInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CiviCrmInstaller.php',
        'Composer\\Installers\\ClanCatsFrameworkInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php',
        'Composer\\Installers\\CockpitInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CockpitInstaller.php',
        'Composer\\Installers\\CodeIgniterInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php',
        'Composer\\Installers\\Concrete5Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Concrete5Installer.php',
        'Composer\\Installers\\CraftInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CraftInstaller.php',
        'Composer\\Installers\\CroogoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/CroogoInstaller.php',
        'Composer\\Installers\\DecibelInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DecibelInstaller.php',
        'Composer\\Installers\\DframeInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DframeInstaller.php',
        'Composer\\Installers\\DokuWikiInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DokuWikiInstaller.php',
        'Composer\\Installers\\DolibarrInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DolibarrInstaller.php',
        'Composer\\Installers\\DrupalInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/DrupalInstaller.php',
        'Composer\\Installers\\ElggInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ElggInstaller.php',
        'Composer\\Installers\\EliasisInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/EliasisInstaller.php',
        'Composer\\Installers\\ExpressionEngineInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php',
        'Composer\\Installers\\EzPlatformInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/EzPlatformInstaller.php',
        'Composer\\Installers\\FuelInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/FuelInstaller.php',
        'Composer\\Installers\\FuelphpInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/FuelphpInstaller.php',
        'Composer\\Installers\\GravInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/GravInstaller.php',
        'Composer\\Installers\\HuradInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/HuradInstaller.php',
        'Composer\\Installers\\ImageCMSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ImageCMSInstaller.php',
        'Composer\\Installers\\Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Installer.php',
        'Composer\\Installers\\ItopInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ItopInstaller.php',
        'Composer\\Installers\\JoomlaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/JoomlaInstaller.php',
        'Composer\\Installers\\KanboardInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KanboardInstaller.php',
        'Composer\\Installers\\KirbyInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KirbyInstaller.php',
        'Composer\\Installers\\KnownInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KnownInstaller.php',
        'Composer\\Installers\\KodiCMSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KodiCMSInstaller.php',
        'Composer\\Installers\\KohanaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/KohanaInstaller.php',
        'Composer\\Installers\\LanManagementSystemInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php',
        'Composer\\Installers\\LaravelInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LaravelInstaller.php',
        'Composer\\Installers\\LavaLiteInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LavaLiteInstaller.php',
        'Composer\\Installers\\LithiumInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/LithiumInstaller.php',
        'Composer\\Installers\\MODULEWorkInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php',
        'Composer\\Installers\\MODXEvoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MODXEvoInstaller.php',
        'Composer\\Installers\\MagentoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MagentoInstaller.php',
        'Composer\\Installers\\MajimaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MajimaInstaller.php',
        'Composer\\Installers\\MakoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MakoInstaller.php',
        'Composer\\Installers\\MantisBTInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MantisBTInstaller.php',
        'Composer\\Installers\\MauticInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MauticInstaller.php',
        'Composer\\Installers\\MayaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MayaInstaller.php',
        'Composer\\Installers\\MediaWikiInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MediaWikiInstaller.php',
        'Composer\\Installers\\MiaoxingInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MiaoxingInstaller.php',
        'Composer\\Installers\\MicroweberInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MicroweberInstaller.php',
        'Composer\\Installers\\ModxInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ModxInstaller.php',
        'Composer\\Installers\\MoodleInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/MoodleInstaller.php',
        'Composer\\Installers\\OctoberInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OctoberInstaller.php',
        'Composer\\Installers\\OntoWikiInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OntoWikiInstaller.php',
        'Composer\\Installers\\OsclassInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OsclassInstaller.php',
        'Composer\\Installers\\OxidInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/OxidInstaller.php',
        'Composer\\Installers\\PPIInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PPIInstaller.php',
        'Composer\\Installers\\PantheonInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PantheonInstaller.php',
        'Composer\\Installers\\PhiftyInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PhiftyInstaller.php',
        'Composer\\Installers\\PhpBBInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PhpBBInstaller.php',
        'Composer\\Installers\\PimcoreInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PimcoreInstaller.php',
        'Composer\\Installers\\PiwikInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PiwikInstaller.php',
        'Composer\\Installers\\PlentymarketsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php',
        'Composer\\Installers\\Plugin' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Plugin.php',
        'Composer\\Installers\\PortoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PortoInstaller.php',
        'Composer\\Installers\\PrestashopInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PrestashopInstaller.php',
        'Composer\\Installers\\ProcessWireInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ProcessWireInstaller.php',
        'Composer\\Installers\\PuppetInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PuppetInstaller.php',
        'Composer\\Installers\\PxcmsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/PxcmsInstaller.php',
        'Composer\\Installers\\RadPHPInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/RadPHPInstaller.php',
        'Composer\\Installers\\ReIndexInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ReIndexInstaller.php',
        'Composer\\Installers\\Redaxo5Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Redaxo5Installer.php',
        'Composer\\Installers\\RedaxoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/RedaxoInstaller.php',
        'Composer\\Installers\\RoundcubeInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/RoundcubeInstaller.php',
        'Composer\\Installers\\SMFInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SMFInstaller.php',
        'Composer\\Installers\\ShopwareInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ShopwareInstaller.php',
        'Composer\\Installers\\SilverStripeInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SilverStripeInstaller.php',
        'Composer\\Installers\\SiteDirectInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SiteDirectInstaller.php',
        'Composer\\Installers\\StarbugInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/StarbugInstaller.php',
        'Composer\\Installers\\SyDESInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SyDESInstaller.php',
        'Composer\\Installers\\SyliusInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/SyliusInstaller.php',
        'Composer\\Installers\\Symfony1Installer' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/Symfony1Installer.php',
        'Composer\\Installers\\TYPO3CmsInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php',
        'Composer\\Installers\\TYPO3FlowInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php',
        'Composer\\Installers\\TaoInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TaoInstaller.php',
        'Composer\\Installers\\TastyIgniterInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php',
        'Composer\\Installers\\TheliaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TheliaInstaller.php',
        'Composer\\Installers\\TuskInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/TuskInstaller.php',
        'Composer\\Installers\\UserFrostingInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/UserFrostingInstaller.php',
        'Composer\\Installers\\VanillaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/VanillaInstaller.php',
        'Composer\\Installers\\VgmcpInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/VgmcpInstaller.php',
        'Composer\\Installers\\WHMCSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WHMCSInstaller.php',
        'Composer\\Installers\\WinterInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WinterInstaller.php',
        'Composer\\Installers\\WolfCMSInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WolfCMSInstaller.php',
        'Composer\\Installers\\WordPressInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/WordPressInstaller.php',
        'Composer\\Installers\\YawikInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/YawikInstaller.php',
        'Composer\\Installers\\ZendInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ZendInstaller.php',
        'Composer\\Installers\\ZikulaInstaller' => __DIR__ . '/..' . '/composer/installers/src/Composer/Installers/ZikulaInstaller.php',
        'Yoast\\WP\\Duplicate_Post\\Admin\\Options' => __DIR__ . '/../..' . '/src/admin/options.php',
        'Yoast\\WP\\Duplicate_Post\\Admin\\Options_Form_Generator' => __DIR__ . '/../..' . '/src/admin/options-form-generator.php',
        'Yoast\\WP\\Duplicate_Post\\Admin\\Options_Inputs' => __DIR__ . '/../..' . '/src/admin/options-inputs.php',
        'Yoast\\WP\\Duplicate_Post\\Admin\\Options_Page' => __DIR__ . '/../..' . '/src/admin/options-page.php',
        'Yoast\\WP\\Duplicate_Post\\Duplicate_Post' => __DIR__ . '/../..' . '/src/duplicate-post.php',
        'Yoast\\WP\\Duplicate_Post\\Handlers\\Bulk_Handler' => __DIR__ . '/../..' . '/src/handlers/bulk-handler.php',
        'Yoast\\WP\\Duplicate_Post\\Handlers\\Check_Changes_Handler' => __DIR__ . '/../..' . '/src/handlers/check-changes-handler.php',
        'Yoast\\WP\\Duplicate_Post\\Handlers\\Handler' => __DIR__ . '/../..' . '/src/handlers/handler.php',
        'Yoast\\WP\\Duplicate_Post\\Handlers\\Link_Handler' => __DIR__ . '/../..' . '/src/handlers/link-handler.php',
        'Yoast\\WP\\Duplicate_Post\\Handlers\\Save_Post_Handler' => __DIR__ . '/../..' . '/src/handlers/save-post-handler.php',
        'Yoast\\WP\\Duplicate_Post\\Permissions_Helper' => __DIR__ . '/../..' . '/src/permissions-helper.php',
        'Yoast\\WP\\Duplicate_Post\\Post_Duplicator' => __DIR__ . '/../..' . '/src/post-duplicator.php',
        'Yoast\\WP\\Duplicate_Post\\Post_Republisher' => __DIR__ . '/../..' . '/src/post-republisher.php',
        'Yoast\\WP\\Duplicate_Post\\Revisions_Migrator' => __DIR__ . '/../..' . '/src/revisions-migrator.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Admin_Bar' => __DIR__ . '/../..' . '/src/ui/admin-bar.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Asset_Manager' => __DIR__ . '/../..' . '/src/ui/asset-manager.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Block_Editor' => __DIR__ . '/../..' . '/src/ui/block-editor.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Bulk_Actions' => __DIR__ . '/../..' . '/src/ui/bulk-actions.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Classic_Editor' => __DIR__ . '/../..' . '/src/ui/classic-editor.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Column' => __DIR__ . '/../..' . '/src/ui/column.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Link_Builder' => __DIR__ . '/../..' . '/src/ui/link-builder.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Metabox' => __DIR__ . '/../..' . '/src/ui/metabox.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Newsletter' => __DIR__ . '/../..' . '/src/ui/newsletter.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Post_States' => __DIR__ . '/../..' . '/src/ui/post-states.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\Row_Actions' => __DIR__ . '/../..' . '/src/ui/row-actions.php',
        'Yoast\\WP\\Duplicate_Post\\UI\\User_Interface' => __DIR__ . '/../..' . '/src/ui/user-interface.php',
        'Yoast\\WP\\Duplicate_Post\\Utils' => __DIR__ . '/../..' . '/src/utils.php',
        'Yoast\\WP\\Duplicate_Post\\Watchers\\Bulk_Actions_Watcher' => __DIR__ . '/../..' . '/src/watchers/bulk-actions-watcher.php',
        'Yoast\\WP\\Duplicate_Post\\Watchers\\Copied_Post_Watcher' => __DIR__ . '/../..' . '/src/watchers/copied-post-watcher.php',
        'Yoast\\WP\\Duplicate_Post\\Watchers\\Link_Actions_Watcher' => __DIR__ . '/../..' . '/src/watchers/link-actions-watcher.php',
        'Yoast\\WP\\Duplicate_Post\\Watchers\\Original_Post_Watcher' => __DIR__ . '/../..' . '/src/watchers/original-post-watcher.php',
        'Yoast\\WP\\Duplicate_Post\\Watchers\\Republished_Post_Watcher' => __DIR__ . '/../..' . '/src/watchers/republished-post-watcher.php',
        'Yoast\\WP\\Duplicate_Post\\Watchers\\Watchers' => __DIR__ . '/../..' . '/src/watchers/watchers.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInit54f1369b9135ce2e1472c9945cacd03c::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit54f1369b9135ce2e1472c9945cacd03c::$prefixDirsPsr4;
            $loader->classMap = ComposerStaticInit54f1369b9135ce2e1472c9945cacd03c::$classMap;

        }, null, ClassLoader::class);
    }
}
PK!�����vendor/composer/installed.phpnu�[���<?php return array(
    'root' => array(
        'pretty_version' => 'dev-master',
        'version' => 'dev-master',
        'type' => 'wordpress-plugin',
        'install_path' => __DIR__ . '/../../',
        'aliases' => array(),
        'reference' => '66efa2fa0d3b8a0b3af956da9385531f2b6e1ae7',
        'name' => 'yoast/duplicate-post',
        'dev' => false,
    ),
    'versions' => array(
        'composer/installers' => array(
            'pretty_version' => 'v1.12.0',
            'version' => '1.12.0.0',
            'type' => 'composer-plugin',
            'install_path' => __DIR__ . '/./installers',
            'aliases' => array(),
            'reference' => 'd20a64ed3c94748397ff5973488761b22f6d3f19',
            'dev_requirement' => false,
        ),
        'roundcube/plugin-installer' => array(
            'dev_requirement' => false,
            'replaced' => array(
                0 => '*',
            ),
        ),
        'shama/baton' => array(
            'dev_requirement' => false,
            'replaced' => array(
                0 => '*',
            ),
        ),
        'yoast/duplicate-post' => array(
            'pretty_version' => 'dev-master',
            'version' => 'dev-master',
            'type' => 'wordpress-plugin',
            'install_path' => __DIR__ . '/../../',
            'aliases' => array(),
            'reference' => '66efa2fa0d3b8a0b3af956da9385531f2b6e1ae7',
            'dev_requirement' => false,
        ),
    ),
);
PK!;�S22!vendor/composer/autoload_real.phpnu�[���<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit54f1369b9135ce2e1472c9945cacd03c
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        require __DIR__ . '/platform_check.php';

        spl_autoload_register(array('ComposerAutoloaderInit54f1369b9135ce2e1472c9945cacd03c', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
        spl_autoload_unregister(array('ComposerAutoloaderInit54f1369b9135ce2e1472c9945cacd03c', 'loadClassLoader'));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInit54f1369b9135ce2e1472c9945cacd03c::getInitializer($loader));
        } else {
            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->setClassMapAuthoritative(true);
        $loader->register(true);

        return $loader;
    }
}
PK!T��t��"vendor/composer/platform_check.phpnu�[���<?php

// platform_check.php @generated by Composer

$issues = array();

if (!(PHP_VERSION_ID >= 50600)) {
    $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.';
}

if ($issues) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
        } elseif (!headers_sent()) {
            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
        }
    }
    trigger_error(
        'Composer detected issues in your platform: ' . implode(' ', $issues),
        E_USER_ERROR
    );
}
PK! �..vendor/composer/LICENSEnu�[���
Copyright (c) Nils Adermann, Jordi Boggiano

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

PK!+|i��!vendor/composer/autoload_psr4.phpnu�[���<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Composer\\Installers\\' => array($vendorDir . '/composer/installers/src/Composer/Installers'),
);
PK!T��"�:�:%vendor/composer/InstalledVersions.phpnu�[���<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer;

use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;

/**
 * This class is copied in every Composer installed project and available to all
 *
 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
 *
 * To require its presence, you can require `composer-runtime-api ^2.0`
 */
class InstalledVersions
{
    /**
     * @var mixed[]|null
     * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
     */
    private static $installed;

    /**
     * @var bool|null
     */
    private static $canGetVendors;

    /**
     * @var array[]
     * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
     */
    private static $installedByVendor = array();

    /**
     * Returns a list of all package names which are present, either by being installed, replaced or provided
     *
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = array_keys($installed['versions']);
        }

        if (1 === \count($packages)) {
            return $packages[0];
        }

        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
    }

    /**
     * Returns a list of all package names with a specific type e.g. 'library'
     *
     * @param  string   $type
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();

        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }

        return $packagesByType;
    }

    /**
     * Checks whether the given package is installed
     *
     * This also returns true if the package name is provided or replaced by another package
     *
     * @param  string $packageName
     * @param  bool   $includeDevRequirements
     * @return bool
     */
    public static function isInstalled($packageName, $includeDevRequirements = true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
            }
        }

        return false;
    }

    /**
     * Checks whether the given package satisfies a version constraint
     *
     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
     *
     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
     *
     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
     * @param  string        $packageName
     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
     * @return bool
     */
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints($constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));

        return $provided->matches($constraint);
    }

    /**
     * Returns a version constraint representing all the range(s) which are installed for a given package
     *
     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
     * whether a given version of a package is installed, and not just whether it exists
     *
     * @param  string $packageName
     * @return string Version constraint usable with composer/semver
     */
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }

            return implode(' || ', $ranges);
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['pretty_version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
     */
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }

            return $installed['versions'][$packageName]['reference'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
     */
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @return array
     * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
     */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();

        return $installed[0]['root'];
    }

    /**
     * Returns the raw installed.php data for custom implementations
     *
     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
     * @return array[]
     * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
     */
    public static function getRawData()
    {
        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = include __DIR__ . '/installed.php';
            } else {
                self::$installed = array();
            }
        }

        return self::$installed;
    }

    /**
     * Returns the raw data of all installed.php which are currently loaded for custom implementations
     *
     * @return array[]
     * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
     */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }

    /**
     * Lets you reload the static array from another file
     *
     * This is only useful for complex integrations in which a project needs to use
     * this class but then also needs to execute another project's autoloader in process,
     * and wants to ensure both projects have access to their version of installed.php.
     *
     * A typical case would be PHPUnit, where it would need to make sure it reads all
     * the data it needs from this class, then call reload() with
     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
     * the project in which it runs can then also use this class safely, without
     * interference between PHPUnit's dependencies and the project's dependencies.
     *
     * @param  array[] $data A vendor/composer/installed.php data set
     * @return void
     *
     * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
     */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();
    }

    /**
     * @return array[]
     * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
     */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
        }

        $installed = array();

        if (self::$canGetVendors) {
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (is_file($vendorDir.'/composer/installed.php')) {
                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
                        self::$installed = $installed[count($installed) - 1];
                    }
                }
            }
        }

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = require __DIR__ . '/installed.php';
            } else {
                self::$installed = array();
            }
        }
        $installed[] = self::$installed;

        return $installed;
    }
}
PK!�+6�bAbA%vendor/composer/autoload_classmap.phpnu�[���<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    'Composer\\Installers\\AglInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AglInstaller.php',
    'Composer\\Installers\\AimeosInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AimeosInstaller.php',
    'Composer\\Installers\\AnnotateCmsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php',
    'Composer\\Installers\\AsgardInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AsgardInstaller.php',
    'Composer\\Installers\\AttogramInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/AttogramInstaller.php',
    'Composer\\Installers\\BaseInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/BaseInstaller.php',
    'Composer\\Installers\\BitrixInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/BitrixInstaller.php',
    'Composer\\Installers\\BonefishInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/BonefishInstaller.php',
    'Composer\\Installers\\CakePHPInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CakePHPInstaller.php',
    'Composer\\Installers\\ChefInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ChefInstaller.php',
    'Composer\\Installers\\CiviCrmInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CiviCrmInstaller.php',
    'Composer\\Installers\\ClanCatsFrameworkInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php',
    'Composer\\Installers\\CockpitInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CockpitInstaller.php',
    'Composer\\Installers\\CodeIgniterInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php',
    'Composer\\Installers\\Concrete5Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Concrete5Installer.php',
    'Composer\\Installers\\CraftInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CraftInstaller.php',
    'Composer\\Installers\\CroogoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/CroogoInstaller.php',
    'Composer\\Installers\\DecibelInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DecibelInstaller.php',
    'Composer\\Installers\\DframeInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DframeInstaller.php',
    'Composer\\Installers\\DokuWikiInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DokuWikiInstaller.php',
    'Composer\\Installers\\DolibarrInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DolibarrInstaller.php',
    'Composer\\Installers\\DrupalInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/DrupalInstaller.php',
    'Composer\\Installers\\ElggInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ElggInstaller.php',
    'Composer\\Installers\\EliasisInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/EliasisInstaller.php',
    'Composer\\Installers\\ExpressionEngineInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php',
    'Composer\\Installers\\EzPlatformInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/EzPlatformInstaller.php',
    'Composer\\Installers\\FuelInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/FuelInstaller.php',
    'Composer\\Installers\\FuelphpInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/FuelphpInstaller.php',
    'Composer\\Installers\\GravInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/GravInstaller.php',
    'Composer\\Installers\\HuradInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/HuradInstaller.php',
    'Composer\\Installers\\ImageCMSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ImageCMSInstaller.php',
    'Composer\\Installers\\Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Installer.php',
    'Composer\\Installers\\ItopInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ItopInstaller.php',
    'Composer\\Installers\\JoomlaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/JoomlaInstaller.php',
    'Composer\\Installers\\KanboardInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KanboardInstaller.php',
    'Composer\\Installers\\KirbyInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KirbyInstaller.php',
    'Composer\\Installers\\KnownInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KnownInstaller.php',
    'Composer\\Installers\\KodiCMSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KodiCMSInstaller.php',
    'Composer\\Installers\\KohanaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/KohanaInstaller.php',
    'Composer\\Installers\\LanManagementSystemInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php',
    'Composer\\Installers\\LaravelInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LaravelInstaller.php',
    'Composer\\Installers\\LavaLiteInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LavaLiteInstaller.php',
    'Composer\\Installers\\LithiumInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/LithiumInstaller.php',
    'Composer\\Installers\\MODULEWorkInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php',
    'Composer\\Installers\\MODXEvoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MODXEvoInstaller.php',
    'Composer\\Installers\\MagentoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MagentoInstaller.php',
    'Composer\\Installers\\MajimaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MajimaInstaller.php',
    'Composer\\Installers\\MakoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MakoInstaller.php',
    'Composer\\Installers\\MantisBTInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MantisBTInstaller.php',
    'Composer\\Installers\\MauticInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MauticInstaller.php',
    'Composer\\Installers\\MayaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MayaInstaller.php',
    'Composer\\Installers\\MediaWikiInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MediaWikiInstaller.php',
    'Composer\\Installers\\MiaoxingInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MiaoxingInstaller.php',
    'Composer\\Installers\\MicroweberInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MicroweberInstaller.php',
    'Composer\\Installers\\ModxInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ModxInstaller.php',
    'Composer\\Installers\\MoodleInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/MoodleInstaller.php',
    'Composer\\Installers\\OctoberInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OctoberInstaller.php',
    'Composer\\Installers\\OntoWikiInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OntoWikiInstaller.php',
    'Composer\\Installers\\OsclassInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OsclassInstaller.php',
    'Composer\\Installers\\OxidInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/OxidInstaller.php',
    'Composer\\Installers\\PPIInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PPIInstaller.php',
    'Composer\\Installers\\PantheonInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PantheonInstaller.php',
    'Composer\\Installers\\PhiftyInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PhiftyInstaller.php',
    'Composer\\Installers\\PhpBBInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PhpBBInstaller.php',
    'Composer\\Installers\\PimcoreInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PimcoreInstaller.php',
    'Composer\\Installers\\PiwikInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PiwikInstaller.php',
    'Composer\\Installers\\PlentymarketsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php',
    'Composer\\Installers\\Plugin' => $vendorDir . '/composer/installers/src/Composer/Installers/Plugin.php',
    'Composer\\Installers\\PortoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PortoInstaller.php',
    'Composer\\Installers\\PrestashopInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PrestashopInstaller.php',
    'Composer\\Installers\\ProcessWireInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ProcessWireInstaller.php',
    'Composer\\Installers\\PuppetInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PuppetInstaller.php',
    'Composer\\Installers\\PxcmsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/PxcmsInstaller.php',
    'Composer\\Installers\\RadPHPInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/RadPHPInstaller.php',
    'Composer\\Installers\\ReIndexInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ReIndexInstaller.php',
    'Composer\\Installers\\Redaxo5Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Redaxo5Installer.php',
    'Composer\\Installers\\RedaxoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/RedaxoInstaller.php',
    'Composer\\Installers\\RoundcubeInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/RoundcubeInstaller.php',
    'Composer\\Installers\\SMFInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SMFInstaller.php',
    'Composer\\Installers\\ShopwareInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ShopwareInstaller.php',
    'Composer\\Installers\\SilverStripeInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SilverStripeInstaller.php',
    'Composer\\Installers\\SiteDirectInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SiteDirectInstaller.php',
    'Composer\\Installers\\StarbugInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/StarbugInstaller.php',
    'Composer\\Installers\\SyDESInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SyDESInstaller.php',
    'Composer\\Installers\\SyliusInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/SyliusInstaller.php',
    'Composer\\Installers\\Symfony1Installer' => $vendorDir . '/composer/installers/src/Composer/Installers/Symfony1Installer.php',
    'Composer\\Installers\\TYPO3CmsInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php',
    'Composer\\Installers\\TYPO3FlowInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php',
    'Composer\\Installers\\TaoInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TaoInstaller.php',
    'Composer\\Installers\\TastyIgniterInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TastyIgniterInstaller.php',
    'Composer\\Installers\\TheliaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TheliaInstaller.php',
    'Composer\\Installers\\TuskInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/TuskInstaller.php',
    'Composer\\Installers\\UserFrostingInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/UserFrostingInstaller.php',
    'Composer\\Installers\\VanillaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/VanillaInstaller.php',
    'Composer\\Installers\\VgmcpInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/VgmcpInstaller.php',
    'Composer\\Installers\\WHMCSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WHMCSInstaller.php',
    'Composer\\Installers\\WinterInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WinterInstaller.php',
    'Composer\\Installers\\WolfCMSInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WolfCMSInstaller.php',
    'Composer\\Installers\\WordPressInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/WordPressInstaller.php',
    'Composer\\Installers\\YawikInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/YawikInstaller.php',
    'Composer\\Installers\\ZendInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ZendInstaller.php',
    'Composer\\Installers\\ZikulaInstaller' => $vendorDir . '/composer/installers/src/Composer/Installers/ZikulaInstaller.php',
    'Yoast\\WP\\Duplicate_Post\\Admin\\Options' => $baseDir . '/src/admin/options.php',
    'Yoast\\WP\\Duplicate_Post\\Admin\\Options_Form_Generator' => $baseDir . '/src/admin/options-form-generator.php',
    'Yoast\\WP\\Duplicate_Post\\Admin\\Options_Inputs' => $baseDir . '/src/admin/options-inputs.php',
    'Yoast\\WP\\Duplicate_Post\\Admin\\Options_Page' => $baseDir . '/src/admin/options-page.php',
    'Yoast\\WP\\Duplicate_Post\\Duplicate_Post' => $baseDir . '/src/duplicate-post.php',
    'Yoast\\WP\\Duplicate_Post\\Handlers\\Bulk_Handler' => $baseDir . '/src/handlers/bulk-handler.php',
    'Yoast\\WP\\Duplicate_Post\\Handlers\\Check_Changes_Handler' => $baseDir . '/src/handlers/check-changes-handler.php',
    'Yoast\\WP\\Duplicate_Post\\Handlers\\Handler' => $baseDir . '/src/handlers/handler.php',
    'Yoast\\WP\\Duplicate_Post\\Handlers\\Link_Handler' => $baseDir . '/src/handlers/link-handler.php',
    'Yoast\\WP\\Duplicate_Post\\Handlers\\Save_Post_Handler' => $baseDir . '/src/handlers/save-post-handler.php',
    'Yoast\\WP\\Duplicate_Post\\Permissions_Helper' => $baseDir . '/src/permissions-helper.php',
    'Yoast\\WP\\Duplicate_Post\\Post_Duplicator' => $baseDir . '/src/post-duplicator.php',
    'Yoast\\WP\\Duplicate_Post\\Post_Republisher' => $baseDir . '/src/post-republisher.php',
    'Yoast\\WP\\Duplicate_Post\\Revisions_Migrator' => $baseDir . '/src/revisions-migrator.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Admin_Bar' => $baseDir . '/src/ui/admin-bar.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Asset_Manager' => $baseDir . '/src/ui/asset-manager.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Block_Editor' => $baseDir . '/src/ui/block-editor.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Bulk_Actions' => $baseDir . '/src/ui/bulk-actions.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Classic_Editor' => $baseDir . '/src/ui/classic-editor.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Column' => $baseDir . '/src/ui/column.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Link_Builder' => $baseDir . '/src/ui/link-builder.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Metabox' => $baseDir . '/src/ui/metabox.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Newsletter' => $baseDir . '/src/ui/newsletter.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Post_States' => $baseDir . '/src/ui/post-states.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\Row_Actions' => $baseDir . '/src/ui/row-actions.php',
    'Yoast\\WP\\Duplicate_Post\\UI\\User_Interface' => $baseDir . '/src/ui/user-interface.php',
    'Yoast\\WP\\Duplicate_Post\\Utils' => $baseDir . '/src/utils.php',
    'Yoast\\WP\\Duplicate_Post\\Watchers\\Bulk_Actions_Watcher' => $baseDir . '/src/watchers/bulk-actions-watcher.php',
    'Yoast\\WP\\Duplicate_Post\\Watchers\\Copied_Post_Watcher' => $baseDir . '/src/watchers/copied-post-watcher.php',
    'Yoast\\WP\\Duplicate_Post\\Watchers\\Link_Actions_Watcher' => $baseDir . '/src/watchers/link-actions-watcher.php',
    'Yoast\\WP\\Duplicate_Post\\Watchers\\Original_Post_Watcher' => $baseDir . '/src/watchers/original-post-watcher.php',
    'Yoast\\WP\\Duplicate_Post\\Watchers\\Republished_Post_Watcher' => $baseDir . '/src/watchers/republished-post-watcher.php',
    'Yoast\\WP\\Duplicate_Post\\Watchers\\Watchers' => $baseDir . '/src/watchers/watchers.php',
);
PK!�C�\kIkI%duplicate_post_yoast_icon-125x125.pngnu�[����PNG


IHDR}}��l%*8zTXtRaw profile type exifxڭ�ird����s��a�x���V�����U�*)��s�V�
����ެ�R�h�Z�x�4�bğ}��L|���F��?,������������m��B�׻��~?��?.�~��z����B���<�/��|�X��~�z��k����F����R�9����w�?���ƿ);�1�L>+�����x���_w�4�cs�~?�
 ����<�ua���ҵ�?����9��޿?��#|���q���ڿ��Z��V��_&��__�>�J���w�{�{F����W����zaZ�}Ÿ_����_^�{��^����5%������}%-K��B�~��*��&�u�L�??<j�;��ի�K?���wj}K��w��������lpˉ�	V�u�\ߚͤ4��kk֓��e+��Z�9��SM/����Q{ü�i�#sKj5��R��V���{��� �7������T�s��+��h�>;C���1\r�)S�ef��3��k��}/�3�FC����vx��js�~�Χ�S_̥Uf${YI�9��kZ\�l̬�6[6Z��n���b,e�RC*�	��{��Ɠ�.��n����i�9�M��B��{X]��kNi�Y�ih�w�bm�]׶���=y�ɼ�X��F��f]o;c��7K�J�a��k|�q�r��Y�Oe�a!k���f?+Y�~�(�}�9��a��oh�]�Ňa����:6/��:.���1g��|i����''7��}�qz�,r9Ŋך��}�N�°Al��4sr���<�x^�^{�^�m����q޾�)-���t��ݏ��\Rf8��\�)`V:3TxU��ߞ�#���XZ�Ͳ�\�a���j�1�MC��6���=�x��2-��L7b��ln�p��紛���
�������QIߚRӨm;�M���
���myA��y�����m����ݖ�˱���R�1E��7�۽�W�X���������'���� ��m�ȴ)�j&o�y�ұ�sH�-��x����㉱�_�w5fa��w�3��ٺ�r�;�KF���su��O�M���]b��{+���7u\eU`wn��%@c�*,"�B�z��y���_�Ej�<�u*+/��b���E��b�f�W�Dz�鵺j��/�0,�r��m�ΘX������v�+��j09�d�	��n-�n��t"�q{M�7@�0�!ϛ���
9ؖ�PM��ߙ��ׁ������ަ}щ��3a�)NԳ���y�̋:-�q��N�J���h<ļ_;��	��Z
��7��=B;�
��zjۗ7�Bf,����ܑU.N\W�og{�喬�e+�[�����'��hi�9���ȱS���,��";D?�	��z�O��Dw����{M�v0q^u)����V����cT�[�G>�#	�ң������}�Շ��>��^������D_�
	�nM�w8�=8���SW����T��5@���5�o�^	����JsM'H���'1��;r��_���N���i��[�����y
��և���m���<X*f��ؔա��^�m�$�N��&K�>;2A[�����t��
��w๗S���@D�}Q10A����4���\���
�kkt,�+�d��#T�3+��荘�q�9������3�]Lm�����XӾ�;�j�,�C��;KG3�T�]F>^��q�;��P��1�L'�fϓv�3���1���)0�KQ���F�+��� 3���*R�s�k�װ׊W�0�s��(?̱5|�C����ƈ��'2�%)�'�G�u��P&�u����$>;�~ʭ�$6D#�sF=e$2"�#���6{,�Ct��d0b@.��:�ܻ��7���1�0�?\�� ��w�D ���cHE�`ʀ��0���Y-��9oB�L4�
H��a�A*eA,�9�k���F�56� w��΀k��<[��3<�itţ��l7�$ڠ�
[#lH�7y���f�s*yE'4�"-��92k�G�Y�螲	4^Z��.�Sj	�1��	������v�n ��Ȭ�3a@Ћ�B��W�‰�6�J����@rp�Fc���M@xK�:#Ѡ~�"���?���H6�9�8��N���Y��!���0
����'.��h�}%l����V\?�����д�}��4�m��V��(�‘s��oAI\�����A!o�#�a"��D����l�B�EZ�q�t�y!��Q5�� F}�0`D�h��)�݇��v�.a��fS��Abp��G4إ2���M���S�t��'eg��-�"5�I�B��\���"��8�r�5BAq���K/�,����"xN���#��V��Ȅl��&ɐCZH܃h;$

|�m(?t�˄̾��ɤ��K�BQ�Ej�v��x|������Л,"+1�@P���pt��
D"�WA���$�I�'N���X8�qpV�jxiHpo@a����M�%��>�I��]NT��.��,������4/�s��ٱMLK�"��-�Z9dvK��?��s�����	�dA��pBXX�.��P#-Z�ep�d(b����p��\���6��XOM�
��Y��e����GZb^��7����h�gB�5D��-}�T��,��h�B��2���zG�,��?�3n�� ����A	�����u!s�i�/�դ���%�H.h�O�-O�R	?G;��%m�yA��
yH�����٣{����<y �E$8��τM����
؜C+����L�} %Ʌ��b� fA�:V("Y\���3�x3���x�H�-�˚�/ro��P�sX%c*���H���a"x^�,OA�0�a>0*\�Rp�qA9XI����;ʿu�B�X(D���{į����u�
߀��W��D�`��8��`���5F�K��;⎠'I�Nq�dd�p�*A��D��1�\��K 'D1 yb�Ч�
iN�?mbf��0���� Sn�+~��[L.7[/*'�B
�X6�;�,�U�2m��A�D!�.���j�5�az�AI��zp�r"���#�$,(}���M�o����p�h����ُ�V�OL�9Uy����z_�
�׷���IKS@.�M8�.uWhV�����qCڝ�Ō�Db���?��o�>�F0�b@�x�U���ZH��m�o�\�7����nI�%�@�׶O��`P�I��
<17�$���w�ka�Q��"'�`�_n��.�r��c�$��)�\�B�_�d���@�r�4k"�؇@j���|$~bt�_�,������T���$�Zm�]��Bܡ���_jf��+��xF�S����|�T�JvL�!:
_��t�)~:�� Ց#���`r���m,��e�*��n��i�y����p����l�4O�&��]hNO�a�&O�
��p� �Hi|�����S8KVy�[G+,΀i�J���z4���8�'
�~<�J�e�*Đ"���pgTI��|{�oǍ�"��4d�DF���
��_�C�/c*��4�L���1p;�Ѝ�����/��Z���>�R��hnV-��M�4D��n˟���A(5D�ʭO��N�+���2t#k	��:����&��
,�6�ƌ�:w�A�B�_Qy�2Ը)��0�I"�Â�|���A���u�rnT����5)/���V��;���۝!�W3�`���4pB�r��.��F�Ag�Q������i#D_�����`H���y�5��c��L9��1�z`1ގ���2�6�F�)@�0�v���#���em0���;
�J�h�+����aƠ�R�m���F��؎t�'Q���J��� ֓�r`�Rq�#��3"��>1�]J�O�"�.)����7r�5A�u0�\!cB��A�Sx�>�?���+m��y�8%0�3���*�r�jr4�(,#I7Br��= y�#iz�\����|�&�q�PzD�q�9�̸��*/��a�Qx%T�Z*�V?��!���{J��)"JY��Q�4��P���	�:R�It��G]o���rG��O��tH/i��#p�H@��ؙVL
�u��Z�}�J��0�m�����9������F1����.�2�(Vh�i���b`�
2�M�N��^d��8%���9�u�*��h.�5�5�.�]rh%�VcUP���B�0���IR��z������qܭ9(��q�x
!�(��0w�a|}_�	E�A2��z̰��܄:kQ�uD8o�­�� PaTɪ`��V9�}���=E�om�Á���*7�������:#Z�4 ��d]�4�`�6�JX/U2�����0
��U0��H��/O�Y����	1�\�m�g�u�l��e
����@�%䂻���eH9��#4�ӡ���<"7�Yaׁ�^�԰��<v|Jo:W�@���)�ՄI�ӊ*Ҏj�h]Zy%�6@
�K��R��P�5Ӗ���͆��h
�2��w� +�E�U�d����cT�޿����o��x�4�DTy>�mq�:̂>Tc�- :�w�H&e6�}��E�sU&�`J�,{[{x�M":\m%n(��	ۤ�>/O=��K�v|��nn����)3�u+�)#յ}���Ց�DpIԳ�*ϻ0�xǩE=��c< �jPɉL��E)�}�z�{ ���]xd�{C0��WCړOPX���Q@Q����"��p�w�䝥�T�#�o����(�J��c|9�ԞdR�	�g%�\�,z��� ���uEJ�!�?�]��h�NԮ51��Β���W��S����_�=�έ��n]{5�T�[bJT��L˯�Eyy����o%n�f�T�}Uq�s��.S�OY1�T_��9A���Fze�Y�௺ᵡ9%��׻�-LB��T��cQ��tFX�?b�����)�Y/C[Å`�@yƟM�� J����ȷ��m��l�
�mq�A�N��7�1�"�f��c>������!N:F
�5���۠]э�#*��*:.;u��+"�>�pwP?�wC�i	����%Fr�$�^ܐ�Y�&fb#m���I��2.ig�f�������"{ ��B@E���
Su��)�a�TjE����LG�0��l��tI_�Ɲ�t�B�@�J��!�^n�{j�ߖ
2�2o�Z��$���!!��2\��Ǡ�>V1<��!d!�f&20G���G��.�k�]o��j�E�.�?S�]�5L�r�8���*��Єo%�^S�uV�n4&	�K����"�c�څι�	4U��-��&��r��O�g�2Љ/RcCAA�^K���
П�7$k�j[x�?��'-�O�FK@��%����p�m��1�sMz#�R��1���Q�5Ñz<�դ%Sk�	��j��F�"w�
�.�K�P�+e�o򮖻�T��“Z�7֐�?����-Q�$�j{o������L�V{z��dN�#�4�?c��$�Um�m"F��
p⮩)#E�=	��ofrT�(�R�W���	jfA�VE��S�3GEy\$��(Ϊ*a������t�*���60%h
�������Nj��.XM����:��Ҫ!eU*@�W0tDG��Oa�B�~���$#��S0d�˽
q*9��`m��|�y_��.ѐ�W��>��6H�bp~5���Q�F��FB�i��Q!���eb���1ȁ��W-�ۯ�`���A�^_�O␔3�*~�Lʫ�3�"�\P_�D�_��C%�xj,�6Ѹ��!8qt�~�L�TJ�Yg�Lh�S6���‰�p�m�
�����ߦ2�� ӌr�hx��ڮX� K���� ���ұk��r	�X��Z�j~�&:ه�F
�����#��ǽ�<�Z�FG$���mUŋoi�gx1[��Wƿ�PrC�9>/��z��������ûoxêJ�H�%]��2։iXIl�Wsm�զ]Ut2ֵ):�ʅ���"���7T2�R�4�bz;8?X$[d.:NPz��Zy\.��c��sk7�)�s!�;�Ů}��
�8R�,ŷ=��Fp2��)����D:Ѐ�̠
�g�ֽ� ]n��*�ME[�D�JW���K�GO�:��XU���� �M|$0��]5'��5Я톪�8,sDMm�ޔ��|��ӂ����U��z�upU��6W��=9u0�'M�F*��u���N!օM%�% �Q
3��jhTm^ځ?%k��:���������l:�
���6��HYUY0�)�9��j5��R���A�4�ZKj�Մ�-a{���x0М��oߋqG�/���e���B���%����8P��	o�5���O��apd�J�
H|��<�A�L�Is��>�F��KtTx77�eL$>6��,M��-�cR���>V��g��Q@�,���
 #d$�T%���e�Q_�%�]�"��:.]
ϡ��|?�܁��sd�?k���K̈��������@c!�
����G<�� ��������Xc�l�U�w�!C�<5�4�Y
p<b�^Q�M�������+�/p
K!����kU�;�O�8��j��-j6��UŘ�*�W5W�܃�j�J�#���-W�5�SM����U
X=���ͱ�69���	#F0�">��wP#ԣ	�pa�r�y`h�W�lO^jD�Ak�L��aa^�P���:Tx�m��M�Hl���Њu���*E�e���9�ks��N�&
M%��Ҟ>T+J�.դ+!y����s���?���p�nH=
s
!Z0V�e��� �
vb_@�Gm�,��+��e/���BAƬ�8S���q��_�6��G0픪�͛�A�x$^�å2�֜ IE��=`&���wМ����=o�6�k~ �"B�Hb)L�HU[b����p��`��S�J�P��A�^�5�
٩60p�#���((D:iߜ?�j�@ASgbhf��y1e7�j�g×<�a�
!�X��{�D]������
S[�P��j� ���j��ك��F��{K�*��a�|����i�;�(���ƭOĥ#��;�ň�����!@��?X�PTW�G^w>�
c��P?�e2J�,���������_���7��k�Kjy��Q	�u�Û�K�#�f��/yN}&���]DG��<^�Z��R�J���\�q��M#������(Mց��\���nb�����F��,����-uL[`����=f�n��4�ND�e�K��a��Ϭ�L�21�o���[9r�rT��DUX:2(-���:5v���g�ԣEf5_Mp��niu�W�L�:0��BFeTy�I���;�E'�HX'�xa��Nr��[6`��#X��@���qԾ0ZڤKj{���2�_P��j�YCެ��JX/"ɯ��.U/���E��T�FUK*$�fX��]�o�Ւ�͒B]��t���-A:��"'�_7���@d�Q�8�
r+K]&dT����;K'��[{7��xڅ��Q�Bl�Ӏr�j�`r��_�6Ӽ�g��jɬ�I��~��\O�I�"i-"|s���׈����S��@p��9���"�l�n������N
�i"�ʷ'�$�{S-����#�^�d<h&���kj�H�;PtT��{"�u�k����@d�W[�#»���ӫD$ *�[]*H��Ƽ�o�i
Glr����蟐�M�'���2��ϻ�2�U��j�W
�`�?�s�fBq�˾�p��2u~e�"�.<>	n��6a��I�VT)%0l�L)MZd�e��%�Q���,C9p/>�3�s�(23M_�d$=7o�[�n��8V����
Hw�jWV�V�-����n��Q]I�QNL���e���U��VP�:8"ˈ���Ѥ�5L�#��φA�xd� S��ׅZ�c����5�����k�UG�I=1*�#��7��������&IUP��RIC��Mt��L�C��!v��$
�$���%RҵO��n7.��r@�Mi�A�98�B�p��S|N�:��`e����m��O�BR1P4�T�&��B����12)آ�l�)��P&:����^B_nQ��O�@�G����
i����cc�>C����O��D�,���.��v�ի�wA�"^���K�d�Q娙D�U�T�G���|��'�wj��t��x�����ڜ�ծ�eҵ��
JMKRup(n<T����%���$��U�o\�8j{Ϫɦ	��=*�Щ�g�pW�(x��'��fS���lX��E.͇�SI#���kmY��fb�!���B�ڼ^�U��g�t@�8$	jj\UXֶ?R�2��u�@���eV#���m]jQ���^Y�w<����5�8?��DV��}1h�y�7���O�എV�c�VcjWW4�KR�oU���_�حĔ�jl��x�������l�,�PT�ပPد��8C��Z��M���Zp ӂ�`�1���k
�K�uy��7���<F,�<z�s�|W�ki��Ğ���y-%0x��қl)�zڡ��e�p���}��	!w�2%7`UX-�@�4�+���R�'�0T��'��n�)�U�'����i�Q�?sA���6�B�G�}��O�9�Oc�rұQm\`�1_
"����;���iK����Xa/	]��7�q
[=0��w<��R��fV�$�V{�,��Y��������py�;tRO:���p)x��=�Y��u����tP'���mR��/ɛ�6A#|�(0����/��O�s��x'�B�Php��<u�2��rI4�'Ll�Ż�aᏖ�[�'��{�7��&i��2C-�ܐ� <��3�F}���%L$W��#I:��&*qY��N�����+O�"��7}���u,mVR��l��B�X�u�.�N6i���C^a�Ƿ	'G��W:p���8V(maB�K�UvD�&&l}Ͷļ����
�j�APT�QA�E\e^�~��ɵy�� ���v��N���]|�PS�g:�4��8��2*��)�\��Ta�Ϡꁫ�c�ʣ舱5�	����dp_Es������������Gn<u�?<ʜm]|�:�H�v��W�B��u5�����h㑼Ȱ�*k?�m)d��tt�
FѾn|r��?���٥}����U����޴�{��"w�����xfVih�y��v} ���|��V'5H��SK��y�2�E;�&�XU�Z����tvG�׷���3�����w7��
�u4mkU����~����0�k�tVB]=U�)�����6�Gj���֙\�����Hnc� �B��~���Z��}�N������edYs٢CM�9����#8�j����R:��P�(���rh�71�K�/�4�yR��t�j�h�s��ҳ�u 0'r��;�!bU�	w�S4#���utV����Q8S�ۗK�_|��<�P�ώ^Җ��
�EmaM��H�0��_�t�=��]g�����)&�:�D�uEXdeI�2$H��ž+�Y
�bPZm�PSE��]��=��fM�𫌎��C'>~�ѻvTt܍���R�Q�~���?=z�Lz��?"���vV�S�U{p�]�7z5��ɁǰM#��4�>�*X��݌����O��w���y���e�0�U^:��_	)�/�C�PZx
F�&(�5t��L���WܱBF��3�2^�)O%��6'��TZ�
�PQB0g��y����
uB�>m(�_|�ӽS�0pG�5���&џ�W��(jϛ`�8�_\R!v.{��#�:�������F���m�S�U���c�φ��:ڎ:C��8 <O|hu�RW��%~F~�`�t�h��M�y
�Ӣ�{账_��#�5���EK2TEjx�*�����0T�Qm����j@f&��H���xs}�>D�lE�8
<_��'c�Z�0�H?bSG���&���ߡn�V8[d���~��ǽ[�qD�V<��E 2��A���d	�u��*ũ�"�mnm&U5�Eس�W%�!n'���yrӯP��
k*(��_,�
u�>]��dk���#��n��[?�D�n��X����#G���h���lՕ�N̚�9�˗t</�p7�O����u�A�����<(�nHlW>��q����db��5N��R���6Ԩ)<V�=`k���C���h8���Ԣ���B�o'/��ttQE�m�sUI+�D!��}����Bk��]��t�?��ﳩ߷@�E�>�(�������F~�
�?�Յ�f��}j���m�+qC�Z�d	Qc���>8d�żδ���ov�z
;I��:\�Z[���ۢM:�pW_�r�;-�[G�n�W���W�m���XbA�`�_XҦ;2�I{̠ix�6^hU�P���g^r��"B�w~��jW�߁���ƌ��8������:)�=U��P�T�=JH���8)�t�|C�:��7���O�sBIT|d��IDATx��y|�չ�k�Þ2'$d �fDQT���O[;8�ν�9�=G�q�mzmOk{:�m{zmm�=����EZ�H[d��$�9���u�x߽�`��$$���g}�����[���z�Z�A�U���q�
�{K����j��Ea2ֆ�i�#�Yi�����yW�u?��F�uq����_��Zb0��.tK�=��6-�
)��0���Cf��@"��vPZ�Z<�Q�>��+���A�h���[*�&Lq����F �jW�h��.���6�������0I��_jG�_�z<~�7y"�N^}��Ҕ�ۆ}�@B�\G;)��@�1����<s����a�&M��-�w��c�W�J��S��U��s��wLiݦqQ�ux�|���0�J>j�ݟ��o�
���@.���;�с��f�ʤ����˱g;�ɞmɀ�p�k����Mǻzq<�7�ޝ�㶴�L���{��~ג#�k��}���<��x����b�/�O�ܘTq�S�`b��$�K�ǖ��B��[K��-���AO���57��e�qt2e�'|N
PB���b�w��O�\3��)�*Sڳ��mz���W�J��Z���ꮩ�0�J)�v��b�\�H:�s�$�Ψ�v�0P��	�(|}�x)��j����_ݶ�U2�a~�6삤���q\�8'��,��������V#M�����`���{/Rk׵�@A>ܖ&r��r�@4����\)��}��>��y��<*@�_���g~@8'̶�-l��H*/�e��k�@����ǻ��Q��Z2�������J���#�+�E+��'T�âo��3-z��BU�<��ʒ���� �����b�X�j���?|}htC�Ɠ�וq�C�dƬr���/�k�j�Xyk��Ra/BT+�j2\�R�t��*/`�>��Ü#h�^H�]-��V�K�!Xj
S����Od�֚�	E,�yq5ӣG	��m��MaJC�T*ͼ�O^��`�UDJ�X��'�~q
3��6�Ed��k�f����ujzttފ�hW�U��zK)�J)�c�C��YK��s���3x�Jk��F��@��l���'��ށ����t	���[g��uL�j""U&/4
4�L�(.q���s�����V�67��e�%���a��}(��3\���}��?�{�f^��t)��ά�'�9�kڴ�l��8��9a�=�_>�+�oP��o�b����A�?`�z�2��_�˅GZ�d�ӥD�	8湶�3��o���]
4o܅	�Hàz�<�ex.�w���<B�rx��=q Siٔ&���G�J#È�y��ӫ�;S����|�رN�0n,I�������V����+���w�]uR��]��^}��lzl=2�j�ʹS@Ďv�}��<�Y�v\�kJ�gqp��5p�	JO!RZ��p���VVp�&`e�ra;�Bв����}��/m��y^�#!��4x��wmj���A�(��E��$�bl��/���bJ/��]\��o0^H
/�3�Y|��Yw׏�s���|EVc���J#�S&��מ �#�!�#r%��6wмq;������_�}>���;������_���|��+g��K��{��LvE9�f��e*�Rq�,�"���O����o_���j޹��cżC���7���ɫ+�o}3�G����}Ө��4n�E��Ø�t	�E��jv�E[�!>p�
-l|�q�.�N ?�/Ɵ�M��{�}m/���ϬX��\�Sф��u�k�i�.�_�Cӆ��n��5!�(miJ�!9��u�XaJ�X�q�k)�6��&U\B0��i����b�҇�����;+H�0���B�ᗶ�}+;D�=J�s�7?:�m���m�Q3����ͅ�
�S+ȚP���P{��罕���cp{7f$�	���_*��$2>�'�a��i�^��t�J��F�f�B%"e��_>��zگ��
i�عa�=�t�S��gfby�9/��K�"��-��Ob-��Ҹag?�S�[��5�����%(]4���B߃oP�0��a[~x0����{�u#`���r��F�G�����������F9
/n��^������h\��O\�XL����	Cmn�eK}:׎�s_�^،vz������>B�M2.эTC4��kBJӤM��a�|G�^<�3�h~ef����]�Z:	d�]!
��L��
;+H2'����������-�=9��Q�������~9H=@ �`ڬR�ӫ��X��$���H�z��zhg�F���J��E���4m؉�t�7Ӵq7�W�FH�r\��l��@%]&,��������LX~!�|�#�����CltZ)��͡7��1S� ����!~�M�NX>�-�&�E%^��.h�z�����z���a�ճ{���X�!3d��*`�PH�.E~��=��FR
��#���#i���JM��&0l���;��uP�f��.�m�Dͮ�`zՀ�V�g�>�]�n�;���ۮ`�ne����BI�٠�e�U+��pat�m���h�8�f�4|���\>Ǜ7?�t���GE���w^̢��3#5C��r�)k-]<���r�v4��4��;;L��A7�$<>��+f��Gu�ޮ�ƅA�z��Ş���͑v�Zi������-����ᗶ��p7�`B8�q�N!{�8?�������hץ�ڋ�r�#ȮNv�و���]�Ry�\�Y�A붃�f#F�rsˠ��9�CK��O��RT];�%�������G�)�?�����pb	��(�8�$��R�hʀn�5�pH�w����z{π����=Յ@;��+g��aZ�`b���LKټ{�T�����tLTҡ�ع��d͈u�^��o���X�!��8�+Y�͏bز��aio L�+�_>�K��w<�q��7�l�($��{JL)���HYn��4z���3��9�"��9�TLi���ƾ'7�q����Gh�~�����Ť>�*m�$:��=CG��nJ�Ob�oej��݅:�,=����q9t7� �'W�_XK�̪~����Fu���3`�����>܂�F;.��|�W���K���í��� ����H:�d�8&�u�c��}T�
�pz���T.������S�:)O����H*Rb�&�Ͻ��
��h
yu��l#�,
/�f�÷��'f��1��~�Gv>�q&%��zք"���t7�`e��2�������
-���p���ʮg;7�S?7�d��9��F:4��N���
�˾�	�Y4�m�W��z7[����Z��鍔^2�@^h�	R�xʠ��5��8
�g�tT�̟�4
��f=s�~�'=j�:�}k1
�=�2�.���.&,�����^�{6��t�m䥻~L�Ϊa�Ex"�`7eQ#l�s�xv�r-�����a��C�����f�u�(��"e\�StaM��g��H%��5��T�Dք"&�o	���,��L�tɴ���]� L��Wv��g/x�+�$�q9�}�Ҵ�> =�eR����š��ɮ(W��vʗ�:づ]Ł߿ꭎ�7��쒩󳰲�\������?ƚ��z�_�7��Qos�{�0�3�Q<ok>��=��x[W�x�ߴr��
k��am�ȀI�;N���?�"��@��Wh�~:�	��מ ���Տ�Aŕz��߬h��r�M�Ƕ���0�EfЦ�ڹ�ϟ�\\�Տ݁��_����d#�Ӆj 7���$��9���,����֎g��иa'�|�	Z�ԣ\��h�x�D�b9��y�O�ƒ^��oY�e���*R��I* RV޶����ld�7�?��H�H.7��C�Wz5��^��5�����
��Q0����<}�r\�Ź\tϻ���?�q�.JO�:ef���(�	fs�>F��K��5Z�ԓ쌂�n�����J�Zo�"���E�v+vN��_��p+F�:���Z�g9�q���v!L���s�7�e��W�?�;;D�#J����k赗�8�8��iz�)ǥb�L�H0}�Ծ7��N#4.��붟�=�����JL�d����.A��!eKg�`�ɛX�V�޵���^|ʏ�۪�"����}��E۰s��r�8�@L��c_*�Zk�|hvV(�I�RCҴq7�o�Z�"���^1)=���Uvv�PI��V�eG�}R�t���f�(�UM��J�/�A�5s��|p3i�eK�tg�|�~<qR��]XM�e�9��u��ئ}�.��+�o=���8�q��Q�/�D���t����b��9S������ͧjż~%N��xbv������կ�${b4��F��*Zc-]4����"�p�\�)Ӌ0FBQ�{����̉s?W�U~�t���q�I�epd�v�X!�'�G����}M�H)/���W�1�&\R���#b�+OgP�r�X67��ڴ�<L˖�~�֯~�8��%)]<�����Ec��ܲF�@�~T��ȓ��dg��k���I�u��{3��XT^32=���8�澋f�P4�'�@Z��mǍ'h��f�Z1l'� oR���1�G�!
*����w�h�v���
X��/{�0*����
�e�|��e��r&��BP�x�����b��
r�,��m��"t�HY!e�NÉ%�Rrd�v��z=��n�e��0jғ(#��o���,���a-dТq�Nv<�F���LX>�[��՘�g�J��Q0�wpzĎu M�� ����+f��Ld�3 tJc-*�����axU�N<��E�ɪ(q���g�U\1�`a6:�]�a[T^;wD��c��}O����_��^�1���'���|����0N!�?g�Z�Q~���y��c�ׂE9$�b�ۻOYg����Nz�=�z�y�;.�{~��[c���h��/m�֊�d>^ko���/n��H+F���N0~�
gT�Vތ�>rS0�5��+�T6}�I�M��cA�-���I��0��v��'BJ��+���ҋ�R�{���c��W�q�=�&����7��n�V+Ҕt7��ҿ<B�z�H�dW���fQv�t��~�	���wk�!g�Ն^),�R炩����;��7|�ʫ�Pxa��T�c.��G��^b��6Ҿ�;+�M*�e�?��p����2,)N���_����Jnm����P~����Y������_�*��:ٕ�T��K�����	fcg�qcq�y����Ie��K����^hh���ܬ�k /2\�::@���K0�5�Oŷ�Pq.s?{�c�����ⱳ�}m�]��s��?o����^9�i\���z?=����J{��t�D���5d*��Y�F!����+S5H� \��~M)��+\V@ɂ:�~hYo��DJ�G
����r)L66|����	������֥�+�{�S���ͬ"���`Q��������^��G�a>Bd�w��'R��o4�5$ӕ���~���7�*/�x�D�E��o)��6U??�~$fP��}��]F�*�/?ϡ�?#���=����V��R�O����n��q������i�G9݌�@��=�ʑ�����}�݁�w�,{�oT8�-���������n������H����{�c{�ݮ[������L>S~D+r�r�qao�S�i���S;���}5�ѷ�ߞ՛2LR��ܞ�ڑo��8��}h������� J'0e��~��.6~W��;��L�׸H����`��Q�9u�}h���,�u���������+9�� ����j��4�Y�x'H2��
_e�ޏ�p;��1Ї�νud��ME�U�@�Y��r�c
O�x�}3����d���v����>e��e�m͏��ҝ8ԇ?��>�*
��݀e��p�Fa!4.ۏ�O�X�3n���	ܲ6���F:N�buz0h���z����<��D�f�#^{O����)�ZL}���P|�������Z����G�g-�82��`a�ˈx@�A0D`�8o�!��_�+���'��\����@/�ʹq�`ǟ�-�*E�$���H����=Ş֧0�A�,"b���[�	���F������?��2Bt��qi�w�Tp�?0�G�$���m�ZQ�w#�Y�i�|ɳ���[�v�۰��Ŝfz��4�����nS�!����.�w[yn��M62����0 Fa�|��7��P�o����3��_1�`ڭ����1���b!f�>�{?���\���v�z���ۣ3�3��n<I�;��9�<)��_��2�B7����X:��%W:=kvftҳjCX��%z�G���[X2k�Y����F�Z���M���*���k�6q�|�)��k���L�?k� ���'y�e5���5~T<��o$�zB��&Q��Kh������L����Q	�pi�ǰ�{Z�&꼓�kJ^�����;��.������&m��VI�;�1����Í[9|�U�0C��S;�gY�Ôf_���q ����j��V8N�˓x��o ޒ�J����U�]�FG�;X����$����L��#j���$F(AˆIl��Mt�Y���h��Iaw��Vqi��ŀ�s�LM��uS3�kg[��8�^�Y(���C�j�kǝ(�p}�3T��k�24��(�NI�`�3���]CˆI���S��@c
)����W�-�n��������3���L��t�&�8��W�)���Q�7������-RX��.��njPA`�t����Š���7���C��'�.%�˘S��n����|�c�7�I!�b�G�`Ho0�\�2p�(���e�ƌ�O�m�En$[=��EfQ�Ŝ��;�@[|mѝt&�M6��(�]h��F
s@��� �F�	TrE�R�{Mz�e4j�z*d�*�\_�7���,[y����}��X��}\ɕj܉R���+k~H~hꨟ^�L��&ӧ5h��F�G�	�N�����!B渱����}S��)¦���������2���.I7�ed�d¿3��}���8z?��S�<�*s��j�vbеv�<_ �$�vQ��9�턃[���X���k�br�XY�ی�a�=R4Z����9���\U���a�'u�J�X|>�w���'y�IG�Nh�R�%2a
���޴h��&5��Z�}R��rq>E���1��O�|�I��6��i�����G^�����线]�m�'U��8��rF [��L3�����|��V�J������=j��Iw��*Gw�d����,��K����0hY�&�le����.9MK��o	X!�����bT2��f�
o��ܴ6#c�0i6C���8HY��5���m������k���/��<��[�/�>�<C�q�b+[E���Gl#xkR���l��p}6���lC�T{wn@��Ҿr4��v���}�5Z�jσ���	'�ƒAp�y��g<�)�W�J�t�כ�����ax[��ד2��
h)bpK�ݷKi~�2�qI���:�~��e�I�x�[*�&Lq����F �j�۠G�b���1�)���y�z���/VZg���%�)���>������[b�Xj�r%�<)t�F����Q�?�>���Y~IEND�B`�PK!��FN�F�Fgpl-2.0.txtnu�[���                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
PK!� --compat/wpml-functions.phpnu�[���<?php
/**
 * WPML compatibility functions
 *
 * @global array $duplicated_posts Array to store the posts being duplicated.
 *
 * @package Yoast\WP\Duplicate_Post
 * @since   3.2
 */

add_action( 'admin_init', 'duplicate_post_wpml_init' );

/**
 * Add handlers for WPML compatibility.
 */
function duplicate_post_wpml_init() {
	if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
		add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 );
		add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 );
		add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 );
	}
}

global $duplicated_posts;

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break.
$duplicated_posts = [];

/**
 * Copy post translations.
 *
 * @global SitePress $sitepress        Instance of the Main WPML class.
 * @global array     $duplicated_posts Array of duplicated posts.
 *
 * @param int     $post_id ID of the copy.
 * @param WP_Post $post    Original post object.
 * @param string  $status  Status of the new post.
 */
function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) {
	global $sitepress;
	global $duplicated_posts;

	remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 );
	remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 );

	$current_language = $sitepress->get_current_language();
	$trid             = $sitepress->get_element_trid( $post->ID );
	if ( ! empty( $trid ) ) {
		$translations = $sitepress->get_element_translations( $trid );
		$new_trid     = $sitepress->get_element_trid( $post_id );
		foreach ( $translations as $code => $details ) {
			if ( $code !== $current_language ) {
				if ( $details->element_id ) {
					$translation = get_post( $details->element_id );
					if ( ! $translation ) {
						continue;
					}
					$new_post_id = duplicate_post_create_duplicate( $translation, $status );
					if ( ! is_wp_error( $new_post_id ) ) {
						$sitepress->set_element_language_details(
							$new_post_id,
							'post_' . $translation->post_type,
							$new_trid,
							$code,
							$current_language
						);
					}
				}
			}
		}

		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above.
		$duplicated_posts[ $post->ID ] = $post_id;
	}
}

/**
 * Duplicate string packages.
 *
 * @global array() $duplicated_posts Array of duplicated posts.
 */
function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break.
	global $duplicated_posts;

	foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) {
		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter.
		$original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id );

		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter.
		$new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id );

		if ( is_array( $original_string_packages ) ) {
			foreach ( $original_string_packages as $original_string_package ) {
				$translated_original_strings = $original_string_package->get_translated_strings( [] );

				foreach ( $new_string_packages as $new_string_package ) {
					$cache = new WPML_WP_Cache( 'WPML_Package' );
					$cache->flush_group_cache();
					$new_strings = $new_string_package->get_package_strings();
					foreach ( $new_strings as $new_string ) {

						if ( isset( $translated_original_strings[ $new_string->name ] ) ) {
							foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) {

								do_action(
									// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter.
									'wpml_add_string_translation',
									$new_string->id,
									$language,
									$translated_string['value'],
									$translated_string['status']
								);
							}
						}
					}
				}
			}
		}
	}
}
PK!�ᱏ�compat/jetpack-functions.phpnu�[���<?php
/**
 * JetPack compatibility functions.
 *
 * @package Yoast\WP\Duplicate_Post
 * @since   3.2
 */

add_action( 'admin_init', 'duplicate_post_jetpack_init' );

/**
 * Add handlers for JetPack compatibility.
 */
function duplicate_post_jetpack_init() {
	add_filter( 'duplicate_post_excludelist_filter', 'duplicate_post_jetpack_add_to_excludelist', 10, 1 );

	if ( class_exists( 'WPCom_Markdown' ) ) {
		add_action( 'duplicate_post_pre_copy', 'duplicate_post_jetpack_disable_markdown', 10 );
		add_action( 'duplicate_post_post_copy', 'duplicate_post_jetpack_enable_markdown', 10 );
	}
}

/**
 * Add some JetPack custom field wildcards to be filtered out when cloning.
 *
 * @param array $meta_excludelist The array containing the blacklist of custom fields.
 * @return array
 */
function duplicate_post_jetpack_add_to_excludelist( $meta_excludelist ) {
	$meta_excludelist[] = '_wpas*'; // Jetpack Publicize.
	$meta_excludelist[] = '_publicize*'; // Jetpack Publicize.

	$meta_excludelist[] = '_jetpack*'; // Jetpack Subscriptions etc.

	return $meta_excludelist;
}

/**
 * Disable Markdown.
 *
 * To be called before copy.
 */
function duplicate_post_jetpack_disable_markdown() {
	WPCom_Markdown::get_instance()->unload_markdown_for_posts();
}

/**
 * Enaable Markdown.
 *
 * To be called after copy.
 */
function duplicate_post_jetpack_enable_markdown() {
	WPCom_Markdown::get_instance()->load_markdown_for_posts();
}
PK!�*��
readme.txtnu�[���PK!E�\k

Yoptions.phpnu�[���PK!iL���common-functions.phpnu�[���PK!f��(�"js/dist/duplicate-post-quick-edit-450.jsnu�[���PK!LG�.".*js/dist/duplicate-post-edit-450.jsnu�[���PK!kb<+�
�
%�?js/dist/duplicate-post-options-450.jsnu�[���PK!<M��

'uJjs/dist/duplicate-post-elementor-450.jsnu�[���PK!����%�Tjs/dist/duplicate-post-strings-450.jsnu�[���PK!�=�[ecss/duplicate-post.cssnu�[���PK!�v�6@@atcss/duplicate-post-options.cssnu�[���PK!М�FF�wsrc/duplicate-post.phpnu�[���PK!��F22{~src/post-republisher.phpnu�[���PK!ǩxi##հsrc/ui/link-builder.phpnu�[���PK!#*
[?�src/ui/metabox.phpnu�[���PK!���bb��src/ui/user-interface.phpnu�[���PK!J��p��K�src/ui/post-states.phpnu�[���PK!�/ww_�src/ui/block-editor.phpnu�[���PK!)m5����src/ui/asset-manager.phpnu�[���PK!�oH�src/ui/column.phpnu�[���PK!@��--\src/ui/classic-editor.phpnu�[���PK!�GK����Lsrc/ui/admin-bar.phpnu�[���PK!M�©��_src/ui/bulk-actions.phpnu�[���PK!�_�<??�hsrc/ui/row-actions.phpnu�[���PK!
�?:ff,{src/ui/newsletter.phpnu�[���PK!��sS׋src/permissions-helper.phpnu�[���PK!!tA��
&�src/utils.phpnu�[���PK!ř�$0$03�src/post-duplicator.phpnu�[���PK!|L� " "��src/admin/views/options.phpnu�[���PK!�K&��	src/admin/options-inputs.phpnu�[���PK!�4W(W(Jsrc/admin/options.phpnu�[���PK!�N
�``�Gsrc/admin/options-page.phpnu�[���PK!l7�P�%�%$�Ysrc/admin/options-form-generator.phpnu�[���PK!�!�
^^�src/revisions-migrator.phpnu�[���PK!����
�
%6�src/watchers/link-actions-watcher.phpnu�[���PK!.�e�

R�src/watchers/watchers.phpnu�[���PK!���w		&��src/watchers/original-post-watcher.phpnu�[���PK!��� ��$�src/watchers/copied-post-watcher.phpnu�[���PK!\�	th
h
)�src/watchers/republished-post-watcher.phpnu�[���PK!�6$�

%ɼsrc/watchers/bulk-actions-watcher.phpnu�[���PK!�A#@&*�src/handlers/check-changes-handler.phpnu�[���PK!��*��"��src/handlers/save-post-handler.phpnu�[���PK!�P!+��src/handlers/handler.phpnu�[���PK!�-mBB
�src/handlers/bulk-handler.phpnu�[���PK!��11��src/handlers/link-handler.phpnu�[���PK!���
�
duplicate-post.phpnu�[���PK!��s��`�`�%admin-functions.phpnu�[���PK!(�B����vendor/autoload.phpnu�[���PK!t�!ו�'�vendor/composer/autoload_namespaces.phpnu�[���PK!�5Ky�>�>وvendor/composer/ClassLoader.phpnu�[���PK!)Ϥ�7J7J#��vendor/composer/autoload_static.phpnu�[���PK!�����vvendor/composer/installed.phpnu�[���PK!;�S22!�vendor/composer/autoload_real.phpnu�[���PK!T��t��"vendor/composer/platform_check.phpnu�[���PK! �..#vendor/composer/LICENSEnu�[���PK!+|i��!x'vendor/composer/autoload_psr4.phpnu�[���PK!T��"�:�:%�(vendor/composer/InstalledVersions.phpnu�[���PK!�+6�bAbA%�cvendor/composer/autoload_classmap.phpnu�[���PK!�C�\kIkI%W�duplicate_post_yoast_icon-125x125.pngnu�[���PK!��FN�F�F�gpl-2.0.txtnu�[���PK!� --�5compat/wpml-functions.phpnu�[���PK!�ᱏ�tFcompat/jetpack-functions.phpnu�[���PK==�OL

Youez - 2016 - github.com/yon3zu
LinuXploit