Current Path : /storage/v11800/romasitenew/public_html/wp-content/plugins/google-listings-and-ads/src/Admin/ |
Linux v11800 5.3.0-1023-aws #25~18.04.1-Ubuntu SMP Fri Jun 5 15:19:18 UTC 2020 aarch64
|
Current File : /storage/v11800/romasitenew/public_html/wp-content/plugins/google-listings-and-ads/src/Admin/ProductBlocksService.php |
<?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\AttributesForm;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\AttributesTrait;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\ChannelVisibilityBlock;
use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AdminScriptWithBuiltDependenciesAsset;
use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AdminStyleAsset;
use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AssetsHandlerInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Conditional;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Registerable;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Service;
use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantCenterService;
use Automattic\WooCommerce\GoogleListingsAndAds\PluginHelper;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\AttributeManager;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\ProductSyncer;
use Automattic\WooCommerce\GoogleListingsAndAds\Value\BuiltScriptDependencyArray;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
use Automattic\WooCommerce\Admin\Features\ProductBlockEditor\BlockRegistry;
use Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates\SectionInterface;
use Automattic\WooCommerce\Admin\PageController;
defined( 'ABSPATH' ) || exit;
/**
* Class ProductBlocksService
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Admin
*/
class ProductBlocksService implements Service, Registerable, Conditional {
use AttributesTrait;
use PluginHelper;
/**
* @var AssetsHandlerInterface
*/
protected $assets_handler;
/**
* @var AttributeManager
*/
protected $attribute_manager;
/**
* @var MerchantCenterService
*/
protected $merchant_center;
/**
* @var ChannelVisibilityBlock
*/
protected $channel_visibility_block;
/**
* @var string[]
*/
protected const CUSTOM_BLOCKS = [
'product-onboarding-prompt',
'product-channel-visibility',
'product-date-time-field',
'product-select-field',
'product-select-with-text-field',
];
/**
* ProductBlocksService constructor.
*
* @param AssetsHandlerInterface $assets_handler
* @param ChannelVisibilityBlock $channel_visibility_block
* @param AttributeManager $attribute_manager
* @param MerchantCenterService $merchant_center
*/
public function __construct( AssetsHandlerInterface $assets_handler, ChannelVisibilityBlock $channel_visibility_block, AttributeManager $attribute_manager, MerchantCenterService $merchant_center ) {
$this->assets_handler = $assets_handler;
$this->attribute_manager = $attribute_manager;
$this->merchant_center = $merchant_center;
$this->channel_visibility_block = $channel_visibility_block;
}
/**
* Return whether this service is needed to be registered.
*
* @return bool Whether this service is needed to be registered.
*/
public static function is_needed(): bool {
// compatibility-code "WC >= 8.6" -- The Block Template API used requires at least WooCommerce 8.6
return version_compare( WC_VERSION, '8.6', '>=' );
}
/**
* Register a service.
*/
public function register(): void {
if ( PageController::is_admin_page() ) {
add_action( 'init', [ $this, 'hook_init' ] );
}
// https://github.com/woocommerce/woocommerce/blob/8.6.0/plugins/woocommerce/src/Internal/Features/ProductBlockEditor/ProductTemplates/AbstractProductFormTemplate.php#L19
$template_area = 'product-form';
// https://github.com/woocommerce/woocommerce/blob/8.6.0/plugins/woocommerce/src/Internal/Features/ProductBlockEditor/ProductTemplates/SimpleProductTemplate.php#L19
// https://github.com/woocommerce/woocommerce/blob/8.6.0/plugins/woocommerce/src/Internal/Features/ProductBlockEditor/ProductTemplates/ProductVariationTemplate.php#L19
$block_id = 'general';
add_action(
"woocommerce_block_template_area_{$template_area}_after_add_block_{$block_id}",
[ $this, 'hook_block_template' ]
);
}
/**
* Action hanlder for the 'init' hook.
*/
public function hook_init(): void {
$build_path = "{$this->get_root_dir()}/js/build";
$uri = 'js/build/blocks';
$this->register_custom_blocks( BlockRegistry::get_instance(), $build_path, $uri, self::CUSTOM_BLOCKS );
}
/**
* Action hanlder for the "woocommerce_block_template_area_{$template_area}_after_add_block_{$block_id}" hook.
*
* @param BlockInterface $block The block just added to get its root template to add this extension's group and blocks.
*/
public function hook_block_template( BlockInterface $block ): void {
/** @var Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates\ProductFormTemplateInterface */
$template = $block->get_root_template();
$is_variation_template = $this->is_variation_template( $block );
// Please note that the simple, variable, grouped, and external product types
// use the same product block template 'simple-product'. Their dynamic hidden
// conditions are added below.
if ( 'simple-product' !== $template->get_id() && ! $is_variation_template ) {
return;
}
/** @var Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates\GroupInterface */
$group = $template->add_group(
[
'id' => 'google-listings-and-ads-group',
'order' => 100,
'attributes' => [
'title' => __( 'Google Listings & Ads', 'google-listings-and-ads' ),
],
]
);
$visible_product_types = ProductSyncer::get_supported_product_types();
if ( $is_variation_template ) {
// The property of `editedProduct.type` doesn't exist in the variation product.
// The condition returned from `get_hide_condition` won't work, so it uses 'true' directly.
if ( ! in_array( 'variation', $visible_product_types, true ) ) {
$group->add_hide_condition( 'true' );
}
} else {
$group->add_hide_condition( $this->get_hide_condition( $visible_product_types ) );
}
if ( ! $this->merchant_center->is_setup_complete() ) {
$group->add_block(
[
'id' => 'google-listings-and-ads-product-onboarding-prompt',
'blockName' => 'google-listings-and-ads/product-onboarding-prompt',
'attributes' => [
'startUrl' => $this->get_start_url(),
],
]
);
return;
}
/** @var SectionInterface */
$channel_visibility_section = $group->add_section(
[
'id' => 'google-listings-and-ads-channel-visibility-section',
'order' => 1,
'attributes' => [
'title' => __( 'Channel visibility', 'google-listings-and-ads' ),
],
]
);
if ( ! $is_variation_template ) {
$this->add_channel_visibility_block( $channel_visibility_section );
}
// Add the hidden condition to the channel visibility section because it only has one block.
$visible_product_types = $this->channel_visibility_block->get_visible_product_types();
$channel_visibility_section->add_hide_condition( $this->get_hide_condition( $visible_product_types ) );
/** @var SectionInterface */
$product_attributes_section = $group->add_section(
[
'id' => 'google-listings-and-ads-product-attributes-section',
'order' => 2,
'attributes' => [
'title' => __( 'Product attributes', 'google-listings-and-ads' ),
],
]
);
$this->add_product_attribute_blocks( $product_attributes_section );
}
/**
* Register the custom blocks and their assets.
*
* @param BlockRegistry $block_registry BlockRegistry instance getting from Woo Core for registering custom blocks.
* @param string $build_path The absolute path to the build directory of the assets.
* @param string $uri The script URI of the custom blocks.
* @param string[] $custom_blocks The directory names of each custom block under the build path.
*/
public function register_custom_blocks( BlockRegistry $block_registry, string $build_path, string $uri, array $custom_blocks ): void {
foreach ( $custom_blocks as $custom_block ) {
$block_json_file = "{$build_path}/{$custom_block}/block.json";
if ( ! file_exists( $block_json_file ) ) {
continue;
}
$block_registry->register_block_type_from_metadata( $block_json_file );
}
$assets[] = new AdminScriptWithBuiltDependenciesAsset(
'google-listings-and-ads-product-blocks',
$uri,
"{$build_path}/blocks.asset.php",
new BuiltScriptDependencyArray(
[
'dependencies' => [],
'version' => (string) filemtime( "{$build_path}/blocks.js" ),
]
)
);
$assets[] = new AdminStyleAsset(
'google-listings-and-ads-product-blocks-css',
$uri,
[],
(string) filemtime( "{$build_path}/blocks.css" )
);
$this->assets_handler->register_many( $assets );
$this->assets_handler->enqueue_many( $assets );
}
/**
* Add the channel visibility block to the given section block.
*
* @param SectionInterface $section The section block to add the channel visibility block
*/
private function add_channel_visibility_block( SectionInterface $section ): void {
$section->add_block( $this->channel_visibility_block->get_block_config() );
}
/**
* Add product attribute blocks to the given section block.
*
* @param SectionInterface $section The section block to add product attribute blocks
*/
private function add_product_attribute_blocks( SectionInterface $section ): void {
$is_variation_template = $this->is_variation_template( $section );
$product_types = $is_variation_template ? [ 'variation' ] : $this->get_applicable_product_types();
$attribute_types = $this->attribute_manager->get_attribute_types_for_product_types( $product_types );
foreach ( $attribute_types as $attribute_type ) {
$input_type = call_user_func( [ $attribute_type, 'get_input_type' ] );
$input = AttributesForm::init_input( new $input_type(), new $attribute_type() );
if ( $is_variation_template ) {
// When editing a variation, its product type on the frontend side won't be changed dynamically.
// In addition, the property of `editedProduct.type` doesn't exist in the variation product.
// Therefore, instead of using the ProductTemplates API `add_hide_condition` to conditionally
// hide attributes, it doesn't add invisible attribute blocks from the beginning.
if ( $this->is_visible_for_variation( $attribute_type ) ) {
$section->add_block( $input->get_block_config() );
}
} else {
$visible_product_types = AttributesForm::get_attribute_product_types( $attribute_type )['visible'];
// When editing a simple, variable, grouped, or external product, its product type on the
// frontend side can be changed dynamically. So, it needs to use the ProductTemplates API
// `add_hide_condition` to conditionally hide attributes.
/** @var BlockInterface */
$block = $section->add_block( $input->get_block_config() );
$block->add_hide_condition( $this->get_hide_condition( $visible_product_types ) );
}
}
}
/**
* Determine if the product block template of the given block is the variation template.
*
* @param BlockInterface $block The block to be checked
*
* @return boolean
*/
private function is_variation_template( BlockInterface $block ): bool {
return 'product-variation' === $block->get_root_template()->get_id();
}
/**
* Determine if the given attribute is visible for variation product after applying related filters.
*
* @param string $attribute_type An attribute class extending AttributeInterface
*
* @return bool
*/
private function is_visible_for_variation( string $attribute_type ): bool {
$attribute_product_types = AttributesForm::get_attribute_product_types( $attribute_type );
return in_array( 'variation', $attribute_product_types['visible'], true );
}
/**
* Get the expression of the hide condition to a block based on the visible product types.
* e.g. "editedProduct.type !== 'simple' && ! editedProduct.parent_id > 0"
*
* The hide condition is a JavaScript-like expression that will be evaluated on the client to determine if the block should be hidden.
* See [@woocommerce/expression-evaluation](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/expression-evaluation/README.md) for more details.
*
* @param array $visible_product_types The visible product types to be converted to a hidden condition
*
* @return string
*/
public function get_hide_condition( array $visible_product_types ): string {
$conditions = array_map(
function ( $type ) {
return "editedProduct.type !== '{$type}'";
},
$visible_product_types
);
return implode( ' && ', $conditions ) ?: 'true';
}
}