Changeset 3252339
- Timestamp:
- 03/07/2025 08:35:48 PM (9 months ago)
- Location:
- just-duplicate/trunk
- Files:
-
- 4 added
- 8 edited
-
README.txt (modified) (3 diffs)
-
assets/css/admin-style.css (modified) (1 diff)
-
assets/images/banner-772x250.png (added)
-
assets/images/icon-128x128.png.png (added)
-
assets/images/icon-256x256.png.png (added)
-
includes/admin/class-admin-settings.php (modified) (9 diffs)
-
includes/admin/class-media-duplicator.php (modified) (1 diff)
-
includes/admin/class-menu-duplicator.php (modified) (1 diff)
-
includes/class-duplicate-handler.php (modified) (4 diffs)
-
includes/class-duplicate-logger.php (added)
-
includes/class-just-duplicate-loader.php (modified) (2 diffs)
-
just-duplicate.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
just-duplicate/trunk/README.txt
r3237505 r3252339 2 2 Plugin Name: Just Duplicate 3 3 Author: Just There 4 Contributors: [Just There] (https://justthere.co.uk/)4 Contributors: carlbensy16 5 5 Plugin URI: https://wordpress.org/plugins/just-duplicate 6 6 Documentation URI: https://justthere.co.uk/plugins/just-duplicate/documentation … … 10 10 Requires at least: 6.0 11 11 Tested up to: 6.7 12 Stable tag: 1.0. 113 Version: 1.0. 112 Stable tag: 1.0.2 13 Version: 1.0.2 14 14 Requires PHP: 7.4 15 15 License: GNU General Public License v3.0 or later … … 83 83 == Changelog == 84 84 85 = 1.0.2 = 86 - Fix: Donation Link (Buy Us A Coffee) 87 - Update: Enhanced logging and reporting features. 88 - Improvement: Added a new tab in the settings page for viewing duplication reports. 89 - Add: Logging of duplication actions for posts, pages, menus, and media. 90 - Add: Report interface showing details about duplications (dates, users, status). 91 - Add: Preview duplicate functionality with a modal interface. 92 - Add: Role-based access control for duplication permissions. 93 - Add: Batch duplication for handling multiple items at once. 94 - Add: Customizable duplication settings to include post meta, taxonomies, attachments, and custom fields. 95 - Add: Automatic prefix/suffix for duplicated content. 96 - Add: Compatibility with major page builders (Elementor, Divi, Gutenberg). 97 - Add: Duplicate navigation menus along with their items. 98 - Add: Duplicate media attachments. 99 - Add: Admin settings page with various options. 100 - Add: Custom bulk action for duplication. 101 - Add: AJAX action for previewing a duplicate. 102 - Add: Enqueue admin assets (CSS and JS) for the plugin. 103 - Add: Duplicate comments functionality. 104 - Add: Duplicate custom taxonomies functionality. 105 - Add: Duplicate featured image functionality. 106 - Add: Duplicate custom fields functionality. 107 - Add: Duplicate attachments functionality. 108 - Add: Duplicate taxonomies functionality. 109 - Add: Duplicate post meta functionality. 110 - Add: Default prefix and suffix settings for duplicated items. 111 - Add: Redirect to the edit screen of the duplicated item setting. 112 - Add: Help & Support section in the settings page. 113 - Add: System requirements section in the Help & Support page. 114 - Add: Useful links section in the Help & Support page. 115 - Add: Contact Us section in the Help & Support page. 116 - Add: Advanced settings tab (coming soon). 117 85 118 = 1.0.1 = 119 - Fix: "Advanced Settings". 120 - Update: README.txt. 121 - Improvement: Product Short Description 122 - Improvement: Product Long Description 123 - Improvement: FAQ's 124 - Improvement: Copyright Notice 125 - Add: Logo & Banner Assets 126 127 = 1.0.0 = 86 128 - Initial release. 87 129 88 130 == Upgrade Notice == 89 = 1.0. 1=90 - Initial release. No changes required.131 = 1.0.2 = 132 - No Major Changes (Safe Update) 91 133 92 134 == Copyright == -
just-duplicate/trunk/assets/css/admin-style.css
r3237393 r3252339 15 15 --jd-transition: 0.3s ease; 16 16 --jd-border-radius: 3px; 17 --jd-text-color: #23282d; /* Default admin text colour */17 --jd-text-color: #23282d; /* Default admin text colour */ 18 18 } 19 19 -
just-duplicate/trunk/includes/admin/class-admin-settings.php
r3237505 r3252339 34 34 'duplicate_taxonomies' => true, 35 35 'duplicate_attachments' => false, 36 'duplicate_custom_fields' => true, 37 'duplicate_custom_taxonomies' => true, 38 'duplicate_comments' => true, 39 'duplicate_featured_image' => true, 36 40 ]; 37 41 … … 80 84 'type' => 'array', 81 85 'description' => __( 'Settings for Just Duplicate', 'just-duplicate' ), 82 'sanitize_callback' => [ __CLASS__, 'sanitize_settings' ], 86 'sanitize_callback' => [ __CLASS__, 'sanitize_settings' ], // Explicitly defined callback 83 87 'show_in_rest' => false, 84 88 'default' => self::DEFAULT_SETTINGS, … … 143 147 __( 'Duplicate Attachments', 'just-duplicate' ), 144 148 [ __CLASS__, 'render_duplicate_attachments_field' ], 149 self::OPTION_KEY, 150 'JUST_DUPLICATE_general' 151 ); 152 153 // Duplicate Custom Fields field. 154 add_settings_field( 155 'duplicate_custom_fields', 156 __( 'Duplicate Custom Fields', 'just-duplicate' ), 157 [ __CLASS__, 'render_duplicate_custom_fields_field' ], 158 self::OPTION_KEY, 159 'JUST_DUPLICATE_general' 160 ); 161 162 // Duplicate Custom Taxonomies field. 163 add_settings_field( 164 'duplicate_custom_taxonomies', 165 __( 'Duplicate Custom Taxonomies', 'just-duplicate' ), 166 [ __CLASS__, 'render_duplicate_custom_taxonomies_field' ], 167 self::OPTION_KEY, 168 'JUST_DUPLICATE_general' 169 ); 170 171 // Duplicate Comments field. 172 add_settings_field( 173 'duplicate_comments', 174 __( 'Duplicate Comments', 'just-duplicate' ), 175 [ __CLASS__, 'render_duplicate_comments_field' ], 176 self::OPTION_KEY, 177 'JUST_DUPLICATE_general' 178 ); 179 180 // Duplicate Featured Image field. 181 add_settings_field( 182 'duplicate_featured_image', 183 __( 'Duplicate Featured Image', 'just-duplicate' ), 184 [ __CLASS__, 'render_duplicate_featured_image_field' ], 145 185 self::OPTION_KEY, 146 186 'JUST_DUPLICATE_general' … … 162 202 'duplicate_taxonomies' => isset( $settings['duplicate_taxonomies'] ) ? (bool) $settings['duplicate_taxonomies'] : true, 163 203 'duplicate_attachments' => isset( $settings['duplicate_attachments'] ) ? (bool) $settings['duplicate_attachments'] : false, 204 'duplicate_custom_fields' => isset( $settings['duplicate_custom_fields'] ) ? (bool) $settings['duplicate_custom_fields'] : true, 205 'duplicate_custom_taxonomies' => isset( $settings['duplicate_custom_taxonomies'] ) ? (bool) $settings['duplicate_custom_taxonomies'] : true, 206 'duplicate_comments' => isset( $settings['duplicate_comments'] ) ? (bool) $settings['duplicate_comments'] : true, 207 'duplicate_featured_image' => isset( $settings['duplicate_featured_image'] ) ? (bool) $settings['duplicate_featured_image'] : true, 164 208 ]; 165 209 } … … 251 295 <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_attachments]" value="1" <?php checked( $settings['duplicate_attachments'] ?? false, true ); ?> /> 252 296 <label><?php esc_html_e( 'Duplicate featured image and attachments (if available).', 'just-duplicate' ); ?></label> 297 </p> 298 <?php 299 } 300 301 /** 302 * Render the "Duplicate Custom Fields" field. 303 * 304 * @return void 305 */ 306 public static function render_duplicate_custom_fields_field(): void { 307 $settings = get_option( self::OPTION_KEY, [] ); 308 ?> 309 <p> 310 <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_custom_fields]" value="1" <?php checked( $settings['duplicate_custom_fields'] ?? true, true ); ?> /> 311 <label><?php esc_html_e( 'Duplicate custom fields (meta boxes).', 'just-duplicate' ); ?></label> 312 </p> 313 <?php 314 } 315 316 /** 317 * Render the "Duplicate Custom Taxonomies" field. 318 * 319 * @return void 320 */ 321 public static function render_duplicate_custom_taxonomies_field(): void { 322 $settings = get_option( self::OPTION_KEY, [] ); 323 ?> 324 <p> 325 <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_custom_taxonomies]" value="1" <?php checked( $settings['duplicate_custom_taxonomies'] ?? true, true ); ?> /> 326 <label><?php esc_html_e( 'Duplicate custom taxonomies.', 'just-duplicate' ); ?></label> 327 </p> 328 <?php 329 } 330 331 /** 332 * Render the "Duplicate Comments" field. 333 * 334 * @return void 335 */ 336 public static function render_duplicate_comments_field(): void { 337 $settings = get_option( self::OPTION_KEY, [] ); 338 ?> 339 <p> 340 <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_comments]" value="1" <?php checked( $settings['duplicate_comments'] ?? true, true ); ?> /> 341 <label><?php esc_html_e( 'Duplicate comments.', 'just-duplicate' ); ?></label> 342 </p> 343 <?php 344 } 345 346 /** 347 * Render the "Duplicate Featured Image" field. 348 * 349 * @return void 350 */ 351 public static function render_duplicate_featured_image_field(): void { 352 $settings = get_option( self::OPTION_KEY, [] ); 353 ?> 354 <p> 355 <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_featured_image]" value="1" <?php checked( $settings['duplicate_featured_image'] ?? true, true ); ?> /> 356 <label><?php esc_html_e( 'Duplicate featured image.', 'just-duplicate' ); ?></label> 253 357 </p> 254 358 <?php … … 384 488 <li class="jd-tab" data-tab="advanced-tab"><?php esc_html_e( 'Advanced', 'just-duplicate' ); ?></li> 385 489 <li class="jd-tab" data-tab="help-tab"><?php esc_html_e( 'Help & Support', 'just-duplicate' ); ?></li> 490 <li class="jd-tab" data-tab="report-tab"><?php esc_html_e( 'Report', 'just-duplicate' ); ?></li> 386 491 </ul> 387 492 <!-- Tabs Content --> … … 401 506 <div class="jd-tab-content" id="help-tab"> 402 507 <?php self::render_help_page(); ?> 508 </div> 509 <div class="jd-tab-content" id="report-tab"> 510 <?php self::render_report_page(); ?> 403 511 </div> 404 512 </div> … … 439 547 </li> 440 548 <li> 441 <a href="https://justthere.co.uk/ buy-us-a-coffee" target="_blank">549 <a href="https://justthere.co.uk/donate" target="_blank"> 442 550 <?php esc_html_e( 'Buy Us a Coffee', 'just-duplicate' ); ?> 443 551 </a> … … 455 563 <p><?php esc_html_e( 'For further assistance, feel free to reach out via the support link. We appreciate your feedback and suggestions!', 'just-duplicate' ); ?></p> 456 564 </div> 565 <?php 566 } 567 568 /** 569 * Render the Report page. 570 * 571 * @return void 572 */ 573 public static function render_report_page(): void { 574 $log = Duplicate_Logger::get_log(); 575 ?> 576 <h2><?php esc_html_e( 'Duplication Report', 'just-duplicate' ); ?></h2> 577 <table class="wp-list-table widefat fixed striped"> 578 <thead> 579 <tr> 580 <th><?php esc_html_e( 'Original ID', 'just-duplicate' ); ?></th> 581 <th><?php esc_html_e( 'New ID', 'just-duplicate' ); ?></th> 582 <th><?php esc_html_e( 'Type', 'just-duplicate' ); ?></th> 583 <th><?php esc_html_e( 'User', 'just-duplicate' ); ?></th> 584 <th><?php esc_html_e( 'Date', 'just-duplicate' ); ?></th> 585 </tr> 586 </thead> 587 <tbody> 588 <?php foreach ( $log as $entry ) : ?> 589 <tr> 590 <td><?php echo esc_html( $entry['original_id'] ); ?></td> 591 <td><?php echo esc_html( $entry['new_id'] ); ?></td> 592 <td><?php echo esc_html( $entry['type'] ); ?></td> 593 <td><?php echo esc_html( get_userdata( $entry['user'] )->user_login ); ?></td> 594 <td><?php echo esc_html( $entry['date'] ); ?></td> 595 </tr> 596 <?php endforeach; ?> 597 </tbody> 598 </table> 457 599 <?php 458 600 } -
just-duplicate/trunk/includes/admin/class-media-duplicator.php
r3237393 r3252339 105 105 } 106 106 107 // Log the duplication action. 108 Duplicate_Logger::log( $media_id, $new_media_id, 'media' ); 109 107 110 // Redirect back to the media library. 108 111 wp_redirect( admin_url( 'upload.php?duplicated=' . $new_media_id ) ); -
just-duplicate/trunk/includes/admin/class-menu-duplicator.php
r3237393 r3252339 144 144 } 145 145 } 146 147 // Log the duplication action. 148 Duplicate_Logger::log( $menu_id, $new_menu_id, 'menu' ); 149 146 150 return $new_menu_id; 147 151 } -
just-duplicate/trunk/includes/class-duplicate-handler.php
r3237393 r3252339 108 108 // Prepare the duplicated post. 109 109 $new_post_data = [ 110 'post_title' => $post->post_title. ' (Copy)',111 'post_content' => $post->post_content,110 'post_title' => sanitize_text_field( $post->post_title ) . ' (Copy)', 111 'post_content' => wp_kses_post( $post->post_content ), 112 112 'post_status' => 'draft', 113 'post_type' => $post->post_type,113 'post_type' => sanitize_text_field( $post->post_type ), 114 114 'post_author' => get_current_user_id(), 115 'post_excerpt' => $post->post_excerpt,116 'post_parent' => $post->post_parent,115 'post_excerpt' => sanitize_text_field( $post->post_excerpt ), 116 'post_parent' => absint( $post->post_parent ), 117 117 ]; 118 118 … … 123 123 } 124 124 125 // Retrieve plugin settings. 126 $settings = get_option( 'JUST_DUPLICATE_settings', [] ); 125 // Log the duplication action. 126 Duplicate_Logger::log( $post_id, $new_post_id, 'post' ); 127 128 // Retrieve selective duplication options. 129 $options = self::get_selective_duplication_options(); 127 130 128 131 // Conditionally copy post meta. 129 if ( ! empty( $settings['duplicate_post_meta'] )) {132 if ( $options['duplicate_post_meta'] ) { 130 133 self::copy_post_meta( $post_id, $new_post_id ); 131 134 } 132 135 // Conditionally copy taxonomies. 133 if ( ! empty( $settings['duplicate_taxonomies'] )) {136 if ( $options['duplicate_taxonomies'] ) { 134 137 self::copy_post_taxonomies( $post_id, $new_post_id ); 135 138 } 136 139 // Conditionally duplicate attachments (e.g., featured image). 137 if ( ! empty( $settings['duplicate_attachments'] ) ) { 140 if ( $options['duplicate_attachments'] ) { 141 $thumb_id = get_post_thumbnail_id( $post_id ); 142 if ( $thumb_id ) { 143 $new_thumb_id = self::duplicate_attachment( $thumb_id, $new_post_id ); 144 if ( $new_thumb_id ) { 145 set_post_thumbnail( $new_post_id, $new_thumb_id ); 146 } 147 } 148 } 149 // Conditionally copy custom fields. 150 if ( $options['duplicate_custom_fields'] ) { 151 self::copy_custom_fields( $post_id, $new_post_id ); 152 } 153 // Conditionally copy custom taxonomies. 154 if ( $options['duplicate_custom_taxonomies'] ) { 155 self::copy_custom_taxonomies( $post_id, $new_post_id ); 156 } 157 // Conditionally copy comments. 158 if ( $options['duplicate_comments'] ) { 159 self::copy_comments( $post_id, $new_post_id ); 160 } 161 // Conditionally copy featured image. 162 if ( $options['duplicate_featured_image'] ) { 138 163 $thumb_id = get_post_thumbnail_id( $post_id ); 139 164 if ( $thumb_id ) { … … 245 270 $post_type = get_post_type( $old_post_id ); 246 271 $taxonomies = get_object_taxonomies( $post_type ); 272 273 foreach ( $taxonomies as $taxonomy ) { 274 $terms = wp_get_object_terms( $old_post_id, $taxonomy, [ 'fields' => 'slugs' ] ); 275 if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) { 276 wp_set_object_terms( $new_post_id, $terms, $taxonomy ); 277 } 278 } 279 } 280 281 /** 282 * Copy custom fields from the original post to the duplicated post. 283 * 284 * @param int $old_post_id Original post ID. 285 * @param int $new_post_id New post ID. 286 * @return void 287 */ 288 private static function copy_custom_fields( int $old_post_id, int $new_post_id ): void { 289 $meta_data = get_post_meta( $old_post_id ); 290 291 foreach ( $meta_data as $key => $values ) { 292 foreach ( $values as $value ) { 293 add_post_meta( $new_post_id, $key, maybe_unserialize( $value ) ); 294 } 295 } 296 } 297 298 /** 299 * Copy custom taxonomies from the original post to the duplicated post. 300 * 301 * @param int $old_post_id Original post ID. 302 * @param int $new_post_id New post ID. 303 * @return void 304 */ 305 private static function copy_custom_taxonomies( int $old_post_id, int $new_post_id ): void { 306 $taxonomies = get_object_taxonomies( get_post_type( $old_post_id ) ); 247 307 248 308 foreach ( $taxonomies as $taxonomy ) { … … 309 369 wp_send_json_success( $preview_data ); 310 370 } 371 372 /** 373 * Get selective duplication options from settings. 374 * 375 * @return array 376 */ 377 private static function get_selective_duplication_options(): array { 378 $settings = get_option( 'JUST_DUPLICATE_settings', [] ); 379 return [ 380 'duplicate_post_meta' => ! empty( $settings['duplicate_post_meta'] ), 381 'duplicate_taxonomies' => ! empty( $settings['duplicate_taxonomies'] ), 382 'duplicate_attachments' => ! empty( $settings['duplicate_attachments'] ), 383 'duplicate_custom_fields' => ! empty( $settings['duplicate_custom_fields'] ), 384 'duplicate_custom_taxonomies' => ! empty( $settings['duplicate_custom_taxonomies'] ), 385 'duplicate_comments' => ! empty( $settings['duplicate_comments'] ), 386 'duplicate_featured_image' => ! empty( $settings['duplicate_featured_image'] ), 387 ]; 388 } 389 390 /** 391 * Copy comments from the original post to the duplicated post. 392 * 393 * @param int $old_post_id Original post ID. 394 * @param int $new_post_id New post ID. 395 * @return void 396 */ 397 private static function copy_comments( int $old_post_id, int $new_post_id ): void { 398 $comments = get_comments( [ 'post_id' => $old_post_id ] ); 399 foreach ( $comments as $comment ) { 400 $new_comment = [ 401 'comment_post_ID' => $new_post_id, 402 'comment_author' => $comment->comment_author, 403 'comment_author_email' => $comment->comment_author_email, 404 'comment_author_url' => $comment->comment_author_url, 405 'comment_content' => $comment->comment_content, 406 'comment_type' => $comment->comment_type, 407 'comment_parent' => $comment->comment_parent, 408 'user_id' => $comment->user_id, 409 ]; 410 wp_insert_comment( $new_comment ); 411 } 412 } 311 413 } -
just-duplicate/trunk/includes/class-just-duplicate-loader.php
r3237393 r3252339 64 64 */ 65 65 private function define_hooks(): void { 66 // Load the duplicate logger. 67 $duplicate_logger_path = JUST_DUPLICATE_PATH . 'includes/class-duplicate-logger.php'; 68 if ( file_exists( $duplicate_logger_path ) ) { 69 require_once $duplicate_logger_path; 70 } 71 66 72 // Load the duplicate handler. 67 73 $duplicate_handler_path = JUST_DUPLICATE_PATH . 'includes/class-duplicate-handler.php'; … … 72 78 } 73 79 } 80 74 81 // Load admin-specific components if in admin area. 75 82 if ( is_admin() ) { -
just-duplicate/trunk/just-duplicate.php
r3237505 r3252339 4 4 * Plugin URI: https://wordpress.org/plugins/just-duplicate 5 5 * Description: A powerful plugin to duplicate pages, posts, custom post types, WooCommerce products, menus, and more. Supports batch duplication, customizable options, and compatibility with major plugins and themes. 6 * Version: 1.0. 16 * Version: 1.0.2 7 7 * Requires at least: 5.0 8 8 * Tested up to: 6.7 … … 10 10 * Author: Just There 11 11 * Author URI: https://justthere.co.uk/ 12 * Support Us: https://justthere.co.uk/ buy-us-a-coffee12 * Support Us: https://justthere.co.uk/donate 13 13 * License: GPLv3 14 14 * License URI: https://www.gnu.org/licenses/gpl-3.0.html … … 21 21 22 22 // Define plugin constants. 23 define( 'JUST_DUPLICATE_VERSION', '1.0. 1' );23 define( 'JUST_DUPLICATE_VERSION', '1.0.2' ); 24 24 define( 'JUST_DUPLICATE_PATH', plugin_dir_path( __FILE__ ) ); 25 25 define( 'JUST_DUPLICATE_URL', plugin_dir_url( __FILE__ ) ); … … 63 63 * Enqueue admin assets (CSS and JS) for the Just Duplicate plugin. 64 64 * 65 * Assets are loaded on all admin pages so that the preview duplicate functionality 66 * is available wherever you can create or modify a page. 65 * Assets are loaded only on the plugin's settings page and post/page list screens. 67 66 * 68 67 * @param string $hook_suffix The current admin page's hook suffix. 69 68 */ 70 69 function just_duplicate_enqueue_admin_assets( $hook_suffix ) { 71 wp_enqueue_style(72 ' just-duplicate-admin-style',73 JUST_DUPLICATE_URL . 'assets/css/admin-style.css',74 [],75 JUST_DUPLICATE_VERSION76 );70 $allowed_pages = [ 71 'toplevel_page_just-duplicate-settings', 72 'edit.php', 73 'upload.php', 74 'nav-menus.php', 75 ]; 77 76 78 wp_enqueue_script( 79 'just-duplicate-admin-script', 80 JUST_DUPLICATE_URL . 'assets/js/admin-script.js', 81 [ 'jquery' ], 82 JUST_DUPLICATE_VERSION, 83 true 84 ); 77 if ( in_array( $hook_suffix, $allowed_pages, true ) ) { 78 wp_enqueue_style( 79 'just-duplicate-admin-style', 80 JUST_DUPLICATE_URL . 'assets/css/admin-style.css', 81 [], 82 JUST_DUPLICATE_VERSION 83 ); 84 85 wp_enqueue_script( 86 'just-duplicate-admin-script', 87 JUST_DUPLICATE_URL . 'assets/js/admin-script.js', 88 [ 'jquery' ], 89 JUST_DUPLICATE_VERSION, 90 true 91 ); 92 } 85 93 } 86 94 add_action( 'admin_enqueue_scripts', 'just_duplicate_enqueue_admin_assets' );
Note: See TracChangeset
for help on using the changeset viewer.