HEX
Server: LiteSpeed
System: Linux eko108.isimtescil.net 4.18.0-477.21.1.lve.1.el8.x86_64 #1 SMP Tue Sep 5 23:08:35 UTC 2023 x86_64
User: uyarreklamcomtr (11202)
PHP: 7.4.33
Disabled: opcache_get_status
Upload Files
File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/Templates.tar
digital_product.csv000064400000000067151546705260010454 0ustar00Type,Name,Published
"simple, downloadable, virtual",,-1external_product.csv000064400000000040151546705260010650 0ustar00Type,Name,Published
external,,-1grouped_product.csv000064400000000040151546705260010473 0ustar00Type,Name,Published
grouped,,-1
physical_product.csv000064400000000036151546705260010647 0ustar00Type,Name,Published
simple,,-1variable_product.csv000064400000000040151546705260010613 0ustar00Type,Name,Published
variable,,-1AbstractPageTemplate.php000064400000005707151550724220011325 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * AbstractPageTemplate class.
 *
 * Shared logic for page templates.
 *
 * @internal
 */
abstract class AbstractPageTemplate {
	/**
	 * Page Template functionality is only initialized when using a block theme.
	 */
	public function __construct() {
		if ( wc_current_theme_is_fse_theme() ) {
			$this->init();
		}
	}

	/**
	 * Initialization method.
	 */
	protected function init() {
		add_filter( 'page_template_hierarchy', array( $this, 'page_template_hierarchy' ), 1 );
		add_action( 'current_screen', array( $this, 'page_template_editor_redirect' ) );
		add_filter( 'pre_get_document_title', array( $this, 'page_template_title' ) );
	}

	/**
	 * Returns the template slug.
	 *
	 * @return string
	 */
	abstract public static function get_slug();

	/**
	 * Returns the page object assigned to this template/page.
	 *
	 * @return \WP_Post|null Post object or null.
	 */
	abstract public static function get_placeholder_page();

	/**
	 * Should return the title of the page.
	 *
	 * @return string
	 */
	abstract public static function get_template_title();

	/**
	 * Should return true on pages/endpoints/routes where the template should be shown.
	 *
	 * @return boolean
	 */
	abstract protected function is_active_template();

	/**
	 * Returns the URL to edit the template.
	 *
	 * @return string
	 */
	protected function get_edit_template_url() {
		return admin_url( 'site-editor.php?postType=wp_template&postId=woocommerce%2Fwoocommerce%2F%2F' . $this->get_slug() );
	}

	/**
	 * When the page should be displaying the template, add it to the hierarchy.
	 *
	 * This places the template name e.g. `cart`, at the beginning of the template hierarchy array. The hook priority
	 * is 1 to ensure it runs first; other consumers e.g. extensions, could therefore inject their own template instead
	 * of this one when using the default priority of 10.
	 *
	 * @param array $templates Templates that match the pages_template_hierarchy.
	 */
	public function page_template_hierarchy( $templates ) {
		if ( $this->is_active_template() ) {
			array_unshift( $templates, $this->get_slug() );
		}
		return $templates;
	}

	/**
	 * Redirect the edit page screen to the template editor.
	 *
	 * @param \WP_Screen $current_screen Current screen information.
	 */
	public function page_template_editor_redirect( \WP_Screen $current_screen ) {
		$page         = $this->get_placeholder_page();
		$edit_page_id = 'page' === $current_screen->id && ! empty( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		if ( $page && $edit_page_id === $page->ID ) {
			wp_safe_redirect( $this->get_edit_template_url() );
			exit;
		}
	}

	/**
	 * Filter the page title when the template is active.
	 *
	 * @param string $title Page title.
	 * @return string
	 */
	public function page_template_title( $title ) {
		if ( $this->is_active_template() ) {
			return $this->get_template_title();
		}
		return $title;
	}
}
AbstractTemplateCompatibility.php000064400000013102151550724220013246 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * AbstractTemplateCompatibility class.
 *
 * To bridge the gap on compatibility with PHP hooks and blockified templates.
 *
 * @internal
 */
abstract class AbstractTemplateCompatibility {
	/**
	 * The data of supported hooks, containing the hook name, the block name,
	 * position, and the callbacks.
	 *
	 * @var array $hook_data The hook data.
	 */
	protected $hook_data;

	/**
	 * Initialization method.
	 */
	public function init() {
		if ( ! wc_current_theme_is_fse_theme() ) {
			return;
		}

		$this->set_hook_data();

		add_filter(
			'render_block_data',
			function( $parsed_block, $source_block, $parent_block ) {
				/**
				* Filter to disable the compatibility layer for the blockified templates.
				*
				* This hook allows to disable the compatibility layer for the blockified templates.
				*
				* @since TBD
				* @param boolean.
				*/
				$is_disabled_compatility_layer = apply_filters( 'woocommerce_disable_compatibility_layer', false );

				if ( $is_disabled_compatility_layer ) {
					return $parsed_block;
				}

				return $this->update_render_block_data( $parsed_block, $source_block, $parent_block );

			},
			10,
			3
		);

		add_filter(
			'render_block',
			function ( $block_content, $block ) {
				/**
				* Filter to disable the compatibility layer for the blockified templates.
				*
				* This hook allows to disable the compatibility layer for the blockified.
				*
				* @since TBD
				* @param boolean.
				*/
				$is_disabled_compatility_layer = apply_filters( 'woocommerce_disable_compatibility_layer', false );

				if ( $is_disabled_compatility_layer ) {
					return $block_content;
				}

				return $this->inject_hooks( $block_content, $block );
			},
			10,
			2
		);
	}

	/**
	 * Update the render block data to inject our custom attribute needed to
	 * determine which blocks belong to an inherited Products block.
	 *
	 * @param array         $parsed_block The block being rendered.
	 * @param array         $source_block An un-modified copy of $parsed_block, as it appeared in the source content.
	 * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block.
	 *
	 * @return array
	 */
	abstract public function update_render_block_data( $parsed_block, $source_block, $parent_block );

	/**
	 * Inject hooks to rendered content of corresponding blocks.
	 *
	 * @param mixed $block_content The rendered block content.
	 * @param mixed $block         The parsed block data.
	 * @return string
	 */
	abstract public function inject_hooks( $block_content, $block );

	/**
	 * The hook data to inject to the rendered content of blocks. This also
	 * contains hooked functions that will be removed by remove_default_hooks.
	 *
	 * The array format:
	 * [
	 *   <hook-name> => [
	 *     block_names => [ <block-name>, ... ],
	 *     position => before|after,
	 *     hooked => [
	 *       <function-name> => <priority>,
	 *        ...
	 *     ],
	 *  ],
	 * ]
	 * Where:
	 * - hook-name is the name of the hook that will be replaced.
	 * - block-names is the array block names that hook will be attached to.
	 * - position is the position of the block relative to the hook.
	 * - hooked is an array of functions hooked to the hook that will be
	 *   replaced. The key is the function name and the value is the
	 *   priority.
	 */
	abstract protected function set_hook_data();


	/**
	 * Remove the default callback added by WooCommerce. We replaced these
	 * callbacks by blocks so we have to remove them to prevent duplicated
	 * content.
	 */
	protected function remove_default_hooks() {
		foreach ( $this->hook_data as $hook => $data ) {
			if ( ! isset( $data['hooked'] ) ) {
				continue;
			}
			foreach ( $data['hooked'] as $callback => $priority ) {
				remove_action( $hook, $callback, $priority );
			}
		}

		/**
		 * When extensions implement their equivalent blocks of the template
		 * hook functions, they can use this filter to register their old hooked
		 * data here, so in the blockified template, the old hooked functions
		 * can be removed in favor of the new blocks while keeping the old
		 * hooked functions working in classic templates.
		 *
		 * Accepts an array of hooked data. The array should be in the following
		 * format:
		 * [
		 *   [
		 *     hook => <hook-name>,
		 *     function => <function-name>,
		 *     priority => <priority>,
		 *  ],
		 *  ...
		 * ]
		 * Where:
		 * - hook-name is the name of the hook that have the functions hooked to.
		 * - function-name is the hooked function name.
		 * - priority is the priority of the hooked function.
		 *
		 * @since 9.5.0
		 * @param array $data Additional hooked data. Default to empty
		 */
		$additional_hook_data = apply_filters( 'woocommerce_blocks_hook_compatibility_additional_data', array() );

		if ( empty( $additional_hook_data ) || ! is_array( $additional_hook_data ) ) {
			return;
		}

		foreach ( $additional_hook_data as $data ) {
			if ( ! isset( $data['hook'], $data['function'], $data['priority'] ) ) {
				continue;
			}
			remove_action( $data['hook'], $data['function'], $data['priority'] );
		}
	}

	/**
	 * Get the buffer content of the hooks to append/prepend to render content.
	 *
	 * @param array  $hooks    The hooks to be rendered.
	 * @param string $position The position of the hooks.
	 *
	 * @return string
	 */
	protected function get_hooks_buffer( $hooks, $position ) {
		ob_start();
		foreach ( $hooks as $hook => $data ) {
			if ( $data['position'] === $position ) {
				/**
				 * Action to render the content of a hook.
				 *
				 * @since 9.5.0
				 */
				do_action( $hook );
			}
		}
		return ob_get_clean();
	}
}
ArchiveProductTemplatesCompatibility.php000064400000030620151550724220014614 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * ArchiveProductTemplatesCompatibility class.
 *
 * To bridge the gap on compatibility with PHP hooks and Product Archive blockified templates.
 *
 * @internal
 */
class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility {

	/**
	 * The custom ID of the loop item block as the replacement of the core/null block.
	 */
	const LOOP_ITEM_ID = 'product-loop-item';

	/**
	 * The data of supported hooks, containing the hook name, the block name,
	 * position, and the callbacks.
	 *
	 * @var array $hook_data The hook data.
	 */
	protected $hook_data;

	/**
	 * Update the render block data to inject our custom attribute needed to
	 * determine which blocks belong to an inherited Products block.
	 *
	 * @param array         $parsed_block The block being rendered.
	 * @param array         $source_block An un-modified copy of $parsed_block, as it appeared in the source content.
	 * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block.
	 *
	 * @return array
	 */
	public function update_render_block_data( $parsed_block, $source_block, $parent_block ) {

		if ( ! $this->is_archive_template() ) {
			return $parsed_block;
		}

		/**
		 * Custom data can be injected to top level block only, as Gutenberg
		 * will use this data to render the blocks and its nested blocks.
		 */
		if ( $parent_block ) {
			return $parsed_block;
		}

		$this->inner_blocks_walker( $parsed_block );

		return $parsed_block;
	}

	/**
	 * Inject hooks to rendered content of corresponding blocks.
	 *
	 * @param mixed $block_content The rendered block content.
	 * @param mixed $block         The parsed block data.
	 * @return string
	 */
	public function inject_hooks( $block_content, $block ) {
		if ( ! $this->is_archive_template() ) {
			return $block_content;
		}
		/**
		 * If the block is not inherited, we don't need to inject hooks.
		 */
		if ( empty( $block['attrs']['isInherited'] ) ) {
			return $block_content;
		}

		$block_name = $block['blockName'];

		if ( $this->is_null_post_template( $block ) ) {
			$block_name = self::LOOP_ITEM_ID;
		}

		$block_hooks = array_filter(
			$this->hook_data,
			function( $hook ) use ( $block_name ) {
				return in_array( $block_name, $hook['block_names'], true );
			}
		);

		// We want to inject hooks to the core/post-template or product template block only when the products exist:
		// https://github.com/woocommerce/woocommerce-blocks/issues/9463.
		if ( $this->is_post_or_product_template( $block_name ) && ! empty( $block_content ) ) {
			$this->restore_default_hooks();
			$content = sprintf(
				'%1$s%2$s%3$s',
				$this->get_hooks_buffer( $block_hooks, 'before' ),
				$block_content,
				$this->get_hooks_buffer( $block_hooks, 'after' )
			);
			$this->remove_default_hooks();
			return $content;
		}

		$supported_blocks = array_merge(
			[],
			...array_map(
				function( $hook ) {
					return $hook['block_names'];
				},
				array_values( $this->hook_data )
			)
		);

		if ( ! in_array( $block_name, $supported_blocks, true ) ) {
			return $block_content;
		}

		if (
			'core/query-no-results' === $block_name
		) {

			/**
			 * `core/query-no-result` is a special case because it can return two
			 * different content depending on the context. We need to check if the
			 * block content is empty to determine if we need to inject hooks.
			 */
			if ( empty( trim( $block_content ) ) ) {
				return $block_content;
			}

			$this->restore_default_hooks();

			$content = sprintf(
				'%1$s%2$s%3$s',
				$this->get_hooks_buffer( $block_hooks, 'before' ),
				$block_content,
				$this->get_hooks_buffer( $block_hooks, 'after' )
			);

			$this->remove_default_hooks();

			return $content;
		}

		if ( empty( $block_content ) ) {
			return $block_content;
		}

		return sprintf(
			'%1$s%2$s%3$s',
			$this->get_hooks_buffer( $block_hooks, 'before' ),
			$block_content,
			$this->get_hooks_buffer( $block_hooks, 'after' )
		);
	}

	/**
	 * The hook data to inject to the rendered content of blocks. This also
	 * contains hooked functions that will be removed by remove_default_hooks.
	 *
	 * The array format:
	 * [
	 *   <hook-name> => [
	 *     block_name => <block-name>,
	 *     position => before|after,
	 *     hooked => [
	 *       <function-name> => <priority>,
	 *        ...
	 *     ],
	 *     permanently_removed_actions => [
	 *         <function-name>
	 *    ]
	 *  ],
	 * ]
	 * Where:
	 * - hook-name is the name of the hook that will be replaced.
	 * - block-name is the name of the block that will replace the hook.
	 * - position is the position of the block relative to the hook.
	 * - hooked is an array of functions hooked to the hook that will be
	 *   replaced. The key is the function name and the value is the
	 *   priority.
	 * - permanently_removed_actions is an array of functions that we do not want to re-add after they have been removed to avoid duplicate content with the Products block and its inner blocks.
	 */
	protected function set_hook_data() {
		$this->hook_data = array(
			'woocommerce_before_main_content'         => array(
				'block_names' => array( 'core/query', 'woocommerce/product-collection' ),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_output_content_wrapper' => 10,
					'woocommerce_breadcrumb'             => 20,
				),
			),
			'woocommerce_after_main_content'          => array(
				'block_names' => array( 'core/query', 'woocommerce/product-collection' ),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_output_content_wrapper_end' => 10,
				),
			),
			'woocommerce_before_shop_loop_item_title' => array(
				'block_names' => array( 'core/post-title' ),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_show_product_loop_sale_flash' => 10,
					'woocommerce_template_loop_product_thumbnail' => 10,
				),
			),
			'woocommerce_shop_loop_item_title'        => array(
				'block_names' => array( 'core/post-title' ),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_template_loop_product_title' => 10,
				),
			),
			'woocommerce_after_shop_loop_item_title'  => array(
				'block_names' => array( 'core/post-title' ),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_template_loop_rating' => 5,
					'woocommerce_template_loop_price'  => 10,
				),
			),
			'woocommerce_before_shop_loop_item'       => array(
				'block_names' => array( self::LOOP_ITEM_ID ),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_template_loop_product_link_open' => 10,
				),
			),
			'woocommerce_after_shop_loop_item'        => array(
				'block_names' => array( self::LOOP_ITEM_ID ),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_template_loop_product_link_close' => 5,
					'woocommerce_template_loop_add_to_cart' => 10,
				),
			),
			'woocommerce_before_shop_loop'            => array(
				'block_names'                 => array( 'core/post-template', 'woocommerce/product-template' ),
				'position'                    => 'before',
				'hooked'                      => array(
					'woocommerce_output_all_notices' => 10,
					'woocommerce_result_count'       => 20,
					'woocommerce_catalog_ordering'   => 30,
				),
				'permanently_removed_actions' => array(
					'woocommerce_output_all_notices',
					'woocommerce_result_count',
					'woocommerce_catalog_ordering',
				),
			),
			'woocommerce_after_shop_loop'             => array(
				'block_names'                 => array( 'core/post-template', 'woocommerce/product-template' ),
				'position'                    => 'after',
				'hooked'                      => array(
					'woocommerce_pagination' => 10,
				),
				'permanently_removed_actions' => array(
					'woocommerce_pagination',
				),
			),
			'woocommerce_no_products_found'           => array(
				'block_names'                 => array( 'core/query-no-results' ),
				'position'                    => 'before',
				'hooked'                      => array(
					'wc_no_products_found' => 10,
				),
				'permanently_removed_actions' => array(
					'wc_no_products_found',
				),
			),
			'woocommerce_archive_description'         => array(
				'block_names' => array( 'core/term-description' ),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_taxonomy_archive_description' => 10,
					'woocommerce_product_archive_description'  => 10,
				),
			),
		);
	}

	/**
	 * Check if current page is a product archive template.
	 */
	private function is_archive_template() {
		return is_shop() || is_product_taxonomy();
	}

	/**
	 * Loop through inner blocks recursively to find the Products blocks that
	 * inherits query from template.
	 *
	 * @param array $block Parsed block data.
	 */
	private function inner_blocks_walker( &$block ) {
		if (
			$this->is_products_block_with_inherit_query( $block ) || $this->is_product_collection_block_with_inherit_query( $block )
		) {
			$this->inject_attribute( $block );
			$this->remove_default_hooks();
		}

		if ( ! empty( $block['innerBlocks'] ) ) {
			array_walk( $block['innerBlocks'], array( $this, 'inner_blocks_walker' ) );
		}
	}

	/**
	 * Restore default hooks except the ones that are not supposed to be re-added.
	 */
	private function restore_default_hooks() {
		foreach ( $this->hook_data as $hook => $data ) {
			if ( ! isset( $data['hooked'] ) ) {
				continue;
			}
			foreach ( $data['hooked'] as $callback => $priority ) {
				if ( ! in_array( $callback, $data['permanently_removed_actions'] ?? [], true ) ) {
					add_action( $hook, $callback, $priority );
				}
			}
		}
	}

	/**
	 * Check if block is within the product-query namespace
	 *
	 * @param array $block Parsed block data.
	 */
	private function is_block_within_namespace( $block ) {
		$attributes = $block['attrs'];

		return isset( $attributes['__woocommerceNamespace'] ) && 'woocommerce/product-query/product-template' === $attributes['__woocommerceNamespace'];
	}

	/**
	 * Check if block has isInherited attribute asigned
	 *
	 * @param array $block Parsed block data.
	 */
	private function is_block_inherited( $block ) {
		$attributes = $block['attrs'];

		$outcome = isset( $attributes['isInherited'] ) && 1 === $attributes['isInherited'];

		return $outcome;
	}

	/**
	 * The core/post-template has two different block names:
	 * - core/post-template when the wrapper is rendered.
	 * - core/null when the loop item is rendered.
	 *
	 * @param array $block Parsed block data.
	 */
	private function is_null_post_template( $block ) {
		$block_name = $block['blockName'];

		return 'core/null' === $block_name && ( $this->is_block_inherited( $block ) || $this->is_block_within_namespace( $block ) );
	}

	/**
	 * Check if block is a Post template
	 *
	 * @param string $block_name Block name.
	 */
	private function is_post_template( $block_name ) {
		return 'core/post-template' === $block_name;
	}

	/**
	 * Check if block is a Product Template
	 *
	 * @param string $block_name Block name.
	 */
	private function is_product_template( $block_name ) {
		return 'woocommerce/product-template' === $block_name;
	}

	/**
	 * Check if block is eaither a Post template or Product Template
	 *
	 * @param string $block_name Block name.
	 */
	private function is_post_or_product_template( $block_name ) {
		return $this->is_post_template( $block_name ) || $this->is_product_template( $block_name );
	}

	/**
	 * Check if the block is a Products block that inherits query from template.
	 *
	 * @param array $block Parsed block data.
	 */
	private function is_products_block_with_inherit_query( $block ) {
		return 'core/query' === $block['blockName'] &&
		isset( $block['attrs']['namespace'] ) &&
		'woocommerce/product-query' === $block['attrs']['namespace'] &&
		isset( $block['attrs']['query']['inherit'] ) &&
		$block['attrs']['query']['inherit'];
	}

	/**
	 * Check if the block is a Product Collection block that inherits query from template.
	 *
	 * @param array $block Parsed block data.
	 */
	private function is_product_collection_block_with_inherit_query( $block ) {
		return 'woocommerce/product-collection' === $block['blockName'] &&
		isset( $block['attrs']['query']['inherit'] ) &&
		$block['attrs']['query']['inherit'];
	}


	/**
	 * Recursively inject the custom attribute to all nested blocks.
	 *
	 * @param array $block Parsed block data.
	 */
	private function inject_attribute( &$block ) {
		$block['attrs']['isInherited'] = 1;

		if ( ! empty( $block['innerBlocks'] ) ) {
			array_walk( $block['innerBlocks'], array( $this, 'inject_attribute' ) );
		}
	}
}
CartTemplate.php000064400000002212151550724220007642 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

use Automattic\WooCommerce\Blocks\Utils\BlockTemplateMigrationUtils;

/**
 * CartTemplate class.
 *
 * @internal
 */
class CartTemplate extends AbstractPageTemplate {
	/**
	 * Template slug.
	 *
	 * @return string
	 */
	public static function get_slug() {
		return 'cart';
	}

	/**
	 * Returns the page object assigned to this template/page.
	 *
	 * @return \WP_Post|null Post object or null.
	 */
	public static function get_placeholder_page() {
		$page_id = wc_get_page_id( 'cart' );
		return $page_id ? get_post( $page_id ) : null;
	}

	/**
	 * True when viewing the cart page or cart endpoint.
	 *
	 * @return boolean
	 */
	protected function is_active_template() {

		if ( ! BlockTemplateMigrationUtils::has_migrated_page( 'cart' ) ) {
			return false;
		}

		global $post;
		$placeholder = $this->get_placeholder_page();
		return null !== $placeholder && $post instanceof \WP_Post && $placeholder->post_name === $post->post_name;
	}

	/**
	 * Should return the title of the page.
	 *
	 * @return string
	 */
	public static function get_template_title() {
		return __( 'Cart', 'woocommerce' );
	}
}
CheckoutHeaderTemplate.php000064400000000270151550724220011631 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * CheckoutHeader Template class.
 *
 * @internal
 */
class CheckoutHeaderTemplate {

	const SLUG = 'checkout-header';

}
CheckoutTemplate.php000064400000002247151550724220010526 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

use Automattic\WooCommerce\Blocks\Utils\BlockTemplateMigrationUtils;

/**
 * CheckoutTemplate class.
 *
 * @internal
 */
class CheckoutTemplate extends AbstractPageTemplate {
	/**
	 * Template slug.
	 *
	 * @return string
	 */
	public static function get_slug() {
		return 'checkout';
	}

	/**
	 * Returns the page object assigned to this template/page.
	 *
	 * @return \WP_Post|null Post object or null.
	 */
	public static function get_placeholder_page() {
		$page_id = wc_get_page_id( 'checkout' );
		return $page_id ? get_post( $page_id ) : null;
	}

	/**
	 * Should return the title of the page.
	 *
	 * @return string
	 */
	public static function get_template_title() {
		return __( 'Checkout', 'woocommerce' );
	}

	/**
	 * True when viewing the checkout page or checkout endpoint.
	 *
	 * @return boolean
	 */
	public function is_active_template() {

		if ( ! BlockTemplateMigrationUtils::has_migrated_page( 'checkout' ) ) {
			return false;
		}

		global $post;
		$placeholder = $this->get_placeholder_page();
		return null !== $placeholder && $post instanceof \WP_Post && $placeholder->post_name === $post->post_name;
	}
}
ClassicTemplatesCompatibility.php000064400000004512151550724220013254 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;

/**
 * ClassicTemplatesCompatibility class.
 *
 * To bridge the gap on compatibility with widget blocks and classic PHP core templates.
 *
 * @internal
 */
class ClassicTemplatesCompatibility {

	/**
	 * Instance of the asset data registry.
	 *
	 * @var AssetDataRegistry
	 */
	protected $asset_data_registry;

	/**
	 * Constructor.
	 *
	 * @param AssetDataRegistry $asset_data_registry Instance of the asset data registry.
	 */
	public function __construct( AssetDataRegistry $asset_data_registry ) {
		$this->asset_data_registry = $asset_data_registry;
		$this->init();
	}

	/**
	 * Initialization method.
	 */
	protected function init() {
		if ( ! wc_current_theme_is_fse_theme() ) {
			add_action( 'template_redirect', array( $this, 'set_classic_template_data' ) );
			// We need to set this data on the widgets screen so the filters render previews.
			add_action( 'load-widgets.php', array( $this, 'set_filterable_product_data' ) );
		}
	}

	/**
	 * Executes the methods which set the necessary data needed for filter blocks to work correctly as widgets in Classic templates.
	 *
	 * @return void
	 */
	public function set_classic_template_data() {
		$this->set_filterable_product_data();
		$this->set_php_template_data();
	}

	/**
	 * This method passes the value `has_filterable_products` to the front-end for product archive pages,
	 * so that widget product filter blocks are aware of the context they are in and can render accordingly.
	 *
	 * @return void
	 */
	public function set_filterable_product_data() {
		global $pagenow;

		if ( is_shop() || is_product_taxonomy() || 'widgets.php' === $pagenow ) {
			$this->asset_data_registry->add( 'hasFilterableProducts', true, true );
		}
	}

	/**
	 * This method passes the value `is_rendering_php_template` to the front-end of Classic themes,
	 * so that widget product filter blocks are aware of how to filter the products.
	 *
	 * This data only matters on WooCommerce product archive pages.
	 * On non-archive pages the merchant could be using the All Products block which is not a PHP template.
	 *
	 * @return void
	 */
	public function set_php_template_data() {
		if ( is_shop() || is_product_taxonomy() ) {
			$this->asset_data_registry->add( 'isRenderingPhpTemplate', true, true );
		}
	}
}
MiniCartTemplate.php000064400000000245151550724220010463 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * MiniCartTemplate class.
 *
 * @internal
 */
class MiniCartTemplate {

	const SLUG = 'mini-cart';

}
OrderConfirmationTemplate.php000064400000001525151550724220012403 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * OrderConfirmationTemplate class.
 *
 * @internal
 */
class OrderConfirmationTemplate extends AbstractPageTemplate {
	/**
	 * Template slug.
	 *
	 * @return string
	 */
	public static function get_slug() {
		return 'order-confirmation';
	}

	/**
	 * Returns the page object assigned to this template/page.
	 *
	 * @return \WP_Post|null Post object or null.
	 */
	public static function get_placeholder_page() {
		return null;
	}

	/**
	 * True when viewing the Order Received endpoint.
	 *
	 * @return boolean
	 */
	protected function is_active_template() {
		return is_wc_endpoint_url( 'order-received' );
	}

	/**
	 * Should return the title of the page.
	 *
	 * @return string
	 */
	public static function get_template_title() {
		return __( 'Order Confirmation', 'woocommerce' );
	}
}
ProductAttributeTemplate.php000064400000001670151550724220012264 0ustar00<?php

namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * ProductAttributeTemplate class.
 *
 * @internal
 */
class ProductAttributeTemplate {
	const SLUG = 'taxonomy-product_attribute';

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->init();
	}

	/**
	 * Initialization method.
	 */
	protected function init() {
		add_filter( 'taxonomy_template_hierarchy', array( $this, 'update_taxonomy_template_hierarchy' ), 1, 3 );
	}

	/**
	 * Renders the Product by Attribute template for product attributes taxonomy pages.
	 *
	 * @param array $templates Templates that match the product attributes taxonomy.
	 */
	public function update_taxonomy_template_hierarchy( $templates ) {
		$queried_object = get_queried_object();
		if ( taxonomy_is_product_attribute( $queried_object->taxonomy ) && wc_current_theme_is_fse_theme() ) {
			array_splice( $templates, count( $templates ) - 1, 0, self::SLUG );
		}

		return $templates;
	}
}
ProductSearchResultsTemplate.php000064400000001560151550724220013106 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * ProductSearchResultsTemplate class.
 *
 * @internal
 */
class ProductSearchResultsTemplate {

	const SLUG = 'product-search-results';

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->init();
	}

	/**
	 * Initialization method.
	 */
	protected function init() {
		add_filter( 'search_template_hierarchy', array( $this, 'update_search_template_hierarchy' ), 10, 3 );
	}

	/**
	 * When the search is for products and a block theme is active, render the Product Search Template.
	 *
	 * @param array $templates Templates that match the search hierarchy.
	 */
	public function update_search_template_hierarchy( $templates ) {
		if ( ( is_search() && is_post_type_archive( 'product' ) ) && wc_current_theme_is_fse_theme() ) {
			array_unshift( $templates, self::SLUG );
		}
		return $templates;
	}
}
SingleProductTemplateCompatibility.php000064400000035173151550724220014301 0ustar00<?php
namespace Automattic\WooCommerce\Blocks\Templates;

/**
 * SingleProductTemplateCompatibility class.
 *
 * To bridge the gap on compatibility with PHP hooks and Single Product templates.
 *
 * @internal
 */
class SingleProductTemplateCompatibility extends AbstractTemplateCompatibility {
	const IS_FIRST_BLOCK = '__wooCommerceIsFirstBlock';
	const IS_LAST_BLOCK  = '__wooCommerceIsLastBlock';


	/**
	 * Inject hooks to rendered content of corresponding blocks.
	 *
	 * @param mixed $block_content The rendered block content.
	 * @param mixed $block         The parsed block data.
	 * @return string
	 */
	public function inject_hooks( $block_content, $block ) {
		if ( ! is_product() ) {
			return $block_content;
		}

		$this->remove_default_hooks();

		$block_name = $block['blockName'];

		$block_hooks = array_filter(
			$this->hook_data,
			function( $hook ) use ( $block_name ) {
				return in_array( $block_name, $hook['block_names'], true );
			}
		);

		$first_or_last_block_content = $this->inject_hook_to_first_and_last_blocks( $block_content, $block, $block_hooks );

		if ( isset( $first_or_last_block_content ) ) {
			return $first_or_last_block_content;
		}

		return sprintf(
			'%1$s%2$s%3$s',
			$this->get_hooks_buffer( $block_hooks, 'before' ),
			$block_content,
			$this->get_hooks_buffer( $block_hooks, 'after' )
		);
	}

	/**
	 * Inject custom hooks to the first and last blocks.
	 * Since that there is a custom logic for the first and last block, we have to inject the hooks manually.
	 * The first block supports the following hooks:
	 * woocommerce_before_single_product
	 * woocommerce_before_single_product_summary
	 * woocommerce_single_product_summary
	 *
	 * The last block supports the following hooks:
	 * woocommerce_after_single_product
	 *
	 * @param mixed $block_content The rendered block content.
	 * @param mixed $block         The parsed block data.
	 * @param array $block_hooks   The hooks that should be injected to the block.
	 * @return string
	 */
	private function inject_hook_to_first_and_last_blocks( $block_content, $block, $block_hooks ) {
		$first_block_hook = array(
			'before' => array(
				'woocommerce_before_main_content'    => $this->hook_data['woocommerce_before_main_content'],
				'woocommerce_before_single_product'  => $this->hook_data['woocommerce_before_single_product'],
				'woocommerce_before_single_product_summary' => $this->hook_data['woocommerce_before_single_product_summary'],
				'woocommerce_single_product_summary' => $this->hook_data['woocommerce_single_product_summary'],
			),
			'after'  => array(),
		);

		$last_block_hook = array(
			'before' => array(),
			'after'  => array(
				'woocommerce_after_single_product' => $this->hook_data['woocommerce_after_single_product'],
				'woocommerce_after_main_content'   => $this->hook_data['woocommerce_after_main_content'],
				'woocommerce_sidebar'              => $this->hook_data['woocommerce_sidebar'],
			),
		);

		if ( isset( $block['attrs'][ self::IS_FIRST_BLOCK ] ) && isset( $block['attrs'][ self::IS_LAST_BLOCK ] ) ) {
			return sprintf(
				'%1$s%2$s',
				$this->inject_hooks_after_the_wrapper(
					$block_content,
					array_merge(
						$first_block_hook['before'],
						$block_hooks,
						$last_block_hook['before']
					)
				),
				$this->get_hooks_buffer(
					array_merge(
						$first_block_hook['after'],
						$block_hooks,
						$last_block_hook['after']
					),
					'after'
				)
			);
		}

		if ( isset( $block['attrs'][ self::IS_FIRST_BLOCK ] ) ) {
			return sprintf(
				'%1$s%2$s',
				$this->inject_hooks_after_the_wrapper(
					$block_content,
					array_merge(
						$first_block_hook['before'],
						$block_hooks
					)
				),
				$this->get_hooks_buffer(
					array_merge(
						$first_block_hook['after'],
						$block_hooks
					),
					'after'
				)
			);
		}

		if ( isset( $block['attrs'][ self::IS_LAST_BLOCK ] ) ) {
			return sprintf(
				'%1$s%2$s%3$s',
				$this->get_hooks_buffer(
					array_merge(
						$last_block_hook['before'],
						$block_hooks
					),
					'before'
				),
				$block_content,
				$this->get_hooks_buffer(
					array_merge(
						$block_hooks,
						$last_block_hook['after']
					),
					'after'
				)
			);
		}
	}

	/**
	 * Update the render block data to inject our custom attribute needed to
	 * determine which is the first block of the Single Product Template.
	 *
	 * @param array         $parsed_block The block being rendered.
	 * @param array         $source_block An un-modified copy of $parsed_block, as it appeared in the source content.
	 * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block.
	 *
	 * @return array
	 */
	public function update_render_block_data( $parsed_block, $source_block, $parent_block ) {
		return $parsed_block;
	}

	/**
	 * Set supported hooks.
	 */
	protected function set_hook_data() {
		$this->hook_data = array(
			'woocommerce_before_main_content'           => array(
				'block_names' => array(),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_output_content_wrapper' => 10,
					'woocommerce_breadcrumb'             => 20,
				),
			),
			'woocommerce_after_main_content'            => array(
				'block_names' => array(),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_output_content_wrapper_end' => 10,
				),
			),
			'woocommerce_sidebar'                       => array(
				'block_names' => array(),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_get_sidebar' => 10,
				),
			),
			'woocommerce_before_single_product'         => array(
				'block_names' => array(),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_output_all_notices' => 10,
				),
			),
			'woocommerce_before_single_product_summary' => array(
				'block_names' => array(),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_show_product_sale_flash' => 10,
					'woocommerce_show_product_images'     => 20,
				),
			),
			'woocommerce_single_product_summary'        => array(
				'block_names' => array(),
				'position'    => 'before',
				'hooked'      => array(
					'woocommerce_template_single_title'   => 5,
					'woocommerce_template_single_rating'  => 10,
					'woocommerce_template_single_price'   => 10,
					'woocommerce_template_single_excerpt' => 20,
					'woocommerce_template_single_add_to_cart' => 30,
					'woocommerce_template_single_meta'    => 40,
					'woocommerce_template_single_sharing' => 50,
				),
			),
			'woocommerce_after_single_product'          => array(
				'block_names' => array(),
				'position'    => 'after',
				'hooked'      => array(),
			),
			'woocommerce_product_meta_start'            => array(
				'block_names' => array( 'woocommerce/product-meta' ),
				'position'    => 'before',
				'hooked'      => array(),
			),
			'woocommerce_product_meta_end'              => array(
				'block_names' => array( 'woocommerce/product-meta' ),
				'position'    => 'after',
				'hooked'      => array(),
			),
			'woocommerce_share'                         => array(
				'block_names' => array( 'woocommerce/product-details' ),
				'position'    => 'before',
				'hooked'      => array(),
			),
			'woocommerce_after_single_product_summary'  => array(
				'block_names' => array( 'woocommerce/product-details' ),
				'position'    => 'after',
				'hooked'      => array(
					'woocommerce_output_product_data_tabs' => 10,
					// We want to display the upsell products after the last block that belongs to the Single Product.
					// 'woocommerce_upsell_display'           => 15.
					'woocommerce_output_related_products'  => 20,
				),
			),
		);
	}

	/**
	 * Add compatibility layer to the first and last block of the Single Product Template.
	 *
	 * @param string $template_content Template.
	 * @return string
	 */
	public static function add_compatibility_layer( $template_content ) {
		$parsed_blocks = parse_blocks( $template_content );

		if ( ! self::has_single_product_template_blocks( $parsed_blocks ) ) {
			$template = self::inject_custom_attributes_to_first_and_last_block_single_product_template( $parsed_blocks );
			return self::serialize_blocks( $template );
		}

		$wrapped_blocks = self::wrap_single_product_template( $template_content );
		$template       = self::inject_custom_attributes_to_first_and_last_block_single_product_template( $wrapped_blocks );
		return self::serialize_blocks( $template );
	}

	/**
	 * For compatibility reason, we need to wrap the Single Product template in a div with specific class.
	 * For more details, see https://github.com/woocommerce/woocommerce-blocks/issues/8314.
	 *
	 * @param string $template_content Template Content.
	 * @return array Wrapped template content inside a div.
	 */
	private static function wrap_single_product_template( $template_content ) {
		$parsed_blocks  = parse_blocks( $template_content );
		$grouped_blocks = self::group_blocks( $parsed_blocks );

		$wrapped_blocks = array_map(
			function( $blocks ) {
				if ( 'core/template-part' === $blocks[0]['blockName'] ) {
					return $blocks;
				}

				$has_single_product_template_blocks = self::has_single_product_template_blocks( $blocks );

				if ( $has_single_product_template_blocks ) {
					$wrapped_block = self::create_wrap_block_group( $blocks );
					return array( $wrapped_block[0] );
				}
				return $blocks;
			},
			$grouped_blocks
		);
		return $wrapped_blocks;
	}

	/**
	 * Add custom attributes to the first group block and last group block that wrap Single Product Template blocks.
	 *
	 * @param array $wrapped_blocks Wrapped blocks.
	 * @return array
	 */
	private static function inject_custom_attributes_to_first_and_last_block_single_product_template( $wrapped_blocks ) {
		$template_with_custom_attributes = array_reduce(
			$wrapped_blocks,
			function( $carry, $item ) {

				$index          = $carry['index'];
				$carry['index'] = $carry['index'] + 1;
				// If the block is a child of a group block, we need to get the first block of the group.
				$block = isset( $item[0] ) ? $item[0] : $item;

				if ( 'core/template-part' === $block['blockName'] || self::is_custom_html( $block ) ) {
					$carry['template'][] = $block;
					return $carry;
				}

				if ( '' === $carry['first_block']['index'] ) {
					$block['attrs'][ self::IS_FIRST_BLOCK ] = true;
					$carry['first_block']['index']          = $index;
				}

				if ( '' !== $carry['last_block']['index'] ) {
					$index_element                         = $carry['last_block']['index'];
					$carry['last_block']['index']          = $index;
					$block['attrs'][ self::IS_LAST_BLOCK ] = true;
					unset( $carry['template'][ $index_element ]['attrs'][ self::IS_LAST_BLOCK ] );

					$carry['template'][] = $block;

					return $carry;
				}

				$block['attrs'][ self::IS_LAST_BLOCK ] = true;
				$carry['last_block']['index']          = $index;

				$carry['template'][] = $block;

				return $carry;
			},
			array(
				'template'    => array(),
				'first_block' => array(
					'index' => '',
				),
				'last_block'  => array(
					'index' => '',
				),
				'index'       => 0,
			)
		);

		return array( $template_with_custom_attributes['template'] );
	}

	/**
	 * Wrap all the blocks inside the template in a group block.
	 *
	 * @param array $blocks Array of parsed block objects.
	 * @return array Group block with the blocks inside.
	 */
	private static function create_wrap_block_group( $blocks ) {
		$serialized_blocks = serialize_blocks( $blocks );

		$new_block = parse_blocks(
			sprintf(
				'<!-- wp:group {"className":"woocommerce product"} -->
				<div class="wp-block-group woocommerce product">
					%1$s
				</div>
			<!-- /wp:group -->',
				$serialized_blocks
			)
		);

		$new_block['innerBlocks'] = $blocks;

		return $new_block;

	}

	/**
	 * Check if the Single Product template has a single product template block:
	 * woocommerce/product-gallery-image, woocommerce/product-details, woocommerce/add-to-cart-form]
	 *
	 * @param array $parsed_blocks Array of parsed block objects.
	 * @return bool True if the template has a single product template block, false otherwise.
	 */
	private static function has_single_product_template_blocks( $parsed_blocks ) {
		$single_product_template_blocks = array( 'woocommerce/product-image-gallery', 'woocommerce/product-details', 'woocommerce/add-to-cart-form', 'woocommerce/product-meta', 'woocommerce/product-price', 'woocommerce/breadcrumbs' );

		$found = false;

		foreach ( $parsed_blocks as $block ) {
			if ( isset( $block['blockName'] ) && in_array( $block['blockName'], $single_product_template_blocks, true ) ) {
				$found = true;
				break;
			}
			$found = self::has_single_product_template_blocks( $block['innerBlocks'], $single_product_template_blocks );
			if ( $found ) {
				break;
			}
		}
		return $found;
	}


	/**
	 * Group blocks in this way:
	 * B1 + TP1 + B2 + B3 + B4 + TP2 + B5
	 * (B = Block, TP = Template Part)
	 * becomes:
	 * [[B1], [TP1], [B2, B3, B4], [TP2], [B5]]
	 *
	 * @param array $parsed_blocks Array of parsed block objects.
	 * @return array Array of blocks grouped by template part.
	 */
	private static function group_blocks( $parsed_blocks ) {
		return array_reduce(
			$parsed_blocks,
			function( $carry, $block ) {
				if ( 'core/template-part' === $block['blockName'] ) {
					$carry[] = array( $block );
					return $carry;
				}
				$last_element_index = count( $carry ) - 1;
				if ( isset( $carry[ $last_element_index ][0]['blockName'] ) && 'core/template-part' !== $carry[ $last_element_index ][0]['blockName'] ) {
					$carry[ $last_element_index ][] = $block;
					return $carry;
				}
				$carry[] = array( $block );
				return $carry;
			},
			array()
		);
	}

	/**
	 * Inject the hooks after the div wrapper.
	 *
	 * @param string $block_content Block Content.
	 * @param array  $hooks Hooks to inject.
	 * @return array
	 */
	private function inject_hooks_after_the_wrapper( $block_content, $hooks ) {
		$closing_tag_position = strpos( $block_content, '>' );

		return substr_replace(
			$block_content,
			$this->get_hooks_buffer(
				$hooks,
				'before'
			),
			// Add 1 to the position to inject the content after the closing tag.
			$closing_tag_position + 1,
			0
		);
	}


	/**
	 * Plain custom HTML block is parsed as block with an empty blockName with a filled innerHTML.
	 *
	 * @param array $block Parse block.
	 * @return bool
	 */
	private static function is_custom_html( $block ) {
		return empty( $block['blockName'] ) && ! empty( $block['innerHTML'] );
	}

	/**
	 * Serialize template.
	 *
	 * @param array $parsed_blocks Parsed blocks.
	 * @return string
	 */
	private static function serialize_blocks( $parsed_blocks ) {
		return array_reduce(
			$parsed_blocks,
			function( $carry, $item ) {
				if ( is_array( $item ) ) {
					return $carry . serialize_blocks( $item );
				}
				return $carry . serialize_block( $item );
			},
			''
		);
	}
}