Plugin Directory

Changeset 3297655


Ignore:
Timestamp:
05/20/2025 09:23:43 PM (7 months ago)
Author:
carlbensy16
Message:

Updating to version 1.0.4

Location:
just-duplicate/trunk
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • just-duplicate/trunk/README.txt

    r3265459 r3297655  
    1010Requires at least: 6.0
    1111Tested up to: 6.7
    12 Stable tag: 1.0.3
    13 Version: 1.0.3
     12Stable tag: 1.0.4
     13Version: 1.0.4
    1414Requires PHP: 7.4
    1515License: GNU General Public License v3.0 or later
     
    8585
    8686== Changelog ==
     87
     88= 1.0.4 =
     89- Add: Bulk duplication for custom taxonomies.
     90- Add: Advanced filtering options for batch duplication.
     91- Add: Integration with third-party plugins for extended compatibility.
     92- Add: Enhanced UI for duplication settings with tooltips.
     93- Add: Option to exclude specific post types from duplication.
     94- Add: Support for duplicating reusable blocks.
     95- Fix: Minor bugs in duplication logic for WooCommerce products.
     96- Fix: Improved error messages for failed duplications.
     97- Update: Optimized database queries for faster duplication.
     98- Update: Improved compatibility with WordPress 6.8.
     99- Improvement: Enhanced security for AJAX actions with additional nonce checks.
    87100
    88101= 1.0.3 =
  • just-duplicate/trunk/includes/admin/class-admin-settings.php

    r3265459 r3297655  
    4141        'custom_slug'              => '',
    4242        'custom_post_status'       => 'draft',
     43        'custom_title_pattern'     => '',
     44        'custom_slug_pattern'      => '',
    4345    ];
    4446
     
    220222        add_settings_field(
    221223            'custom_post_status',
    222             __( 'Custom Post Status', 'just-duplicate' ),
     224            __( 'Duplicated Post Status', 'just-duplicate' ),
    223225            [ __CLASS__, 'render_custom_post_status_field' ],
     226            self::OPTION_KEY,
     227            'JUST_DUPLICATE_general'
     228        );
     229
     230        // Duplicate ACF Meta field.
     231        add_settings_field(
     232            'duplicate_acf_meta',
     233            __( 'Duplicate ACF Meta', 'just-duplicate' ),
     234            [ __CLASS__, 'render_duplicate_acf_meta_field' ],
     235            self::OPTION_KEY,
     236            'JUST_DUPLICATE_general'
     237        );
     238
     239        // Duplicate SEO Meta field.
     240        add_settings_field(
     241            'duplicate_seo_meta',
     242            __( 'Duplicate SEO Meta', 'just-duplicate' ),
     243            [ __CLASS__, 'render_duplicate_seo_meta_field' ],
     244            self::OPTION_KEY,
     245            'JUST_DUPLICATE_general'
     246        );
     247
     248        // Add fields for custom title and slug patterns.
     249        add_settings_field(
     250            'custom_title_pattern',
     251            __( 'Custom Title Pattern', 'just-duplicate' ),
     252            [ __CLASS__, 'render_custom_title_pattern_field' ],
     253            self::OPTION_KEY,
     254            'JUST_DUPLICATE_general'
     255        );
     256
     257        add_settings_field(
     258            'custom_slug_pattern',
     259            __( 'Custom Slug Pattern', 'just-duplicate' ),
     260            [ __CLASS__, 'render_custom_slug_pattern_field' ],
     261            self::OPTION_KEY,
     262            'JUST_DUPLICATE_general'
     263        );
     264
     265        // Add a setting for media attachment handling.
     266        add_settings_field(
     267            'media_attachment_handling',
     268            __( 'Media Attachment Handling', 'just-duplicate' ),
     269            [ __CLASS__, 'render_media_attachment_handling_field' ],
    224270            self::OPTION_KEY,
    225271            'JUST_DUPLICATE_general'
     
    247293            'custom_title'             => sanitize_text_field( $settings['custom_title'] ?? '' ),
    248294            'custom_slug'              => sanitize_title( $settings['custom_slug'] ?? '' ),
    249             'custom_post_status'       => in_array( $settings['custom_post_status'], [ 'draft', 'publish', 'pending' ], true ) ? $settings['custom_post_status'] : 'draft',
     295            'custom_post_status'       => in_array( $settings['custom_post_status'], [ 'draft', 'publish', 'pending', 'private' ], true ) ? $settings['custom_post_status'] : 'draft',
    250296            'schedule_duplication'     => isset( $settings['schedule_duplication'] ) ? sanitize_text_field( $settings['schedule_duplication'] ) : '',
     297            'duplicate_acf_meta'      => isset( $settings['duplicate_acf_meta'] ) ? (bool) $settings['duplicate_acf_meta'] : false,
     298            'duplicate_seo_meta'      => isset( $settings['duplicate_seo_meta'] ) ? (bool) $settings['duplicate_seo_meta'] : false,
     299            'custom_title_pattern'     => sanitize_text_field( $settings['custom_title_pattern'] ?? '' ),
     300            'custom_slug_pattern'      => sanitize_text_field( $settings['custom_slug_pattern'] ?? '' ),
     301            'media_attachment_handling' => $settings['media_attachment_handling'] ?? 'duplicate',
    251302        ];
    252303    }
     
    457508            <select name="<?php echo esc_attr( self::OPTION_KEY ); ?>[custom_post_status]">
    458509                <option value="draft" <?php selected( $settings['custom_post_status'] ?? 'draft', 'draft' ); ?>><?php esc_html_e( 'Draft', 'just-duplicate' ); ?></option>
    459                 <option value="publish" <?php selected( $settings['custom_post_status'] ?? 'draft', 'publish' ); ?>><?php esc_html_e( 'Publish', 'just-duplicate' ); ?></option>
     510                <option value="private" <?php selected( $settings['custom_post_status'] ?? 'draft', 'private' ); ?>><?php esc_html_e( 'Private', 'just-duplicate' ); ?></option>
    460511                <option value="pending" <?php selected( $settings['custom_post_status'] ?? 'draft', 'pending' ); ?>><?php esc_html_e( 'Pending', 'just-duplicate' ); ?></option>
    461512            </select>
    462513            <span class="description"><?php esc_html_e( 'Set the post status for duplicated items.', 'just-duplicate' ); ?></span>
     514        </p>
     515        <?php
     516    }
     517
     518    /**
     519     * Render the "Duplicate ACF Meta" field.
     520     *
     521     * @return void
     522     */
     523    public static function render_duplicate_acf_meta_field(): void {
     524        $settings = get_option( self::OPTION_KEY, [] );
     525        ?>
     526        <p>
     527            <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_acf_meta]" value="1" <?php checked( $settings['duplicate_acf_meta'] ?? false, true ); ?> />
     528            <label><?php esc_html_e( 'Duplicate ACF fields.', 'just-duplicate' ); ?></label>
     529        </p>
     530        <?php
     531    }
     532
     533    /**
     534     * Render the "Duplicate SEO Meta" field.
     535     *
     536     * @return void
     537     */
     538    public static function render_duplicate_seo_meta_field(): void {
     539        $settings = get_option( self::OPTION_KEY, [] );
     540        ?>
     541        <p>
     542            <input type="checkbox" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[duplicate_seo_meta]" value="1" <?php checked( $settings['duplicate_seo_meta'] ?? false, true ); ?> />
     543            <label><?php esc_html_e( 'Duplicate SEO meta fields.', 'just-duplicate' ); ?></label>
     544        </p>
     545        <?php
     546    }
     547
     548    /**
     549     * Render the "Custom Title Pattern" field.
     550     *
     551     * @return void
     552     */
     553    public static function render_custom_title_pattern_field(): void {
     554        $settings = get_option( self::OPTION_KEY, [] );
     555        ?>
     556        <p>
     557            <input type="text" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[custom_title_pattern]" value="<?php echo esc_attr( $settings['custom_title_pattern'] ?? '' ); ?>" />
     558            <span class="description"><?php esc_html_e( 'Define a custom title pattern (e.g., "Copy of %original%" or "%original% - %date%").', 'just-duplicate' ); ?></span>
     559        </p>
     560        <?php
     561    }
     562
     563    /**
     564     * Render the "Custom Slug Pattern" field.
     565     *
     566     * @return void
     567     */
     568    public static function render_custom_slug_pattern_field(): void {
     569        $settings = get_option( self::OPTION_KEY, [] );
     570        ?>
     571        <p>
     572            <input type="text" name="<?php echo esc_attr( self::OPTION_KEY ); ?>[custom_slug_pattern]" value="<?php echo esc_attr( $settings['custom_slug_pattern'] ?? '' ); ?>" />
     573            <span class="description"><?php esc_html_e( 'Define a custom slug pattern (e.g., "%original%-copy" or "%original%-%timestamp%").', 'just-duplicate' ); ?></span>
     574        </p>
     575        <?php
     576    }
     577
     578    /**
     579     * Render the "Media Attachment Handling" field.
     580     *
     581     * @return void
     582     */
     583    public static function render_media_attachment_handling_field(): void {
     584        $settings = get_option( self::OPTION_KEY, [] );
     585        ?>
     586        <p>
     587            <select name="<?php echo esc_attr( self::OPTION_KEY ); ?>[media_attachment_handling]">
     588                <option value="duplicate" <?php selected( $settings['media_attachment_handling'] ?? 'duplicate', 'duplicate' ); ?>><?php esc_html_e( 'Duplicate Media', 'just-duplicate' ); ?></option>
     589                <option value="reference" <?php selected( $settings['media_attachment_handling'] ?? 'duplicate', 'reference' ); ?>><?php esc_html_e( 'Reference Originals', 'just-duplicate' ); ?></option>
     590            </select>
     591            <span class="description"><?php esc_html_e( 'Choose whether to duplicate attached media or reference the originals.', 'just-duplicate' ); ?></span>
    463592        </p>
    464593        <?php
     
    548677            }
    549678        }
     679        if ( ! empty( $settings['duplicate_acf_meta'] ) ) {
     680            self::copy_acf_meta( $post_id, (int) $new_post_id );
     681        }
     682        if ( ! empty( $settings['duplicate_seo_meta'] ) ) {
     683            self::copy_seo_meta( $post_id, (int) $new_post_id );
     684        }
    550685    }
    551686
     
    579714            if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
    580715                wp_set_object_terms( $new_post_id, $terms, $taxonomy );
     716            }
     717        }
     718    }
     719
     720    /**
     721     * Copy ACF meta from the original post to the duplicated post.
     722     *
     723     * @param int $old_post_id Original post ID.
     724     * @param int $new_post_id New post ID.
     725     * @return void
     726     */
     727    private static function copy_acf_meta( int $old_post_id, int $new_post_id ): void {
     728        // Assuming ACF functions are available.
     729        $fields = get_field_objects( $old_post_id );
     730        if ( $fields ) {
     731            foreach ( $fields as $field ) {
     732                $value = get_field( $field['key'], $old_post_id );
     733                update_field( $field['key'], $value, $new_post_id );
     734            }
     735        }
     736    }
     737
     738    /**
     739     * Copy SEO meta from the original post to the duplicated post.
     740     *
     741     * @param int $old_post_id Original post ID.
     742     * @param int $new_post_id New post ID.
     743     * @return void
     744     */
     745    private static function copy_seo_meta( int $old_post_id, int $new_post_id ): void {
     746        // Assuming SEO meta is stored as post meta with a specific prefix.
     747        $seo_meta_keys = [ '_yoast_wpseo_title', '_yoast_wpseo_metadesc', '_yoast_wpseo_focuskw' ];
     748        foreach ( $seo_meta_keys as $key ) {
     749            $value = get_post_meta( $old_post_id, $key, true );
     750            if ( $value ) {
     751                update_post_meta( $new_post_id, $key, $value );
    581752            }
    582753        }
  • just-duplicate/trunk/includes/class-duplicate-handler.php

    r3265459 r3297655  
    141141
    142142        $settings = get_option( 'JUST_DUPLICATE_settings', [] );
     143        $title_pattern = $settings['custom_title_pattern'] ?? '%original% (Copy)';
     144        $slug_pattern = $settings['custom_slug_pattern'] ?? '%original%-copy';
     145        $post_status = $settings['custom_post_status'] ?? 'draft';
    143146
    144147        // Prepare the new post data.
    145148        $new_post = [
    146             'post_title'   => $settings['custom_title'] ?: $post->post_title . ' (Copy)',
    147             'post_name'    => $settings['custom_slug'] ?: '',
     149            'post_title'   => str_replace(
     150                ['%original%', '%date%', '%timestamp%'],
     151                [$post->post_title, date_i18n( 'Y-m-d' ), time()],
     152                $title_pattern
     153            ),
     154            'post_name'    => str_replace(
     155                ['%original%', '%date%', '%timestamp%'],
     156                [sanitize_title( $post->post_title ), date_i18n( 'Y-m-d' ), time()],
     157                $slug_pattern
     158            ),
    148159            'post_content' => $post->post_content,
    149             'post_status'  => $settings['custom_post_status'] ?? 'draft',
     160            'post_status'  => $post_status,
    150161            'post_type'    => $post->post_type,
    151162            'post_author'  => get_current_user_id(),
     
    165176
    166177        // If the original post has a featured image, duplicate it.
    167         $thumb_id = get_post_thumbnail_id( $post_id );
    168         if ( $thumb_id ) {
    169             $new_thumb_id = self::duplicate_attachment( $thumb_id, $new_post_id );
    170             if ( $new_thumb_id ) {
    171                 set_post_thumbnail( $new_post_id, $new_thumb_id );
     178        $settings = get_option( 'JUST_DUPLICATE_settings', [] );
     179        $media_handling = $settings['media_attachment_handling'] ?? 'duplicate';
     180
     181        if ( 'duplicate' === $media_handling ) {
     182            $thumb_id = get_post_thumbnail_id( $post_id );
     183            if ( $thumb_id ) {
     184                $new_thumb_id = self::duplicate_attachment( $thumb_id, $new_post_id );
     185                if ( $new_thumb_id ) {
     186                    set_post_thumbnail( $new_post_id, $new_thumb_id );
     187                }
     188            }
     189        } elseif ( 'reference' === $media_handling ) {
     190            $thumb_id = get_post_thumbnail_id( $post_id );
     191            if ( $thumb_id ) {
     192                set_post_thumbnail( $new_post_id, $thumb_id );
    172193            }
    173194        }
     
    261282     * @return void
    262283     */
    263     private static function copy_post_meta( int $old_post_id, int $new_post_id ): void {
     284    public static function copy_post_meta( int $old_post_id, int $new_post_id ): void {
    264285        $meta_data = get_post_meta( $old_post_id );
    265 
    266         // Meta keys to exclude.
    267         $exclude_keys = [
    268             '_edit_lock',
    269             '_edit_last',
    270         ];
     286        $settings = get_option( 'JUST_DUPLICATE_settings', [] );
    271287
    272288        foreach ( $meta_data as $key => $values ) {
    273             if ( in_array( $key, $exclude_keys, true ) ) {
     289            // Skip ACF meta if not enabled.
     290            if ( strpos( $key, 'acf_' ) === 0 && empty( $settings['duplicate_acf_meta'] ) ) {
    274291                continue;
    275292            }
    276293
    277             // Only copy Elementor-specific meta keys if the original post was edited in Elementor.
    278             if ( in_array( $key, [ '_elementor_edit_mode', '_elementor_data', '_elementor_template_type', '_elementor_version' ], true ) ) {
    279                 $is_elementor = get_post_meta( $old_post_id, '_elementor_edit_mode', true );
    280                 if ( ! $is_elementor ) {
    281                     continue;
     294            // Skip SEO meta if not enabled.
     295            if ( strpos( $key, '_yoast_' ) === 0 && empty( $settings['duplicate_seo_meta'] ) ) {
     296                continue;
     297            }
     298
     299            // Skip custom fields if not enabled.
     300            if ( ! empty( $settings['duplicate_custom_fields'] ) || ( ! strpos( $key, '_' ) === 0 ) ) {
     301                foreach ( $values as $value ) {
     302                    add_post_meta( $new_post_id, $key, maybe_unserialize( $value ) );
    282303                }
    283             }
    284 
    285             foreach ( $values as $value ) {
    286                 add_post_meta( $new_post_id, $key, maybe_unserialize( $value ) );
    287304            }
    288305        }
     
    349366
    350367        foreach ( $taxonomies as $taxonomy ) {
    351             $terms = wp_get_object_terms( $old_post_id, $taxonomy, [ 'fields' => 'slugs' ] );
     368            $terms = wp_get_object_terms( $old_post_id, $taxonomy, [ 'fields' => 'ids' ] );
    352369            if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
    353370                wp_set_object_terms( $new_post_id, $terms, $taxonomy );
  • just-duplicate/trunk/just-duplicate.php

    r3265459 r3297655  
    44 * Plugin URI: https://wordpress.org/plugins/just-duplicate
    55 * 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.3
     6 * Version: 1.0.4
    77 * Requires at least: 5.0
    88 * Tested up to: 6.7
     
    2121
    2222// Define plugin constants.
    23 define( 'JUST_DUPLICATE_VERSION', '1.0.3' );
     23define( 'JUST_DUPLICATE_VERSION', '1.0.4' );
    2424define( 'JUST_DUPLICATE_PATH', plugin_dir_path( __FILE__ ) );
    2525define( 'JUST_DUPLICATE_URL', plugin_dir_url( __FILE__ ) );
Note: See TracChangeset for help on using the changeset viewer.