HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/advanced-ads-pro/modules/duplicate-ads/admin.class.php
<?php // phpcs:ignore WordPress.Files.FileName
/**
 * Duplicate ads in admin class
 *
 * @package     AdvancedAds\Pro
 * @author      Advanced Ads <info@wpadvancedads.com>
 */

use AdvancedAds\Constants;
use AdvancedAds\Framework\Utilities\Params;
use AdvancedAds\Utilities\Conditional;

/**
 * Class Advanced_Ads_Pro_Module_Duplicate_Ads_Admin
 * Admin logic to duplicate an existing ads.
 */
class Advanced_Ads_Pro_Module_Duplicate_Ads_Admin {

	/**
	 * Advanced_Ads_Pro_Module_Duplicate_Ads_Admin constructor.
	 */
	public function __construct() {
		add_action( 'admin_init', [ $this, 'admin_init' ] );
		add_action( 'admin_action_advanced_ads_duplicate_ad', [ $this, 'duplicate_ad' ] );
	}

	/**
	 * On admin init
	 */
	public function admin_init() {
		// add Duplicate link to ad overview list.
		add_filter( 'post_row_actions', [ $this, 'render_duplicate_link' ], 10, 2 );
		// add Duplicate link to post submit box.
		add_action( 'post_submitbox_start', [ $this, 'render_duplicate_link_in_submit_box' ] );
	}

	/**
	 * Add the link to action list for post_row_actions
	 *
	 * @param array  $actions list of existing actions.
	 * @param object $post Post object.
	 *
	 * @return array with actions.
	 */
	public function render_duplicate_link( $actions, $post ) {
		if (
			isset( $post->post_type ) &&
			Constants::POST_TYPE_AD === $post->post_type &&
			Conditional::user_can( 'advanced_ads_edit_ads' )
		) {
			$actions['copy-ad'] = self::get_duplicate_link( $post->ID );
		}

		return $actions;
	}

	/**
	 * Add the link to the submit box on the ad edit screen.
	 */
	public function render_duplicate_link_in_submit_box() {
		global $post;

		if (
			isset( $post->post_type ) &&
			'edit' === $post->filter &&
			Constants::POST_TYPE_AD === $post->post_type &&
			Conditional::user_can( 'advanced_ads_edit_ads' ) ) {
			?>
			<div>
				<?php echo self::get_duplicate_link( $post->ID ); // phpcs:ignore ?>
			</div>
			<?php
		}
	}

	/**
	 * Build the duplicate URL
	 *
	 * @param int $ad_id ID of the ad.
	 *
	 * @return string
	 */
	public static function get_duplicate_link( $ad_id ) {

		$action = '?action=advanced_ads_duplicate_ad&amp;ad_id=' . $ad_id;
		$url    = wp_nonce_url( admin_url( 'admin.php' . $action ), 'duplicate-ad-' . $ad_id );

		return '<a href="' . $url . '" title="' . esc_attr__( 'Create a copy of this ad', 'advanced-ads-pro' ) . '">' . esc_html__( 'Duplicate', 'advanced-ads-pro' ) . '</a>';
	}

	/**
	 * Save a copy of an ad using the same status as the original ad.
	 */
	public function duplicate_ad() {
		$action = Params::get( 'action' );
		$ad_id  = Params::get( 'ad_id', 0, FILTER_VALIDATE_INT );
		if (
			! $action
			|| 'advanced_ads_duplicate_ad' !== $action
			|| ! $ad_id
			|| ! Conditional::user_can( 'advanced_ads_edit_ads' )
		) {
			return;
		}

		check_admin_referer( 'duplicate-ad-' . $ad_id );

		$ad = get_post( $ad_id );

		// copy the ad.
		if ( isset( $ad ) && null !== $ad ) {
			// add copy logic.
			$new_id = $this->create_copy( $ad );

			// redirect to the ad edit page of the new ad.
			wp_safe_redirect( admin_url( 'post.php?action=edit&post=' . $new_id ) );
		}
	}

	/**
	 * Create the copy of an ad.
	 *
	 * @param WP_POST $ad ad object.
	 *
	 * @return mixed
	 */
	public function create_copy( $ad ) {

		// return original ad ID if we are not using the correct post type.
		if ( empty( $ad->post_type ) || Constants::POST_TYPE_AD !== $ad->post_type ) {
			return $ad->ID;
		}

		$new_ad = [];

		$new_ad['post_type']   = $ad->post_type;
		$new_ad['post_status'] = isset( $ad->post_status ) ? $ad->post_status : 'draft';
		$copy_suffix           = ' (' . _x( 'copy', 'noun', 'advanced-ads-pro' ) . ' at ' . current_time( 'Y-m-d H:i:s' ) . ')';
		$new_ad['post_title']  = isset( $ad->post_title ) ? $ad->post_title . $copy_suffix : $copy_suffix;

		// use current user as author – not really needed though.
		$new_ad_author         = wp_get_current_user();
		$new_ad['post_author'] = $new_ad_author->ID;

		// copy content.
		$new_ad['post_content'] = $ad->post_content;

		// save the ad. WordPress will handle missing fields.
		$new_ad_id = wp_insert_post( wp_slash( $new_ad ) );

		/**
		 * Handle post meta of the ad
		 */
		/**
		 * Copy the meta information of a post to another post
		 */
		$post_meta_keys = get_post_custom_keys( $ad->ID );
		if ( empty( $post_meta_keys ) ) {
			return;
		}

		// handle exceptions for post meta key that should not be copied.
		$meta_blacklist[] = '_edit_lock';                       // edit lock.
		$meta_blacklist[] = '_edit_last';                       // edit last.
		$meta_blacklist[] = 'slide_template';                   // unknown plugin.
		$meta_blacklist[] = 'tps_options';                      // unknown plugin.
		$meta_blacklist[] = 'isc_post_images';                  // Image Source Control plugin.
		$meta_blacklist[] = '_wp_old_slug';                     // WooCommerce.
		$meta_blacklist[] = '_vc_post_settings';                // Visual Composer.
		$meta_blacklist[] = 'post_views_count';                 // unknown plugin.
		$meta_blacklist[] = 'advanced_ads_selling_order';       // Advanced Ads Selling Ads add-on (order data).
		$meta_blacklist[] = 'advanced_ads_selling_order_item';  // Advanced Ads Selling Ads add-on (order item data).

		// allow other plugins to filter the list.
		$meta_blacklist = apply_filters( 'advanced_ads_pro_duplicate_meta_blacklist', $meta_blacklist );

		$meta_keys = array_diff( $post_meta_keys, $meta_blacklist );

		// get values and add them to the ad.
		foreach ( $meta_keys as $meta_key ) {
			$meta_values = get_post_custom_values( $meta_key, $ad->ID );

			foreach ( $meta_values as $meta_value ) {
				$meta_value = maybe_unserialize( $meta_value );

				// Tracking add-on: remove value for public tracking ID because it needs to be unique per ad.
				if ( 'advanced_ads_ad_options' === $meta_key && isset( $meta_value['tracking']['public-id'] ) ) {
					unset( $meta_value['tracking']['public-id'] );
				}

				add_post_meta( $new_ad_id, $meta_key, $meta_value );
			}
		}

		return $new_ad_id;
	}
}