File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/Attributes.tar
AbstractAttribute.php 0000644 00000003562 15154777174 0010734 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
defined( 'ABSPATH' ) || exit;
/**
* Class AbstractAttribute
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
abstract class AbstractAttribute implements AttributeInterface {
/**
* @var mixed
*/
protected $value = null;
/**
* AbstractAttribute constructor.
*
* @param mixed $value
*/
public function __construct( $value = null ) {
$this->set_value( $value );
}
/**
* Return the attribute type. Must be a valid PHP type.
*
* @return string
*
* @link https://www.php.net/manual/en/function.settype.php
*/
public static function get_value_type(): string {
return 'string';
}
/**
* Returns the attribute value.
*
* @return mixed
*/
public function get_value() {
return $this->value;
}
/**
* @param mixed $value
*
* @return $this
*/
public function set_value( $value ): AbstractAttribute {
$this->value = $this->cast_value( $value );
return $this;
}
/**
* Casts the value to the attribute value type and returns the result.
*
* @param mixed $value
*
* @return mixed
*/
protected function cast_value( $value ) {
if ( is_string( $value ) ) {
$value = trim( $value );
if ( '' === $value ) {
return null;
}
}
$value_type = static::get_value_type();
if ( in_array( $value_type, [ 'bool', 'boolean' ], true ) ) {
$value = wc_string_to_bool( $value );
} else {
settype( $value, $value_type );
}
return $value;
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variable', 'variation' ];
}
/**
* @return string
*/
public function __toString() {
return (string) $this->get_value();
}
}
Adult.php 0000644 00000003630 15154777174 0006352 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\AdultInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Adult
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Adult extends AbstractAttribute implements WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'adult';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variable', 'variation' ];
}
/**
* Return the attribute type. Must be a valid PHP type.
*
* @return string
*
* @link https://www.php.net/manual/en/function.settype.php
*/
public static function get_value_type(): string {
return 'boolean';
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return AdultInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Adult', 'google-listings-and-ads' );
}
/**
* Returns the attribute sources
*
* @return array
*/
public static function get_sources(): array {
return [
'yes' => __( 'Yes', 'google-listings-and-ads' ),
'no' => __( 'No', 'google-listings-and-ads' ),
];
}
}
AgeGroup.php 0000644 00000003760 15154777174 0007016 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\AgeGroupInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class AgeGroup
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class AgeGroup extends AbstractAttribute implements WithValueOptionsInterface, WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'ageGroup';
}
/**
* Return an array of values available to choose for the attribute.
*
* Note: array key is used as the option key.
*
* @return array
*/
public static function get_value_options(): array {
return [
'newborn' => __( 'Newborn', 'google-listings-and-ads' ),
'infant' => __( 'Infant', 'google-listings-and-ads' ),
'toddler' => __( 'Toddler', 'google-listings-and-ads' ),
'kids' => __( 'Kids', 'google-listings-and-ads' ),
'adult' => __( 'Adult', 'google-listings-and-ads' ),
];
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return AgeGroupInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Age group', 'google-listings-and-ads' );
}
}
AttributeInterface.php 0000644 00000002563 15154777174 0011071 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\AttributeInputInterface;
defined( 'ABSPATH' ) || exit;
/**
* Interface AttributeInterface
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
interface AttributeInterface {
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string;
/**
* Return the attribute's value type. Must be a valid PHP type.
*
* @return string
*
* @link https://www.php.net/manual/en/function.settype.php
*/
public static function get_value_type(): string;
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string;
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array;
/**
* Returns the attribute value.
*
* @return mixed
*/
public function get_value();
}
AttributeManager.php 0000644 00000026252 15154777174 0010544 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Proxies\WC;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidClass;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidValue;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\ValidateInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Service;
use Automattic\WooCommerce\GoogleListingsAndAds\PluginHelper;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\WCProductAdapter;
use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query\AttributeMappingRulesQuery;
use WC_Product;
use WC_Product_Variation;
defined( 'ABSPATH' ) || exit;
/**
* Class AttributeManager
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class AttributeManager implements Service {
use PluginHelper;
use ValidateInterface;
protected const ATTRIBUTES = [
GTIN::class,
MPN::class,
Brand::class,
Condition::class,
Gender::class,
Size::class,
SizeSystem::class,
SizeType::class,
Color::class,
Material::class,
Pattern::class,
AgeGroup::class,
Multipack::class,
IsBundle::class,
AvailabilityDate::class,
Adult::class,
];
/**
* @var array Attribute types mapped to product types
*/
protected $attribute_types_map;
/**
* @var AttributeMappingRulesQuery
*/
protected $attribute_mapping_rules_query;
/**
* @var WC
*/
protected $wc;
/**
* AttributeManager constructor.
*
* @param AttributeMappingRulesQuery $attribute_mapping_rules_query
* @param WC $wc
*/
public function __construct( AttributeMappingRulesQuery $attribute_mapping_rules_query, WC $wc ) {
$this->attribute_mapping_rules_query = $attribute_mapping_rules_query;
$this->wc = $wc;
}
/**
* @param WC_Product $product
* @param AttributeInterface $attribute
*
* @throws InvalidValue If the attribute is invalid for the given product.
*/
public function update( WC_Product $product, AttributeInterface $attribute ) {
$this->validate( $product, $attribute::get_id() );
if ( null === $attribute->get_value() || '' === $attribute->get_value() ) {
$this->delete( $product, $attribute::get_id() );
return;
}
$value = $attribute->get_value();
if ( in_array( $attribute::get_value_type(), [ 'bool', 'boolean' ], true ) ) {
$value = wc_bool_to_string( $value );
}
$product->update_meta_data( $this->prefix_meta_key( $attribute::get_id() ), $value );
$product->save_meta_data();
}
/**
* @param WC_Product $product
* @param string $attribute_id
*
* @return AttributeInterface|null
*
* @throws InvalidValue If the attribute ID is invalid for the given product.
*/
public function get( WC_Product $product, string $attribute_id ): ?AttributeInterface {
$this->validate( $product, $attribute_id );
$value = null;
if ( $this->exists( $product, $attribute_id ) ) {
$value = $product->get_meta( $this->prefix_meta_key( $attribute_id ), true );
}
if ( null === $value || '' === $value ) {
return null;
}
$attribute_class = $this->get_attribute_types_for_product( $product )[ $attribute_id ];
return new $attribute_class( $value );
}
/**
* Return all attribute values for the given product, after the mapping rules, GLA attributes, and filters have been applied.
* GLA Attributes has priority over the product attributes.
*
* @since 2.8.0
*
* @param WC_Product $product
*
* @return array of attribute values
* @throws InvalidValue When the product does not exist.
*/
public function get_all_aggregated_values( WC_Product $product ) {
$attributes = $this->get_all_values( $product );
$parent_product = null;
// merge with parent's attributes if it's a variation product
if ( $product instanceof WC_Product_Variation ) {
$parent_product = $this->wc->get_product( $product->get_parent_id() );
$parent_attributes = $this->get_all_values( $parent_product );
$attributes = array_merge( $parent_attributes, $attributes );
}
$mapping_rules = $this->attribute_mapping_rules_query->get_results();
$adapted_product = new WCProductAdapter(
[
'wc_product' => $product,
'parent_wc_product' => $parent_product,
'targetCountry' => 'US', // targetCountry is required to create a new WCProductAdapter instance, but it's not used in the attributes context.
'gla_attributes' => $attributes,
'mapping_rules' => $mapping_rules,
]
);
foreach ( self::ATTRIBUTES as $attribute_class ) {
$attribute_id = $attribute_class::get_id();
if ( $attribute_id === 'size' ) {
$attribute_id = 'sizes';
}
if ( isset( $adapted_product->$attribute_id ) ) {
$attributes[ $attribute_id ] = $adapted_product->$attribute_id;
}
}
return $attributes;
}
/**
* Return attribute value.
*
* @param WC_Product $product
* @param string $attribute_id
*
* @return mixed|null
*/
public function get_value( WC_Product $product, string $attribute_id ) {
$attribute = $this->get( $product, $attribute_id );
return $attribute instanceof AttributeInterface ? $attribute->get_value() : null;
}
/**
* Return all attributes for the given product
*
* @param WC_Product $product
*
* @return AttributeInterface[]
*/
public function get_all( WC_Product $product ): array {
$all_attributes = [];
foreach ( array_keys( $this->get_attribute_types_for_product( $product ) ) as $attribute_id ) {
$attribute = $this->get( $product, $attribute_id );
if ( null !== $attribute ) {
$all_attributes[ $attribute_id ] = $attribute;
}
}
return $all_attributes;
}
/**
* Return all attribute values for the given product
*
* @param WC_Product $product
*
* @return array of attribute values
*/
public function get_all_values( WC_Product $product ): array {
$all_attributes = [];
foreach ( array_keys( $this->get_attribute_types_for_product( $product ) ) as $attribute_id ) {
$attribute = $this->get_value( $product, $attribute_id );
if ( null !== $attribute ) {
$all_attributes[ $attribute_id ] = $attribute;
}
}
return $all_attributes;
}
/**
* @param WC_Product $product
* @param string $attribute_id
*
* @throws InvalidValue If the attribute ID is invalid for the given product.
*/
public function delete( WC_Product $product, string $attribute_id ) {
$this->validate( $product, $attribute_id );
$product->delete_meta_data( $this->prefix_meta_key( $attribute_id ) );
$product->save_meta_data();
}
/**
* Whether the attribute exists and has been set for the product.
*
* @param WC_Product $product
* @param string $attribute_id
*
* @return bool
*
* @since 1.2.0
*/
public function exists( WC_Product $product, string $attribute_id ): bool {
return $product->meta_exists( $this->prefix_meta_key( $attribute_id ) );
}
/**
* Returns an array of attribute types for the given product
*
* @param WC_Product $product
*
* @return string[] of attribute classes mapped to attribute IDs
*/
public function get_attribute_types_for_product( WC_Product $product ): array {
return $this->get_attribute_types_for_product_types( [ $product->get_type() ] );
}
/**
* Returns an array of attribute types for the given product types
*
* @param string[] $product_types array of WooCommerce product types
*
* @return string[] of attribute classes mapped to attribute IDs
*/
public function get_attribute_types_for_product_types( array $product_types ): array {
// flip the product types array to have them as array keys
$product_types_keys = array_flip( $product_types );
// intersect the product types with our stored attributes map to get arrays of attributes matching the given product types
$match_attributes = array_intersect_key( $this->get_attribute_types_map(), $product_types_keys );
// re-index the attributes map array to avoid string ($product_type) array keys
$match_attributes = array_values( $match_attributes );
if ( empty( $match_attributes ) ) {
return [];
}
// merge all of the attribute arrays from the map (there might be duplicates) and return the results
return array_merge( ...$match_attributes );
}
/**
* Returns all available attribute IDs.
*
* @return array
*
* @since 1.3.0
*/
public static function get_available_attribute_ids(): array {
$attributes = [];
foreach ( self::get_available_attribute_types() as $attribute_type ) {
if ( method_exists( $attribute_type, 'get_id' ) ) {
$attribute_id = call_user_func( [ $attribute_type, 'get_id' ] );
$attributes[ $attribute_id ] = $attribute_id;
}
}
return $attributes;
}
/**
* Return an array of all available attribute class names.
*
* @return string[] Attribute class names
*
* @since 1.3.0
*/
public static function get_available_attribute_types(): array {
/**
* Filters the list of available product attributes.
*
* @param string[] $attributes Array of attribute class names (FQN)
*/
return apply_filters( 'woocommerce_gla_product_attribute_types', self::ATTRIBUTES );
}
/**
* Returns an array of attribute types for all product types
*
* @return string[][] of attribute classes mapped to product types
*/
protected function get_attribute_types_map(): array {
if ( ! isset( $this->attribute_types_map ) ) {
$this->map_attribute_types();
}
return $this->attribute_types_map;
}
/**
* @param WC_Product $product
* @param string $attribute_id
*
* @throws InvalidValue If the attribute type is invalid for the given product.
*/
protected function validate( WC_Product $product, string $attribute_id ) {
$attribute_types = $this->get_attribute_types_for_product( $product );
if ( ! isset( $attribute_types[ $attribute_id ] ) ) {
do_action(
'woocommerce_gla_error',
sprintf( 'Attribute "%s" is not supported for a "%s" product (ID: %s).', $attribute_id, $product->get_type(), $product->get_id() ),
__METHOD__
);
throw InvalidValue::not_in_allowed_list( 'attribute_id', array_keys( $attribute_types ) );
}
}
/**
* @throws InvalidClass If any of the given attribute classes do not implement the AttributeInterface.
*/
protected function map_attribute_types(): void {
$this->attribute_types_map = [];
foreach ( self::get_available_attribute_types() as $attribute_type ) {
$this->validate_interface( $attribute_type, AttributeInterface::class );
$attribute_id = call_user_func( [ $attribute_type, 'get_id' ] );
$applicable_types = call_user_func( [ $attribute_type, 'get_applicable_product_types' ] );
/**
* Filters the list of applicable product types for each attribute.
*
* @param string[] $applicable_types Array of WooCommerce product types
* @param string $attribute_type Attribute class name (FQN)
*/
$applicable_types = apply_filters( "woocommerce_gla_attribute_applicable_product_types_{$attribute_id}", $applicable_types, $attribute_type );
foreach ( $applicable_types as $product_type ) {
$this->attribute_types_map[ $product_type ] = $this->attribute_types_map[ $product_type ] ?? [];
$this->attribute_types_map[ $product_type ][ $attribute_id ] = $attribute_type;
}
}
}
}
AvailabilityDate.php 0000644 00000003350 15154777174 0010510 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\AvailabilityDateInput;
defined( 'ABSPATH' ) || exit;
/**
* Class AvailabilityDate
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class AvailabilityDate extends AbstractAttribute {
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'availabilityDate';
}
/**
* Returns a name for the attribute. Used in attribute's input.
*
* @return string
*/
public static function get_name(): string {
return __( 'Availability Date', 'google-listings-and-ads' );
}
/**
* Returns a short description for the attribute. Used in attribute's input.
*
* @return string
*/
public static function get_description(): string {
return __( 'The date a preordered or backordered product becomes available for delivery. Required if product availability is preorder or backorder', 'google-listings-and-ads' );
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*/
public static function get_input_type(): string {
return AvailabilityDateInput::class;
}
}
Brand.php 0000644 00000002673 15154777174 0006335 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\BrandInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Brand
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Brand extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'brand';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variable' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return BrandInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Brand', 'google-listings-and-ads' );
}
}
Color.php 0000644 00000002674 15154777174 0006366 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\ColorInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Color
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Color extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'color';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return ColorInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Color', 'google-listings-and-ads' );
}
}
Condition.php 0000644 00000003613 15154777174 0007230 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\ConditionInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Condition
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Condition extends AbstractAttribute implements WithValueOptionsInterface, WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'condition';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return an array of values available to choose for the attribute.
*
* Note: array key is used as the option key.
*
* @return array
*/
public static function get_value_options(): array {
return [
'new' => __( 'New', 'google-listings-and-ads' ),
'refurbished' => __( 'Refurbished', 'google-listings-and-ads' ),
'used' => __( 'Used', 'google-listings-and-ads' ),
];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return ConditionInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Condition', 'google-listings-and-ads' );
}
}
GTIN.php 0000644 00000002666 15154777174 0006052 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\GTINInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class GTIN
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class GTIN extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'gtin';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return GTINInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'GTIN', 'google-listings-and-ads' );
}
}
Gender.php 0000644 00000003550 15154777174 0006506 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\GenderInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Gender
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Gender extends AbstractAttribute implements WithValueOptionsInterface, WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'gender';
}
/**
* Return an array of values available to choose for the attribute.
*
* Note: array key is used as the option key.
*
* @return array
*/
public static function get_value_options(): array {
return [
'male' => __( 'Male', 'google-listings-and-ads' ),
'female' => __( 'Female', 'google-listings-and-ads' ),
'unisex' => __( 'Unisex', 'google-listings-and-ads' ),
];
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return GenderInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Gender', 'google-listings-and-ads' );
}
}
IsBundle.php 0000644 00000003640 15154777174 0007007 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\IsBundleInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class IsBundle
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class IsBundle extends AbstractAttribute implements WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'isBundle';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute type. Must be a valid PHP type.
*
* @return string
*
* @link https://www.php.net/manual/en/function.settype.php
*/
public static function get_value_type(): string {
return 'boolean';
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return IsBundleInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Is Bundle', 'google-listings-and-ads' );
}
/**
* Returns the attribute sources
*
* @return array
*/
public static function get_sources(): array {
return [
'yes' => __( 'Yes', 'google-listings-and-ads' ),
'no' => __( 'No', 'google-listings-and-ads' ),
];
}
}
MPN.php 0000644 00000002660 15154777174 0005735 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\MPNInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class MPN
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class MPN extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'mpn';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return MPNInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'MPN', 'google-listings-and-ads' );
}
}
Material.php 0000644 00000002716 15154777174 0007043 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\MaterialInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Material
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Material extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'material';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return MaterialInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Material', 'google-listings-and-ads' );
}
}
Multipack.php 0000644 00000003272 15154777174 0007234 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\MultipackInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Multipack
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Multipack extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'multipack';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute type. Must be a valid PHP type.
*
* @return string
*
* @link https://www.php.net/manual/en/function.settype.php
*/
public static function get_value_type(): string {
return 'integer';
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return MultipackInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Multipack', 'google-listings-and-ads' );
}
}
Pattern.php 0000644 00000002710 15154777174 0006714 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\PatternInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Pattern
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Pattern extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'pattern';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return PatternInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Pattern', 'google-listings-and-ads' );
}
}
Size.php 0000644 00000002666 15154777174 0006223 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\SizeInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsFieldTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class Size
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class Size extends AbstractAttribute implements WithMappingInterface {
use IsFieldTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'size';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return SizeInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Size', 'google-listings-and-ads' );
}
}
SizeSystem.php 0000644 00000004407 15154777174 0007423 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\SizeSystemInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class SizeSystem
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class SizeSystem extends AbstractAttribute implements WithValueOptionsInterface, WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'sizeSystem';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return an array of values available to choose for the attribute.
*
* Note: array key is used as the option key.
*
* @return array
*/
public static function get_value_options(): array {
return [
'US' => __( 'US', 'google-listings-and-ads' ),
'EU' => __( 'EU', 'google-listings-and-ads' ),
'UK' => __( 'UK', 'google-listings-and-ads' ),
'DE' => __( 'DE', 'google-listings-and-ads' ),
'FR' => __( 'FR', 'google-listings-and-ads' ),
'IT' => __( 'IT', 'google-listings-and-ads' ),
'AU' => __( 'AU', 'google-listings-and-ads' ),
'BR' => __( 'BR', 'google-listings-and-ads' ),
'CN' => __( 'CN', 'google-listings-and-ads' ),
'JP' => __( 'JP', 'google-listings-and-ads' ),
'MEX' => __( 'MEX', 'google-listings-and-ads' ),
];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return SizeSystemInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Size System', 'google-listings-and-ads' );
}
}
SizeType.php 0000644 00000004160 15154777174 0007054 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\SizeTypeInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\AttributeMapping\Traits\IsEnumTrait;
defined( 'ABSPATH' ) || exit;
/**
* Class SizeType
*
* @see https://support.google.com/merchants/answer/6324497
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
class SizeType extends AbstractAttribute implements WithValueOptionsInterface, WithMappingInterface {
use IsEnumTrait;
/**
* Returns the attribute ID.
*
* Must be the same as a Google product's property name to be set automatically.
*
* @return string
*
* @see \Google\Service\ShoppingContent\Product for the list of properties.
*/
public static function get_id(): string {
return 'sizeType';
}
/**
* Return an array of WooCommerce product types that this attribute can be applied to.
*
* @return array
*/
public static function get_applicable_product_types(): array {
return [ 'simple', 'variation' ];
}
/**
* Return an array of values available to choose for the attribute.
*
* Note: array key is used as the option key.
*
* @return array
*/
public static function get_value_options(): array {
return [
'regular' => __( 'Regular', 'google-listings-and-ads' ),
'petite' => __( 'Petite', 'google-listings-and-ads' ),
'plus' => __( 'Plus', 'google-listings-and-ads' ),
'tall' => __( 'Tall', 'google-listings-and-ads' ),
'big' => __( 'Big', 'google-listings-and-ads' ),
'maternity' => __( 'Maternity', 'google-listings-and-ads' ),
];
}
/**
* Return the attribute's input class. Must be an instance of `AttributeInputInterface`.
*
* @return string
*
* @see AttributeInputInterface
*
* @since 1.5.0
*/
public static function get_input_type(): string {
return SizeTypeInput::class;
}
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string {
return __( 'Size Type', 'google-listings-and-ads' );
}
}
WithMappingInterface.php 0000644 00000001227 15154777174 0011351 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
defined( 'ABSPATH' ) || exit;
/**
* Interface with specific options for mapping
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
interface WithMappingInterface {
/**
* Returns the attribute name
*
* @return string
*/
public static function get_name(): string;
/**
* Returns true if the attribute is enum type
*
* @return boolean
*/
public static function is_enum(): bool;
/**
* Returns the available attribute sources
*
* @return array
*/
public static function get_sources(): array;
}
WithValueOptionsInterface.php 0000644 00000000775 15154777174 0012415 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes;
defined( 'ABSPATH' ) || exit;
/**
* Interface WithValueOptionsInterface
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*/
interface WithValueOptionsInterface {
/**
* Return an array of values available to choose for the attribute.
*
* Note: array key is used as the option key.
*
* @return array
*/
public static function get_value_options(): array;
}
AttributesForm.php 0000644 00000017455 15155172351 0010250 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Form;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\FormException;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\InputInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Select;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\SelectWithTextInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input\GTINInput;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidValue;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\ValidateInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\AttributeInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes\WithValueOptionsInterface;
defined( 'ABSPATH' ) || exit;
/**
* Class AttributesForm
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes
*/
class AttributesForm extends Form {
use ValidateInterface;
/**
* @var string[]
*/
protected $attribute_types = [];
/**
* AttributesForm constructor.
*
* @param string[] $attribute_types The names of the attribute classes extending AttributeInterface.
* @param array $data
*/
public function __construct( array $attribute_types, array $data = [] ) {
foreach ( $attribute_types as $attribute_type ) {
$this->add_attribute( $attribute_type );
}
parent::__construct( $data );
}
/**
* Return the data used for the input's view.
*
* @return array
*/
public function get_view_data(): array {
$view_data = parent::get_view_data();
// add classes to hide/display attributes based on product type
foreach ( $view_data['children'] as $index => $input ) {
if ( ! isset( $this->attribute_types[ $index ] ) ) {
continue;
}
$attribute_type = $this->attribute_types[ $index ];
$attribute_product_types = self::get_attribute_product_types( $attribute_type );
$hidden_types = $attribute_product_types['hidden'];
$visible_types = $attribute_product_types['visible'];
$input['gla_wrapper_class'] = $input['gla_wrapper_class'] ?? '';
if ( ! empty( $visible_types ) ) {
$input['gla_wrapper_class'] .= ' show_if_' . join( ' show_if_', $visible_types );
}
if ( ! empty( $hidden_types ) ) {
$input['gla_wrapper_class'] .= ' hide_if_' . join( ' hide_if_', $hidden_types );
}
$view_data['children'][ $index ] = $input;
}
return $view_data;
}
/**
* Get the hidden and visible types of an attribute's applicable product types.
*
* @param string $attribute_type The name of an attribute class extending AttributeInterface.
*
* @return array
*/
public static function get_attribute_product_types( string $attribute_type ): array {
$attribute_id = call_user_func( [ $attribute_type, 'get_id' ] );
$applicable_product_types = call_user_func( [ $attribute_type, 'get_applicable_product_types' ] );
/**
* This filter is documented in AttributeManager::map_attribute_types
*
* @see AttributeManager::map_attribute_types
*/
$applicable_product_types = apply_filters( "woocommerce_gla_attribute_applicable_product_types_{$attribute_id}", $applicable_product_types, $attribute_type );
/**
* Filters the list of product types to hide the attribute for.
*/
$hidden_product_types = apply_filters( "woocommerce_gla_attribute_hidden_product_types_{$attribute_id}", [] );
$visible_product_types = array_diff( $applicable_product_types, $hidden_product_types );
return [
'hidden' => $hidden_product_types,
'visible' => $visible_product_types,
];
}
/**
* @param InputInterface $input
* @param AttributeInterface $attribute
*
* @return InputInterface
*/
public static function init_input( InputInterface $input, AttributeInterface $attribute ) {
$input->set_id( $attribute::get_id() )
->set_name( $attribute::get_id() );
$value_options = [];
if ( $attribute instanceof WithValueOptionsInterface ) {
$value_options = $attribute::get_value_options();
}
$value_options = apply_filters( "woocommerce_gla_product_attribute_value_options_{$attribute::get_id()}", $value_options );
if ( ! empty( $value_options ) ) {
if ( ! $input instanceof Select && ! $input instanceof SelectWithTextInput ) {
$new_input = new SelectWithTextInput();
$new_input->set_label( $input->get_label() )
->set_description( $input->get_description() );
// When GTIN uses the SelectWithTextInput field, copy the readonly/hidden attributes from the GTINInput field.
if ( $input->name === 'gtin' ) {
$gtin_input = new GTINInput();
$new_input->set_hidden( $gtin_input->is_hidden() );
$new_input->set_readonly( $gtin_input->is_readonly() );
}
return self::init_input( $new_input, $attribute );
}
// add a 'default' value option
$value_options = [ '' => __( 'Default', 'google-listings-and-ads' ) ] + $value_options;
$input->set_options( $value_options );
}
return $input;
}
/**
* Add an attribute to the form
*
* @param string $attribute_type The name of an attribute class extending AttributeInterface.
* @param string|null $input_type The name of an input class extending InputInterface to use for attribute input.
*
* @return AttributesForm
*
* @throws InvalidValue If the attribute type is invalid or an invalid input type is specified for the attribute.
* @throws FormException If form is already submitted.
*/
public function add_attribute( string $attribute_type, ?string $input_type = null ): AttributesForm {
$this->validate_interface( $attribute_type, AttributeInterface::class );
// use the attribute's default input type if none provided.
if ( empty( $input_type ) ) {
$input_type = call_user_func( [ $attribute_type, 'get_input_type' ] );
}
$this->validate_interface( $input_type, InputInterface::class );
$attribute_input = self::init_input( new $input_type(), new $attribute_type() );
if ( ! $attribute_input->is_hidden() ) {
$this->add( $attribute_input );
$attribute_id = call_user_func( [ $attribute_type, 'get_id' ] );
$this->attribute_types[ $attribute_id ] = $attribute_type;
}
return $this;
}
/**
* Remove an attribute from the form
*
* @param string $attribute_type The name of an attribute class extending AttributeInterface.
*
* @return AttributesForm
*
* @throws InvalidValue If the attribute type is invalid or an invalid input type is specified for the attribute.
* @throws FormException If form is already submitted.
*/
public function remove_attribute( string $attribute_type ): AttributesForm {
$this->validate_interface( $attribute_type, AttributeInterface::class );
$attribute_id = call_user_func( [ $attribute_type, 'get_id' ] );
unset( $this->attribute_types[ $attribute_id ] );
$this->remove( $attribute_id );
return $this;
}
/**
* Sets the input type for the given attribute.
*
* @param string $attribute_type The name of an attribute class extending AttributeInterface.
* @param string $input_type The name of an input class extending InputInterface to use for attribute input.
*
* @return $this
*
* @throws FormException If form is already submitted.
*/
public function set_attribute_input( string $attribute_type, string $input_type ): AttributesForm {
if ( $this->is_submitted ) {
throw FormException::cannot_modify_submitted();
}
$this->validate_interface( $attribute_type, AttributeInterface::class );
$this->validate_interface( $input_type, InputInterface::class );
$attribute_id = call_user_func( [ $attribute_type, 'get_id' ] );
if ( $this->has( $attribute_id ) ) {
$this->children[ $attribute_id ] = self::init_input( new $input_type(), new $attribute_type() );
}
return $this;
}
}
AttributesTab.php 0000644 00000011704 15155172351 0010042 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Admin;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\AdminConditional;
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\Product\Attributes\AttributeManager;
use Automattic\WooCommerce\GoogleListingsAndAds\Product\ProductSyncer;
use WC_Product;
defined( 'ABSPATH' ) || exit;
/**
* Class AttributesTab
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes
*/
class AttributesTab implements Service, Registerable, Conditional {
use AdminConditional;
use AttributesTrait;
/**
* @var Admin
*/
protected $admin;
/**
* @var AttributeManager
*/
protected $attribute_manager;
/**
* @var MerchantCenterService
*/
protected $merchant_center;
/**
* AttributesTab constructor.
*
* @param Admin $admin
* @param AttributeManager $attribute_manager
* @param MerchantCenterService $merchant_center
*/
public function __construct( Admin $admin, AttributeManager $attribute_manager, MerchantCenterService $merchant_center ) {
$this->admin = $admin;
$this->attribute_manager = $attribute_manager;
$this->merchant_center = $merchant_center;
}
/**
* Register a service.
*/
public function register(): void {
// Register the hooks only if Merchant Center is set up.
if ( ! $this->merchant_center->is_setup_complete() ) {
return;
}
add_action(
'woocommerce_new_product',
function ( int $product_id, WC_Product $product ) {
$this->handle_update_product( $product );
},
10,
2
);
add_action(
'woocommerce_update_product',
function ( int $product_id, WC_Product $product ) {
$this->handle_update_product( $product );
},
10,
2
);
add_action(
'woocommerce_product_data_tabs',
function ( array $tabs ) {
return $this->add_tab( $tabs );
}
);
add_action(
'woocommerce_product_data_panels',
function () {
$this->render_panel();
}
);
}
/**
* Adds the Google for WooCommerce tab to the WooCommerce product data box.
*
* @param array $tabs The current product data tabs.
*
* @return array An array with product tabs with the Yoast SEO tab added.
*/
private function add_tab( array $tabs ): array {
$tabs['gla_attributes'] = [
'label' => 'Google for WooCommerce',
'class' => 'gla',
'target' => 'gla_attributes',
];
return $tabs;
}
/**
* Render the product attributes tab.
*/
private function render_panel() {
$product = wc_get_product( get_the_ID() );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->admin->get_view( 'attributes/tab-panel', [ 'form' => $this->get_form( $product )->get_view_data() ] );
}
/**
* Handle form submission and update the product attributes.
*
* @param WC_Product $product
*/
private function handle_update_product( WC_Product $product ) {
/**
* Array of `true` values for each product IDs already handled by this method. Used to prevent double submission.
*
* @var bool[] $already_updated
*/
static $already_updated = [];
if ( isset( $already_updated[ $product->get_id() ] ) ) {
return;
}
$form = $this->get_form( $product );
$form_view_data = $form->get_view_data();
// phpcs:disable WordPress.Security.NonceVerification
if ( empty( $_POST[ $form_view_data['name'] ] ) ) {
return;
}
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$submitted_data = (array) wc_clean( wp_unslash( $_POST[ $form_view_data['name'] ] ) );
// phpcs:enable WordPress.Security.NonceVerification
$form->submit( $submitted_data );
$this->update_data( $product, $form->get_data() );
$already_updated[ $product->get_id() ] = true;
}
/**
* @param WC_Product $product
*
* @return AttributesForm
*/
protected function get_form( WC_Product $product ): AttributesForm {
$attribute_types = $this->attribute_manager->get_attribute_types_for_product_types( $this->get_applicable_product_types() );
$form = new AttributesForm( $attribute_types, $this->attribute_manager->get_all_values( $product ) );
$form->set_name( 'attributes' );
return $form;
}
/**
* @param WC_Product $product
* @param array $data
*
* @return void
*/
protected function update_data( WC_Product $product, array $data ): void {
foreach ( $this->attribute_manager->get_attribute_types_for_product( $product ) as $attribute_id => $attribute_type ) {
if ( isset( $data[ $attribute_id ] ) ) {
$this->attribute_manager->update( $product, new $attribute_type( $data[ $attribute_id ] ) );
}
}
}
}
AttributesTrait.php 0000644 00000001172 15155172351 0010415 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes;
/**
* Trait AttributesTrait
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes
*/
trait AttributesTrait {
/**
* Return an array of WooCommerce product types that the Google for WooCommerce tab can be displayed for.
*
* @return array of WooCommerce product types (e.g. 'simple', 'variable', etc.)
*/
protected function get_applicable_product_types(): array {
return apply_filters( 'woocommerce_gla_attributes_tab_applicable_product_types', [ 'simple', 'variable' ] );
}
}
Input/AdultInput.php 0000644 00000001267 15155172351 0010460 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\BooleanSelect;
defined( 'ABSPATH' ) || exit;
/**
* Class Adult
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class AdultInput extends BooleanSelect {
/**
* AdultInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Adult content', 'google-listings-and-ads' ) );
$this->set_description( __( 'Whether the product contains nudity or sexually suggestive content', 'google-listings-and-ads' ) );
}
}
Input/AgeGroupInput.php 0000644 00000001211 15155172351 0011105 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Select;
defined( 'ABSPATH' ) || exit;
/**
* Class AgeGroup
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class AgeGroupInput extends Select {
/**
* AgeGroupInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Age Group', 'google-listings-and-ads' ) );
$this->set_description( __( 'Target age group of the item.', 'google-listings-and-ads' ) );
}
}
Input/AttributeInputInterface.php 0000644 00000001433 15155172351 0013166 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
defined( 'ABSPATH' ) || exit;
/**
* Class AttributeInputInterface
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input
*
* @since 1.5.0
*/
interface AttributeInputInterface {
/**
* Returns a name for the attribute input.
*
* @return string
*/
public static function get_name(): string;
/**
* Returns a short description for the attribute input.
*
* @return string
*/
public static function get_description(): string;
/**
* Returns the input class used for the attribute input.
*
* Must be an instance of `InputInterface`.
*
* @return string
*/
public static function get_input_type(): string;
}
Input/AvailabilityDateInput.php 0000644 00000001426 15155172351 0012614 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\DateTime;
defined( 'ABSPATH' ) || exit;
/**
* Class AvailabilityDate
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class AvailabilityDateInput extends DateTime {
/**
* AvailabilityDateInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Availability Date', 'google-listings-and-ads' ) );
$this->set_description( __( 'The date a preordered or backordered product becomes available for delivery. Required if product availability is preorder or backorder', 'google-listings-and-ads' ) );
}
}
Input/BrandInput.php 0000644 00000001160 15155172351 0010425 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
defined( 'ABSPATH' ) || exit;
/**
* Class Brand
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class BrandInput extends Text {
/**
* BrandInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Brand', 'google-listings-and-ads' ) );
$this->set_description( __( 'Brand of the product.', 'google-listings-and-ads' ) );
}
}
Input/ColorInput.php 0000644 00000001160 15155172351 0010455 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
defined( 'ABSPATH' ) || exit;
/**
* Class Color
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class ColorInput extends Text {
/**
* ColorInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Color', 'google-listings-and-ads' ) );
$this->set_description( __( 'Color of the product.', 'google-listings-and-ads' ) );
}
}
Input/ConditionInput.php 0000644 00000001216 15155172351 0011327 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Select;
defined( 'ABSPATH' ) || exit;
/**
* Class Condition
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class ConditionInput extends Select {
/**
* ConditionInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Condition', 'google-listings-and-ads' ) );
$this->set_description( __( 'Condition or state of the item.', 'google-listings-and-ads' ) );
}
}
Input/GTINInput.php 0000644 00000003125 15155172351 0010143 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
use Automattic\WooCommerce\GoogleListingsAndAds\HelperTraits\GTINMigrationUtilities;
defined( 'ABSPATH' ) || exit;
/**
* Class GTIN
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class GTINInput extends Text {
use GTINMigrationUtilities;
/**
* GTINInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Global Trade Item Number (GTIN)', 'google-listings-and-ads' ) );
$this->set_description( __( 'Global Trade Item Number (GTIN) for your item. These identifiers include UPC (in North America), EAN (in Europe), JAN (in Japan), and ISBN (for books)', 'google-listings-and-ads' ) );
$this->set_field_visibility();
}
/**
* Controls the inputs visibility based on the WooCommerce version and the
* initial version of Google for WooCommerce at the time of installation.
*
* @since 2.9.0
* @return void
*/
public function set_field_visibility(): void {
if ( $this->is_gtin_available_in_core() ) {
// For versions after the GTIN changes are published. Hide the GTIN field from G4W tab. Otherwise, set as readonly.
if ( $this->should_hide_gtin() ) {
$this->set_hidden( true );
} else {
$this->set_readonly( true );
$this->set_description( __( 'The Global Trade Item Number (GTIN) for your item can now be entered on the "Inventory" tab', 'google-listings-and-ads' ) );
}
}
}
}
Input/GenderInput.php 0000644 00000001221 15155172351 0010601 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Select;
defined( 'ABSPATH' ) || exit;
/**
* Class Gender
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class GenderInput extends Select {
/**
* GenderInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Gender', 'google-listings-and-ads' ) );
$this->set_description( __( 'The gender for which your product is intended.', 'google-listings-and-ads' ) );
}
}
Input/IsBundleInput.php 0000644 00000001377 15155172351 0011116 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\BooleanSelect;
defined( 'ABSPATH' ) || exit;
/**
* Class IsBundle
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class IsBundleInput extends BooleanSelect {
/**
* IsBundleInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Is Bundle?', 'google-listings-and-ads' ) );
$this->set_description( __( 'Whether the item is a bundle of products. A bundle is a custom grouping of different products sold by a merchant for a single price.', 'google-listings-and-ads' ) );
}
}
Input/MPNInput.php 0000644 00000001254 15155172351 0010035 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
defined( 'ABSPATH' ) || exit;
/**
* Class MPN
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class MPNInput extends Text {
/**
* MPNInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Manufacturer Part Number (MPN)', 'google-listings-and-ads' ) );
$this->set_description( __( 'This code uniquely identifies the product to its manufacturer.', 'google-listings-and-ads' ) );
}
}
Input/MaterialInput.php 0000644 00000001216 15155172351 0011137 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
defined( 'ABSPATH' ) || exit;
/**
* Class Material
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class MaterialInput extends Text {
/**
* MaterialInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Material', 'google-listings-and-ads' ) );
$this->set_description( __( 'The material of which the item is made.', 'google-listings-and-ads' ) );
}
}
Input/MultipackInput.php 0000644 00000001500 15155172351 0011326 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Integer;
defined( 'ABSPATH' ) || exit;
/**
* Class Multipack
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class MultipackInput extends Integer {
/**
* MultipackInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Multipack', 'google-listings-and-ads' ) );
$this->set_description( __( 'The number of identical products in a multipack. Use this attribute to indicate that you\'ve grouped multiple identical products for sale as one item.', 'google-listings-and-ads' ) );
$this->set_block_attribute( 'min', [ 'value' => 0 ] );
}
}
Input/PatternInput.php 0000644 00000001211 15155172351 0011011 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
defined( 'ABSPATH' ) || exit;
/**
* Class Pattern
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class PatternInput extends Text {
/**
* PatternInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Pattern', 'google-listings-and-ads' ) );
$this->set_description( __( 'The item\'s pattern (e.g. polka dots).', 'google-listings-and-ads' ) );
}
}
Input/SizeInput.php 0000644 00000001153 15155172351 0010313 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Text;
defined( 'ABSPATH' ) || exit;
/**
* Class Size
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class SizeInput extends Text {
/**
* SizeInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Size', 'google-listings-and-ads' ) );
$this->set_description( __( 'Size of the product.', 'google-listings-and-ads' ) );
}
}
Input/SizeSystemInput.php 0000644 00000001271 15155172351 0011521 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Select;
defined( 'ABSPATH' ) || exit;
/**
* Class SizeSystem
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class SizeSystemInput extends Select {
/**
* SizeSystemInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Size system', 'google-listings-and-ads' ) );
$this->set_description( __( 'System in which the size is specified. Recommended for apparel items.', 'google-listings-and-ads' ) );
}
}
Input/SizeTypeInput.php 0000644 00000001237 15155172351 0011160 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes\Input;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Select;
defined( 'ABSPATH' ) || exit;
/**
* Class SizeType
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Product\Attributes
*
* @since 1.5.0
*/
class SizeTypeInput extends Select {
/**
* SizeTypeInput constructor.
*/
public function __construct() {
parent::__construct();
$this->set_label( __( 'Size type', 'google-listings-and-ads' ) );
$this->set_description( __( 'The cut of the item. Recommended for apparel items.', 'google-listings-and-ads' ) );
}
}
VariationsAttributes.php 0000644 00000012114 15155172351 0011447 0 ustar 00 <?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Admin;
use Automattic\WooCommerce\GoogleListingsAndAds\Admin\Input\Form;
use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\AdminConditional;
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\Product\Attributes\AttributeManager;
use WC_Product_Variation;
use WP_Post;
defined( 'ABSPATH' ) || exit;
/**
* Class VariationsAttributes
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Admin\Product\Attributes
*/
class VariationsAttributes implements Service, Registerable, Conditional {
use AdminConditional;
/**
* @var Admin
*/
protected $admin;
/**
* @var AttributeManager
*/
protected $attribute_manager;
/**
* @var MerchantCenterService
*/
protected $merchant_center;
/**
* VariationsAttributes constructor.
*
* @param Admin $admin
* @param AttributeManager $attribute_manager
* @param MerchantCenterService $merchant_center
*/
public function __construct( Admin $admin, AttributeManager $attribute_manager, MerchantCenterService $merchant_center ) {
$this->admin = $admin;
$this->attribute_manager = $attribute_manager;
$this->merchant_center = $merchant_center;
}
/**
* Register a service.
*/
public function register(): void {
// Register the hooks only if Merchant Center is set up.
if ( ! $this->merchant_center->is_setup_complete() ) {
return;
}
add_action(
'woocommerce_product_after_variable_attributes',
function ( int $variation_index, array $variation_data, WP_Post $variation ) {
$this->render_attributes_form( $variation_index, $variation );
},
90,
3
);
add_action(
'woocommerce_save_product_variation',
function ( int $variation_id, int $variation_index ) {
$this->handle_save_variation( $variation_id, $variation_index );
},
10,
2
);
}
/**
* Render the attributes form for variations.
*
* @param int $variation_index Position in the loop.
* @param WP_Post $variation Post data.
*/
private function render_attributes_form( int $variation_index, WP_Post $variation ) {
/**
* @var WC_Product_Variation $product
*/
$product = wc_get_product( $variation->ID );
$data = $this->get_form( $product, $variation_index )->get_view_data();
// Do not render the form if it doesn't contain any child attributes.
$attributes = reset( $data['children'] );
if ( empty( $data['children'] ) || empty( $attributes['children'] ) ) {
return;
}
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->admin->get_view( 'attributes/variations-form', $data );
}
/**
* Handle form submission and update the product attributes.
*
* @param int $variation_id
* @param int $variation_index
*/
private function handle_save_variation( int $variation_id, int $variation_index ) {
/**
* @var WC_Product_Variation $variation
*/
$variation = wc_get_product( $variation_id );
$form = $this->get_form( $variation, $variation_index );
$form_view_data = $form->get_view_data();
// phpcs:disable WordPress.Security.NonceVerification
if ( empty( $_POST[ $form_view_data['name'] ] ) ) {
return;
}
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$submitted_data = (array) wc_clean( wp_unslash( $_POST[ $form_view_data['name'] ] ) );
// phpcs:enable WordPress.Security.NonceVerification
$form->submit( $submitted_data );
$form_data = $form->get_data();
if ( ! empty( $form_data[ $variation_index ] ) ) {
$this->update_data( $variation, $form_data[ $variation_index ] );
}
}
/**
* @param WC_Product_Variation $variation
* @param int $variation_index
*
* @return Form
*/
protected function get_form( WC_Product_Variation $variation, int $variation_index ): Form {
$attribute_types = $this->attribute_manager->get_attribute_types_for_product( $variation );
$attribute_form = new AttributesForm( $attribute_types );
$attribute_form->set_name( (string) $variation_index );
$form = new Form();
$form->set_name( 'variation_attributes' )
->add( $attribute_form )
->set_data( [ (string) $variation_index => $this->attribute_manager->get_all_values( $variation ) ] );
return $form;
}
/**
* @param WC_Product_Variation $variation
* @param array $data
*
* @return void
*/
protected function update_data( WC_Product_Variation $variation, array $data ): void {
foreach ( $this->attribute_manager->get_attribute_types_for_product( $variation ) as $attribute_id => $attribute_type ) {
if ( isset( $data[ $attribute_id ] ) ) {
$this->attribute_manager->update( $variation, new $attribute_type( $data[ $attribute_id ] ) );
}
}
}
}