<?php
/**
 * LazyBlocks tools.
 *
 * @package lazyblocks
 */

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

/**
 * LazyBlocks_Tools class. Class to work with LazyBlocks CPT.
 */
class LazyBlocks_Tools {
	/**
	 * Admin notices
	 *
	 * @var array
	 */
	private $notices = array();

	/**
	 * LazyBlocks_Tools constructor.
	 */
	public function __construct() {
		add_action( 'admin_menu', array( $this, 'admin_menu' ) );

		// activate/deactivate block on get request.
		add_action( 'admin_init', array( $this, 'maybe_activate_block' ) );

		// export json on get request.
		add_action( 'admin_init', array( $this, 'maybe_export_json' ) );

		// duplicate block on get request.
		add_action( 'admin_init', array( $this, 'maybe_duplicate_block' ) );

		// enqueue script on Tools page.
		add_action( 'admin_footer', array( $this, 'admin_enqueue_scripts' ) );

		// add admin notices.
		add_action( 'admin_notices', array( $this, 'admin_notices' ) );
	}

	/**
	 * Admin menu.
	 */
	public function admin_menu() {
		$page = add_submenu_page(
			'edit.php?post_type=lazyblocks',
			esc_html__( 'Export / Import', 'lazy-blocks' ),
			esc_html__( 'Export / Import', 'lazy-blocks' ),
			'manage_options',
			'lazyblocks_tools',
			array( $this, 'render_tools_page' )
		);

		add_action( 'load-' . $page, array( $this, 'import_json' ) );
	}

	/**
	 * Tools page
	 */
	public function render_tools_page() {
		?>
		<div class="wrap">
			<h1 class="wp-heading-inline"><?php echo esc_html__( 'Export / Import', 'lazy-blocks' ); ?></h1>

			<div id="poststuff">
				<div class="lazyblocks-tools-page">
					<span class="spinner is-active"></span>
				</div>
			</div>
			<style type="text/css">
				.lazyblocks-tools-page > .spinner {
					float: left;
					margin-left: 0;
				}
			</style>
		</div>
		<?php
	}

	/**
	 * Clear block data to export.
	 *
	 * @param array $block block data.
	 *
	 * @return array
	 */
	public function clean_block_to_export( $block ) {
		$db_blocks = lazyblocks()->blocks()->get_blocks( true );
		$controls  = lazyblocks()->controls()->get_controls();

		foreach ( $db_blocks as $db_block ) {
			if ( $db_block['id'] === $block['id'] ) {
				// Remove unused fields from controls data.
				if ( 'lazyblock/example-block' === $block['slug'] && ! empty( $block['controls'] ) ) {
					foreach ( $block['controls'] as $k => $control ) {
						if ( ! isset( $control['type'] ) || ! isset( $controls[ $control['type'] ] ) ) {
							continue;
						}

						$control_data = $controls[ $control['type'] ];

						// Remove restricted fields.
						$restrictions_to_remove = array(
							'name',
							'label',
							'default',
							'placement',
							'group',
							'width',
							'required',
							'hide_if_not_selected',
							'translate',
							'save_in_meta',
						);

						foreach ( $restrictions_to_remove as $restriction ) {
							if (
								isset( $control_data['restrictions'][ $restriction . '_settings' ] )
								&& ! $control_data['restrictions'][ $restriction . '_settings' ]
								&& isset( $block['controls'][ $k ][ $restriction ] )
							) {
								unset( $block['controls'][ $k ][ $restriction ] );

								if ( 'save_in_meta' === $restriction && isset( $block['controls'][ $k ]['save_in_meta_name'] ) ) {
									unset( $block['controls'][ $k ]['save_in_meta_name'] );
								}
							}
						}

						// Remove default fields.
						$default_fields_to_remove = array(
							'default'              => '',
							'help'                 => '',
							'child_of'             => '',
							'placeholder'          => '',
							'characters_limit'     => '',
							'width'                => '100',
							'group'                => 'default',
							'hide_if_not_selected' => 'false',
							'required'             => 'false',
							'translate'            => 'false',
							'save_in_meta'         => 'false',
							'save_in_meta_name'    => '',
						);

						foreach ( $default_fields_to_remove as $field => $val ) {
							if ( isset( $block['controls'][ $k ][ $field ] ) && $val === $block['controls'][ $k ][ $field ] ) {
								unset( $block['controls'][ $k ][ $field ] );

								if ( 'save_in_meta' === $field && isset( $block['controls'][ $field ]['save_in_meta_name'] ) ) {
									unset( $block['controls'][ $field ]['save_in_meta_name'] );
								}
							}
						}
					}
				}

				// Remove `edit_url`.
				if ( isset( $block['edit_url'] ) ) {
					unset( $block['edit_url'] );
				}
			}
		}

		return $block;
	}

	/**
	 * Clear PHP string code.
	 *
	 * @param string $string code string.
	 * @return string
	 */
	public function clean_php_string_code( $string ) {
		$str_replace  = array(
			'  '      => '    ',
			'array (' => 'array(',
		);
		$preg_replace = array(
			'/([ \r\n]+?)array/' => ' array',
			'/[0-9]+ => array/'  => 'array',
			'/\n/'               => "\n    ",
		);

		// change 2-spaces to 4-spaces.
		$string = str_replace( array_keys( $str_replace ), array_values( $str_replace ), $string );

		// correct formats '=> array('.
		// additional spaces.
		$string = preg_replace( array_keys( $preg_replace ), array_values( $preg_replace ), $string );

		return $string;
	}

	/**
	 * Get block PHP string code.
	 *
	 * @param array $block block data.
	 * @return string
	 */
	public function get_block_php_string_code( $block ) {
		$block = $this->clean_block_to_export( $block );

		$result = '';

		$result .= "\nlazyblocks()->add_block( ";
		// phpcs:ignore
		$result .= var_export( $block, true );
		$result .= " );\n";

		return $this->clean_php_string_code( $result );
	}

	/**
	 * Get template PHP string code.
	 *
	 * @param array $template template data.
	 * @return string
	 */
	public function get_template_php_string_code( $template ) {
		$result = '';

		$result .= "\nlazyblocks()->add_template( ";
		// phpcs:ignore
		$result .= var_export( $template, true );
		$result .= " );\n";

		return $this->clean_php_string_code( $result );
	}

	/**
	 * Enqueue script for Tools page.
	 */
	public function admin_enqueue_scripts() {
		$screen = get_current_screen();

		if ( 'lazyblocks_page_lazyblocks_tools' !== $screen->id ) {
			return;
		}

		$blocks    = lazyblocks()->blocks()->get_blocks( true, true, true );
		$templates = lazyblocks()->templates()->get_templates( true, true );
		$data      = array(
			'blocks'    => array(),
			'templates' => array(),
			'nonce'     => wp_create_nonce( 'lzb-tools-import-nonce' ),
		);

		if ( ! empty( $blocks ) ) {
			foreach ( $blocks as $block ) {
				$data['blocks'][] = array(
					'data'            => $block,
					'php_string_code' => $this->get_block_php_string_code( $block ),
				);
			}
		}
		if ( ! empty( $templates ) ) {
			foreach ( $templates as $template ) {
				$data['templates'][] = array(
					'data'            => $template,
					'php_string_code' => $this->get_template_php_string_code( $template ),
				);
			}
		}

		// Lazyblocks Tools.
		LazyBlocks_Assets::enqueue_script( 'lazyblocks-tools', 'build/admin-tools' );
		wp_localize_script( 'lazyblocks-tools', 'lazyblocksToolsData', $data );

		LazyBlocks_Assets::enqueue_style( 'lazyblocks-tools', 'build/admin-tools' );
		wp_style_add_data( 'lazyblocks-tools', 'rtl', 'replace' );
	}

	/**
	 * Activate blocks.
	 *
	 * @param array  $post_ids post ids.
	 * @param string $type action type.
	 */
	public function activate( $post_ids, $type = 'activate' ) {
		$count = count( $post_ids );

		if ( 0 === $count ) {
			return;
		}

		foreach ( $post_ids as $post_id ) {
			wp_update_post(
				array(
					'ID'          => $post_id,
					'post_status' => 'activate' === $type ? 'publish' : 'draft',
				)
			);
		}

		// Redirect.
		wp_safe_redirect( admin_url( 'edit.php?post_type=lazyblocks&lazyblocks_activation_type=' . $type . '&lazyblocks_activate_complete=' . $count . ( 1 === $count ? '&lazyblocks_block_id=' . $post_ids[0] : '' ) ) );
		exit;
	}

	/**
	 * Deactivate blocks.
	 *
	 * @param array $post_ids post ids.
	 */
	public function deactivate( $post_ids ) {
		$this->activate( $post_ids, 'deactivate' );
	}

	/**
	 * Activate block.
	 */
	public function maybe_activate_block() {
		$blocks_activated  = filter_input( INPUT_GET, 'lazyblocks_activate_complete', FILTER_SANITIZE_NUMBER_INT );
		$activation_type   = isset( $_GET['lazyblocks_activation_type'] ) ? sanitize_text_field( wp_unslash( $_GET['lazyblocks_activation_type'] ) ) : false;
		$block_id_complete = filter_input( INPUT_GET, 'lazyblocks_block_id', FILTER_SANITIZE_NUMBER_INT );

		// Add notice for success activate.
		if ( $blocks_activated ) {
			$message = '';

			if ( $block_id_complete ) {
				$block_title = get_the_title( $block_id_complete );

				// translators: %s - block title.
				$message = 'activate' === $activation_type ? sprintf( esc_html__( 'Block "%s" activated successfully.', 'lazy-blocks' ), $block_title ) : sprintf( esc_html__( 'Block "%s" deactivated successfully.', 'lazy-blocks' ), $block_title );
			} else {
				// translators: %s - number of blocks.
				$message = 'activate' === $activation_type ? sprintf( esc_html( _n( 'Activated %s block', 'Activated %s blocks', $blocks_activated, 'lazy-blocks' ) ), $blocks_activated ) : sprintf( esc_html( _n( 'Deactivated %s block', 'Deactivated %s blocks', $blocks_activated, 'lazy-blocks' ) ), $blocks_activated );
			}

			if ( $message ) {
				$this->add_notice( $message, 'success' );
			}
		}

		$nonce = isset( $_GET['lazyblocks_activate_block_nonce'] ) ? $_GET['lazyblocks_activate_block_nonce'] : false;
		if ( ! $nonce || ! wp_verify_nonce( $nonce, 'lzb-activate-block-nonce' ) ) {
			return;
		}

		$action  = isset( $_GET['lazyblocks_activate_block'] ) ? 'activate' : ( isset( $_GET['lazyblocks_deactivate_block'] ) ? 'deactivate' : false );
		$post_id = filter_input( INPUT_GET, 'activate' === $action ? 'lazyblocks_activate_block' : 'lazyblocks_deactivate_block', FILTER_SANITIZE_NUMBER_INT );

		if ( $post_id && $action && current_user_can( 'edit_lazyblock', $post_id ) ) {
			if ( 'activate' === $action ) {
				$this->activate( array( $post_id ) );
			} elseif ( 'deactivate' === $action ) {
				$this->deactivate( array( $post_id ) );
			}
		}
	}

	/**
	 * Import JSON.
	 */
	public function import_json() {
		// Check for nonce security.
		// phpcs:ignore
		$nonce = isset( $_POST[ 'lzb_tools_import_nonce' ] ) ? $_POST[ 'lzb_tools_import_nonce' ] : false;

		if ( ! $nonce || ! wp_verify_nonce( $nonce, 'lzb-tools-import-nonce' ) ) {
			return;
		}

		// Check file size.
		if ( empty( $_FILES['lzb_tools_import_json']['size'] ) ) {
			$this->add_notice( esc_html__( 'No file selected', 'lazy-blocks' ), 'warning' );
			return;
		}

		// Get file data.
		// phpcs:ignore
		$file = $_FILES['lzb_tools_import_json'];

		// Check for errors.
		if ( $file['error'] ) {
			$this->add_notice( esc_html__( 'Error uploading file. Please try again', 'lazy-blocks' ), 'warning' );
			return;
		}

		// Check file type.
		if ( pathinfo( $file['name'], PATHINFO_EXTENSION ) !== 'json' ) {
			$this->add_notice( esc_html__( 'Incorrect file type', 'lazy-blocks' ), 'warning' );
			return;
		}

		// Read JSON.
		// phpcs:ignore
		$json = file_get_contents( $file['tmp_name'] );
		$json = json_decode( $json, true );

		// Check if empty.
		if ( ! $json || ! is_array( $json ) ) {
			$this->add_notice( esc_html__( 'Import file empty', 'lazy-blocks' ), 'warning' );
			return;
		}

		$json = apply_filters( 'lzb/import_json', $json );

		// Remember imported ids.
		$imported_blocks    = array();
		$imported_templates = array();

		// Loop over json.
		foreach ( $json as $data ) {
			if ( isset( $data['id'] ) ) {
				// check if block data.
				if ( isset( $data['icon'] ) || isset( $data['category'] ) || isset( $data['supports'] ) || isset( $data['controls'] ) ) {
					$imported_id = $this->import_block( $data );

					if ( $imported_id ) {
						$imported_blocks[] = $imported_id;
					}

					// check if template.
				} elseif ( isset( $data['post_types'] ) ) {
					$imported_id = $this->import_template( $data );

					if ( $imported_id ) {
						$imported_templates[] = $imported_id;
					}
				}
			}
		}

		// imported blocks.
		if ( ! empty( $imported_blocks ) ) {
			// Count number of imported field groups.
			$total_blocks = count( $imported_blocks );

			// Generate text.
			// translators: %s - number of blocks.
			$text = sprintf( esc_html( _n( 'Imported %s block', 'Imported %s blocks', $total_blocks, 'lazy-blocks' ) ), $total_blocks );

			// Add links to text.
			$links = array();
			foreach ( $imported_blocks as $id ) {
				$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
			}
			$text .= ' ' . implode( ', ', $links );

			// Add notice.
			$this->add_notice( $text, 'success' );
		}

		// imported templates.
		if ( ! empty( $imported_templates ) ) {
			// Count number of imported field groups.
			$total_templates = count( $imported_templates );

			// Generate text.
			// translators: %s - number of templates.
			$text = sprintf( esc_html( _n( 'Imported %s template', 'Imported %s templates', $total_templates, 'lazy-blocks' ) ), $total_templates );

			// Add links to text.
			$links = array();
			foreach ( $imported_templates as $id ) {
				$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
			}
			$text .= ' ' . implode( ', ', $links );

			// Add notice.
			$this->add_notice( $text, 'success' );
		}
	}

	/**
	 * Export JSON.
	 */
	public function maybe_export_json() {
		$block_id  = filter_input( INPUT_GET, 'lazyblocks_export_block', FILTER_SANITIZE_NUMBER_INT );
		$block_ids = filter_input_array(
			INPUT_GET,
			array(
				'lazyblocks_export_blocks' => array(
					'filter' => FILTER_SANITIZE_NUMBER_INT,
					'flags'  => FILTER_REQUIRE_ARRAY,
				),
			)
		);
		$block_ids = is_array( $block_ids ) && isset( $block_ids['lazyblocks_export_blocks'] ) ? $block_ids['lazyblocks_export_blocks'] : array();

		$template_ids = filter_input_array(
			INPUT_GET,
			array(
				'lazyblocks_export_templates' => array(
					'filter' => FILTER_SANITIZE_NUMBER_INT,
					'flags'  => FILTER_REQUIRE_ARRAY,
				),
			)
		);
		$template_ids = is_array( $template_ids ) && isset( $template_ids['lazyblocks_export_templates'] ) ? $template_ids['lazyblocks_export_templates'] : array();

		if ( isset( $block_id ) && current_user_can( 'read_lazyblock', $block_id ) ) {
			$this->export_json( array( $block_id ) );
		} elseif ( isset( $block_ids ) && ! empty( $block_ids ) && current_user_can( 'read_lazyblock', $block_ids[0] ) ) {
			$this->export_json( $block_ids );
		} elseif ( isset( $template_ids ) && ! empty( $template_ids ) && current_user_can( 'read_lazyblock', $template_ids[0] ) ) {
			$this->export_json( $template_ids, 'templates' );
		}
	}

	/**
	 * Export JSON.
	 *
	 * @param array  $items blocks/templates to export.
	 * @param string $type export type (blocks or templates).
	 */
	public function export_json( $items, $type = 'blocks' ) {
		$result = array();

		// fix string ids to int.
		foreach ( $items as $k => $id ) {
			$items[ $k ] = (int) $id;
		}

		if ( 'blocks' === $type ) {
			$blocks = lazyblocks()->blocks()->get_blocks( true );

			foreach ( $blocks as $block ) {
				if ( in_array( $block['id'], $items, true ) ) {
					$result[] = $this->clean_block_to_export( $block );
				}
			}
		} elseif ( 'templates' === $type ) {
			$templates = lazyblocks()->templates()->get_templates( true );

			foreach ( $templates as $template ) {
				if ( in_array( $template['id'], $items, true ) ) {
					$result[] = $template;
				}
			}
		}

		header( 'Content-Description: File Transfer' );
		header( 'Content-disposition: attachment; filename=lzb-export-' . $type . '-' . date_i18n( 'Y-m-d' ) . '.json' );
		header( 'Content-type: application/json; charset=utf-8' );
		echo wp_json_encode( $result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );

		die();
	}

	/**
	 * Import block.
	 *
	 * @param array $data - new block data.
	 */
	public function import_block( $data ) {
		$meta        = array();
		$meta_prefix = 'lazyblocks_';
		$post_id     = wp_insert_post(
			array(
				'post_title'  => wp_strip_all_tags( $data['title'] ),
				'post_status' => 'publish',
				'post_type'   => 'lazyblocks',
			)
		);

		// TODO - reuse this data from /controls/_base/index.php .
		$default_control_attributes = array(
			'type'                 => 'text',
			'name'                 => '',
			'default'              => '',
			'label'                => '',
			'help'                 => '',
			'child_of'             => '',
			'placement'            => 'content',
			'group'                => 'default',
			'width'                => '100',
			'hide_if_not_selected' => 'false',
			'required'             => 'false',
			'translate'            => 'false',
			'save_in_meta'         => 'false',
			'save_in_meta_name'    => '',
		);

		if ( 0 < $post_id ) {
			// add 'lazyblocks_' prefix.
			foreach ( $data as $k => $val ) {
				if ( ( 'code' === $k || 'supports' === $k ) && is_array( $val ) ) {
					foreach ( $val as $i => $inner_val ) {
						$meta[ $meta_prefix . $k . '_' . $i ] = $inner_val;
					}
				} else {
					if ( 'slug' === $k ) {
						$val = substr( $val, strpos( $val, '/' ) + 1 );
					} elseif ( 'keywords' === $k ) {
						$val = implode( ',', $val );
					} elseif ( 'controls' === $k ) {
						$controls = array();

						foreach ( $val as $i => $inner_val ) {
							$controls[ $i ] = array_merge( $default_control_attributes, $inner_val );
						}

						$val = $controls;
					}

					$meta[ $meta_prefix . $k ] = $val;
				}
			}

			lazyblocks()->blocks()->save_meta_boxes( $post_id, $meta );

			do_action( 'lzb/import/block', $post_id, $data );

			return $post_id;
		}

		return false;
	}

	/**
	 * Import template.
	 *
	 * @param array $data - new template data.
	 */
	private function import_template( $data ) {
		if ( ! isset( $data['post_types'] ) || empty( $data['post_types'] ) ) {
			return false;
		}

		$templates = lazyblocks()->templates()->get_templates( true );

		// check if template already exists.
		foreach ( $templates as $template ) {
			if ( count( array_intersect( $data['post_types'], $template['post_types'] ) ) > 0 ) {
				// translators: %s - post type.
				$text = sprintf( esc_html__( 'Template for these post types \'%s\' already exists.', 'lazy-blocks' ), implode( ',', $data['post_types'] ) );
				$this->add_notice( $text, 'warning' );
				return false;
			}
		}

		$post_id = wp_insert_post(
			array(
				'post_title'  => wp_strip_all_tags( $data['title'] ),
				'post_status' => 'publish',
				'post_type'   => 'lazyblocks_templates',
			)
		);

		if ( 0 < $post_id ) {
			add_post_meta( $post_id, '_lzb_template_blocks', rawurlencode( wp_json_encode( $data['blocks'] ) ) );
			add_post_meta( $post_id, '_lzb_template_convert_blocks_to_content', true );
			add_post_meta( $post_id, '_lzb_template_lock', $data['template_lock'] );
			add_post_meta( $post_id, '_lzb_template_post_types', $data['post_types'] );

			do_action( 'lzb/import/template', $post_id, $data );

			return $post_id;
		}

		return false;
	}

	/**
	 * Maybe Duplicate Block.
	 */
	public function maybe_duplicate_block() {
		$block_id          = filter_input( INPUT_GET, 'lazyblocks_duplicate_block', FILTER_SANITIZE_NUMBER_INT );
		$block_id_complete = filter_input( INPUT_GET, 'lazyblocks_duplicate_complete', FILTER_SANITIZE_NUMBER_INT );

		// Duplicate block.
		if ( isset( $block_id ) && current_user_can( 'read_lazyblock', $block_id ) ) {
			$this->duplicate_block( $block_id );
		}

		// Add notice for success duplicate.
		if ( isset( $block_id_complete ) && $block_id_complete ) {
			$post = get_post( $block_id_complete );

			if ( isset( $post ) && $post ) {
				// translators: %s - post title.
				$text = sprintf( esc_html__( 'Added new block \'%s\'.', 'lazy-blocks' ), $post->post_title );
				$this->add_notice( $text, 'success' );
			}
		}
	}

	/**
	 * Duplicate Block.
	 *
	 * Thanks to:
	 * - https://wordpress.org/plugins/duplicate-post/
	 * - https://wordpress.org/plugins/duplicate-page/
	 *
	 * @param int $block_id block ID to duplicate.
	 */
	public function duplicate_block( $block_id ) {
		// Check for nonce security.
		// phpcs:ignore
		$nonce = isset( $_GET[ 'lazyblocks_duplicate_block_nonce' ] ) ? $_GET[ 'lazyblocks_duplicate_block_nonce' ] : false;

		if ( ! $nonce || ! wp_verify_nonce( $nonce, 'lzb-duplicate-block-nonce' ) ) {
			return;
		}

		$post            = get_post( $block_id );
		$current_user    = wp_get_current_user();
		$new_post_author = $current_user->ID;

		if ( isset( $post ) && $post ) {
			$post_name    = $post->post_name;
			$post_title   = $post->post_title;
			$copy_postfix = esc_html__( '(Copy)', 'lazy-blocks' );

			// Add (Copy) postfix to duplicated block title if needed.
			if ( ! empty( $post_title ) && ! str_contains( $post_title, $copy_postfix ) ) {
				$post_title = $post_title . ' ' . $copy_postfix;
			}

			// New post data array.
			$args = array(
				'comment_status' => $post->comment_status,
				'ping_status'    => $post->ping_status,
				'post_author'    => $new_post_author,
				'post_content'   => $post->post_content,
				'post_excerpt'   => $post->post_excerpt,
				'post_name'      => $post_name,
				'post_parent'    => $post->post_parent,
				'post_password'  => $post->post_password,
				// We must set the status to publish for the slug generation function (wp_unique_post_slug) to work correctly.
				'post_status'    => 'publish',
				'post_title'     => $post_title,
				'post_type'      => $post->post_type,
				'to_ping'        => $post->to_ping,
				'menu_order'     => $post->menu_order,
			);

			// Insert new post.
			$new_post_id = wp_insert_post( $args );

			// Get all current post terms ad set them to the new post.
			$taxonomies = get_object_taxonomies( $post->post_type );

			foreach ( $taxonomies as $taxonomy ) {
				$post_terms = wp_get_object_terms( $block_id, $taxonomy, array( 'fields' => 'slugs' ) );
				wp_set_object_terms( $new_post_id, $post_terms, $taxonomy, false );
			}

			// Duplicate all post meta.
			$post_meta_keys = get_post_custom_keys( $block_id );
			if ( ! empty( $post_meta_keys ) ) {
				// Default meta field names to be filtered out.
				$meta_exclude_list = array(
					'_edit_lock',
					'_edit_last',
					'_dp_original',
					'_dp_is_rewrite_republish_copy',
					'_dp_has_rewrite_republish_copy',
					'_dp_has_been_republished',
					'_dp_creation_date_gmt',
				);

				$meta_exclude_list_string = '(' . implode( ')|(', $meta_exclude_list ) . ')';

				if ( strpos( $meta_exclude_list_string, '*' ) !== false ) {
					$meta_exclude_list_string = str_replace( array( '*' ), array( '[a-zA-Z0-9_]*' ), $meta_exclude_list_string );

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

				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_post_id, $meta_key );

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

						if ( 'lazyblocks_slug' === $meta_key ) {
							// Copy new post slug to meta.
							$new_post   = get_post( $new_post_id );
							$meta_value = $new_post->post_name;
						}

						add_post_meta( $new_post_id, $meta_key, wp_slash( $meta_value ) );
					}
				}
			}

			// Change the status to draft after all manipulations with the slug.
			wp_update_post(
				array(
					'post_type'   => $post->post_type,
					'ID'          => $new_post_id,
					'post_status' => 'draft',
				)
			);

			// Redirect.
			wp_safe_redirect( admin_url( 'edit.php?post_type=lazyblocks&lazyblocks_duplicate_complete=' . $new_post_id ) );

			exit;
		}
	}

	/**
	 * Add notice
	 *
	 * @param string $text - notice text.
	 * @param string $type - notice type [success, warning, error, info].
	 * @return void
	 */
	private function add_notice( $text, $type ) {
		$this->notices[] = array(
			'text' => $text,
			'type' => $type,
		);
	}

	/**
	 * Add admin notices if available
	 */
	public function admin_notices() {
		if ( ! empty( $this->notices ) ) {
			foreach ( $this->notices as $notice ) {
				?>
				<div class="notice notice-<?php echo esc_attr( $notice['type'] ); ?> is-dismissible">
					<p><?php echo wp_kses_post( $notice['text'] ); ?></p>
				</div>
				<?php
			}
		}
	}
}
