rebase code on oct-10-2023
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Block template registry.
|
||||
*/
|
||||
final class BlockTemplateRegistry {
|
||||
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var BlockTemplateRegistry|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Templates.
|
||||
*/
|
||||
protected $templates = array();
|
||||
|
||||
/**
|
||||
* Get the instance of the class.
|
||||
*/
|
||||
public static function get_instance(): BlockTemplateRegistry {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a single template.
|
||||
*
|
||||
* @param string $id Template ID.
|
||||
* @param array $template Template layout.
|
||||
*/
|
||||
public function register( BlockTemplateInterface $template ) {
|
||||
$id = $template->get_id();
|
||||
|
||||
if ( isset( $this->templates[ $id ] ) ) {
|
||||
throw new \ValueError( 'A template with the specified ID already exists in the registry.' );
|
||||
}
|
||||
|
||||
$this->templates[ $id ] = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registered templates.
|
||||
*/
|
||||
public function get_all_registered(): array {
|
||||
return $this->templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single registered template.
|
||||
*
|
||||
* @param string $id ID of the template
|
||||
*/
|
||||
public function get_registered( $id ): BlockTemplateInterface {
|
||||
return isset( $this->templates[ $id ] ) ? $this->templates[ $id ] : null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry;
|
||||
|
||||
/**
|
||||
* Block template controller.
|
||||
*/
|
||||
class BlockTemplatesController {
|
||||
|
||||
/**
|
||||
* Block template registry
|
||||
*
|
||||
* @var BlockTemplateRegistry
|
||||
*/
|
||||
private $block_template_registry;
|
||||
|
||||
/**
|
||||
* Block template transformer.
|
||||
*
|
||||
* @var TemplateTransformer
|
||||
*/
|
||||
private $template_transformer;
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
public function init( $block_template_registry, $template_transformer ) {
|
||||
$this->block_template_registry = $block_template_registry;
|
||||
$this->template_transformer = $template_transformer;
|
||||
add_action( 'rest_api_init', array( $this, 'register_templates' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register templates in the blocks endpoint.
|
||||
*/
|
||||
public function register_templates() {
|
||||
$templates = $this->block_template_registry->get_all_registered();
|
||||
|
||||
foreach ( $templates as $template ) {
|
||||
add_filter( 'pre_get_block_templates', function( $query_result, $query, $template_type ) use( $template ) {
|
||||
if ( ! isset( $query['area'] ) || $query['area'] !== $template->get_area() ) {
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
$wp_block_template = $this->template_transformer->transform( $template );
|
||||
$query_result[] = $wp_block_template;
|
||||
|
||||
return $query_result;
|
||||
}, 10, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Template transformer.
|
||||
*/
|
||||
class TemplateTransformer {
|
||||
|
||||
/**
|
||||
* Transform the WooCommerceBlockTemplate to a WP_Block_Template.
|
||||
*
|
||||
* @param object $block_template The product template.
|
||||
*/
|
||||
public function transform( BlockTemplateInterface $block_template ): \WP_Block_Template {
|
||||
$template = new \WP_Block_Template();
|
||||
$template->id = $block_template->get_id();
|
||||
$template->theme = 'woocommerce/woocommerce';
|
||||
$template->content = $block_template->get_formatted_template();
|
||||
$template->source = 'plugin';
|
||||
$template->slug = $block_template->get_id();
|
||||
$template->type = 'wp_template';
|
||||
$template->title = $block_template->get_title();
|
||||
$template->description = $block_template->get_description();
|
||||
$template->status = 'publish';
|
||||
$template->has_theme_file = true;
|
||||
$template->origin = 'plugin';
|
||||
$template->is_custom = false; // Templates loaded from the filesystem aren't custom, ones that have been edited and loaded from the DB are.
|
||||
$template->post_types = array(); // Don't appear in any Edit Post template selector dropdown.
|
||||
$template->area = $block_template->get_area();
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Block configuration used to specify blocks in BlockTemplate.
|
||||
*/
|
||||
class AbstractBlock implements BlockInterface {
|
||||
/**
|
||||
* The block name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* The block ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* The block order.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $order = 10;
|
||||
|
||||
/**
|
||||
* The block attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $attributes = [];
|
||||
|
||||
/**
|
||||
* The block template that this block belongs to.
|
||||
*
|
||||
* @var BlockTemplate
|
||||
*/
|
||||
private $root_template;
|
||||
|
||||
/**
|
||||
* The parent container.
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
/**
|
||||
* Block constructor.
|
||||
*
|
||||
* @param array $config The block configuration.
|
||||
* @param BlockTemplateInterface $root_template The block template that this block belongs to.
|
||||
* @param BlockContainerInterface|null $parent The parent block container.
|
||||
*
|
||||
* @throws \ValueError If the block configuration is invalid.
|
||||
* @throws \ValueError If the parent block container does not belong to the same template as the block.
|
||||
*/
|
||||
public function __construct( array $config, BlockTemplateInterface &$root_template, ContainerInterface &$parent = null ) {
|
||||
$this->validate( $config, $root_template, $parent );
|
||||
|
||||
$this->root_template = $root_template;
|
||||
$this->parent = is_null( $parent ) ? $root_template : $parent;
|
||||
|
||||
$this->name = $config[ self::NAME_KEY ];
|
||||
|
||||
if ( ! isset( $config[ self::ID_KEY ] ) ) {
|
||||
$this->id = $this->root_template->generate_block_id( $this->get_name() );
|
||||
} else {
|
||||
$this->id = $config[ self::ID_KEY ];
|
||||
}
|
||||
|
||||
if ( isset( $config[ self::ORDER_KEY ] ) ) {
|
||||
$this->order = $config[ self::ORDER_KEY ];
|
||||
}
|
||||
|
||||
if ( isset( $config[ self::ATTRIBUTES_KEY ] ) ) {
|
||||
$this->attributes = $config[ self::ATTRIBUTES_KEY ];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate block configuration.
|
||||
*
|
||||
* @param array $config The block configuration.
|
||||
* @param BlockTemplateInterface $root_template The block template that this block belongs to.
|
||||
* @param ContainerInterface|null $parent The parent block container.
|
||||
*
|
||||
* @throws \ValueError If the block configuration is invalid.
|
||||
* @throws \ValueError If the parent block container does not belong to the same template as the block.
|
||||
*/
|
||||
protected function validate( array $config, BlockTemplateInterface &$root_template, ContainerInterface &$parent = null ) {
|
||||
if ( isset( $parent ) && ( $parent->get_root_template() !== $root_template ) ) {
|
||||
throw new \ValueError( 'The parent block must belong to the same template as the block.' );
|
||||
}
|
||||
|
||||
if ( ! isset( $config[ self::NAME_KEY ] ) || ! is_string( $config[ self::NAME_KEY ] ) ) {
|
||||
throw new \ValueError( 'The block name must be specified.' );
|
||||
}
|
||||
|
||||
if ( isset( $config[ self::ORDER_KEY ] ) && ! is_int( $config[ self::ORDER_KEY ] ) ) {
|
||||
throw new \ValueError( 'The block order must be an integer.' );
|
||||
}
|
||||
|
||||
if ( isset( $config[ self::ATTRIBUTES_KEY ] ) && ! is_array( $config[ self::ATTRIBUTES_KEY ] ) ) {
|
||||
throw new \ValueError( 'The block attributes must be an array.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block name.
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block ID.
|
||||
*/
|
||||
public function get_id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block order.
|
||||
*/
|
||||
public function get_order(): int {
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block order.
|
||||
*
|
||||
* @param int $order The block order.
|
||||
*/
|
||||
public function set_order( int $order ) {
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block attributes.
|
||||
*/
|
||||
public function get_attributes(): array {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block attributes.
|
||||
*
|
||||
* @param array $attributes The block attributes.
|
||||
*/
|
||||
public function set_attributes( array $attributes ) {
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template that this block belongs to.
|
||||
*/
|
||||
public function &get_root_template(): BlockTemplateInterface {
|
||||
return $this->root_template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent block container.
|
||||
*/
|
||||
public function &get_parent(): ContainerInterface {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the block configuration as a formatted template.
|
||||
*
|
||||
* @return array The block configuration as a formatted template.
|
||||
*/
|
||||
public function get_formatted_template(): array {
|
||||
$arr = [
|
||||
$this->get_name(),
|
||||
$this->get_attributes(),
|
||||
];
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\ContainerInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Block template class.
|
||||
*/
|
||||
abstract class AbstractBlockTemplate implements BlockTemplateInterface {
|
||||
use BlockContainerTrait;
|
||||
|
||||
/**
|
||||
* Get the template ID.
|
||||
*/
|
||||
public abstract function get_id(): string;
|
||||
|
||||
/**
|
||||
* Get the template title.
|
||||
*/
|
||||
public function get_title(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template description.
|
||||
*/
|
||||
public function get_description(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template area.
|
||||
*/
|
||||
public function get_area(): string {
|
||||
return 'uncategorized';
|
||||
}
|
||||
|
||||
/**
|
||||
* The block cache.
|
||||
*
|
||||
* @var BlockInterface[]
|
||||
*/
|
||||
private $block_cache = [];
|
||||
|
||||
/**
|
||||
* Get a block by ID.
|
||||
*
|
||||
* @param string $block_id The block ID.
|
||||
*/
|
||||
public function get_block( string $block_id ): ?BlockInterface {
|
||||
return $this->block_cache[ $block_id ] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches a block in the template. This is an internal method and should not be called directly
|
||||
* except for classes that implement BlockContainerInterface, in their add_block() method.
|
||||
*
|
||||
* @param BlockInterface $block The block to cache.
|
||||
*
|
||||
* @throws \ValueError If a block with the specified ID already exists in the template.
|
||||
* @throws \ValueError If the block template that the block belongs to is not this template.
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
public function cache_block( BlockInterface &$block ) {
|
||||
$id = $block->get_id();
|
||||
|
||||
if ( isset( $this->block_cache[ $id ] ) ) {
|
||||
throw new \ValueError( 'A block with the specified ID already exists in the template.' );
|
||||
}
|
||||
|
||||
if ( $block->get_root_template() !== $this ) {
|
||||
throw new \ValueError( 'The block template that the block belongs to must be the same as this template.' );
|
||||
}
|
||||
|
||||
$this->block_cache[ $id ] = $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a block ID based on a base.
|
||||
*
|
||||
* @param string $id_base The base to use when generating an ID.
|
||||
* @return string
|
||||
*/
|
||||
public function generate_block_id( string $id_base ): string {
|
||||
$instance_count = 0;
|
||||
|
||||
do {
|
||||
$instance_count++;
|
||||
$block_id = $id_base . '-' . $instance_count;
|
||||
} while ( isset( $this->block_cache[ $block_id ] ) );
|
||||
|
||||
return $block_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root template.
|
||||
*/
|
||||
public function &get_root_template(): BlockTemplateInterface {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the inner blocks as a formatted template.
|
||||
*/
|
||||
public function get_formatted_template(): array {
|
||||
$inner_blocks = $this->get_inner_blocks_sorted_by_order();
|
||||
|
||||
$inner_blocks_formatted_template = array_map(
|
||||
function( Block $block ) {
|
||||
return $block->get_formatted_template();
|
||||
},
|
||||
$inner_blocks
|
||||
);
|
||||
|
||||
return $inner_blocks_formatted_template;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Generic block with container properties to be used in BlockTemplate.
|
||||
*/
|
||||
class Block extends AbstractBlock implements BlockContainerInterface {
|
||||
use BlockContainerTrait;
|
||||
|
||||
/**
|
||||
* Get the block configuration as a formatted template.
|
||||
*
|
||||
* @return array The block configuration as a formatted template.
|
||||
*/
|
||||
public function get_formatted_template(): array {
|
||||
$arr = [
|
||||
$this->get_name(),
|
||||
$this->get_attributes(),
|
||||
];
|
||||
|
||||
$inner_blocks = $this->get_inner_blocks_sorted_by_order();
|
||||
|
||||
if ( ! empty( $inner_blocks ) ) {
|
||||
$arr[] = array_map(
|
||||
function( BlockInterface $block ) {
|
||||
return $block->get_formatted_template();
|
||||
},
|
||||
$inner_blocks
|
||||
);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an inner block to this block.
|
||||
*
|
||||
* @param array $block_config The block data.
|
||||
*/
|
||||
public function &add_block( array $block_config ): BlockInterface {
|
||||
$block = new Block( $block_config, $this->get_root_template(), $this );
|
||||
return $this->add_inner_block( $block );
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
|
||||
/**
|
||||
* Trait for block containers.
|
||||
*/
|
||||
trait BlockContainerTrait {
|
||||
/**
|
||||
* The inner blocks.
|
||||
*
|
||||
* @var BlockInterface[]
|
||||
*/
|
||||
private $inner_blocks = [];
|
||||
|
||||
// phpcs doesn't take into account exceptions thrown by called methods.
|
||||
// phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
|
||||
/**
|
||||
* Add a block to the block container.
|
||||
*
|
||||
* @param BlockInterface $block The block.
|
||||
*
|
||||
* @throws \ValueError If the block configuration is invalid.
|
||||
* @throws \ValueError If a block with the specified ID already exists in the template.
|
||||
* @throws \UnexpectedValueException If the block container is not the parent of the block.
|
||||
*/
|
||||
protected function &add_inner_block( BlockInterface $block ): BlockInterface {
|
||||
if ( ! $block instanceof BlockInterface ) {
|
||||
throw new \UnexpectedValueException( 'The block must return an instance of BlockInterface.' );
|
||||
}
|
||||
|
||||
if ( $block->get_parent() !== $this ) {
|
||||
throw new \UnexpectedValueException( 'The block container is not the parent of the block.' );
|
||||
}
|
||||
|
||||
$root_template = $block->get_root_template();
|
||||
$root_template->cache_block( $block );
|
||||
$this->inner_blocks[] = &$block;
|
||||
return $block;
|
||||
}
|
||||
|
||||
// phpcs:enable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
||||
|
||||
/**
|
||||
* Get the inner blocks sorted by order.
|
||||
*/
|
||||
private function get_inner_blocks_sorted_by_order(): array {
|
||||
$sorted_inner_blocks = $this->inner_blocks;
|
||||
|
||||
usort(
|
||||
$sorted_inner_blocks,
|
||||
function( Block $a, Block $b ) {
|
||||
return $a->get_order() <=> $b->get_order();
|
||||
}
|
||||
);
|
||||
|
||||
return $sorted_inner_blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the inner blocks as a formatted template.
|
||||
*/
|
||||
public function get_formatted_template(): array {
|
||||
$arr = [
|
||||
$this->get_name(),
|
||||
$this->get_attributes(),
|
||||
];
|
||||
|
||||
$inner_blocks = $this->get_inner_blocks_sorted_by_order();
|
||||
|
||||
if ( ! empty( $inner_blocks ) ) {
|
||||
$arr[] = array_map(
|
||||
function( BlockInterface $block ) {
|
||||
return $block->get_formatted_template();
|
||||
},
|
||||
$inner_blocks
|
||||
);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplates;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\ContainerInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Block template class.
|
||||
*/
|
||||
class BlockTemplate extends AbstractBlockTemplate {
|
||||
/**
|
||||
* Get the template ID.
|
||||
*/
|
||||
public function get_id(): string {
|
||||
return 'woocommerce-block-template';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a block ID based on a base.
|
||||
*
|
||||
* @param array $block_config The block data.
|
||||
*/
|
||||
public function add_block( array $block_config ): BlockInterface {
|
||||
$block = new Block( $block_config, $this->get_root_template(), $this );
|
||||
return $this->add_inner_block( $block );
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ namespace Automattic\WooCommerce\Internal\Admin;
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\BlockTemplatesController;
|
||||
use Automattic\WooCommerce\Internal\Admin\ProductReviews\Reviews;
|
||||
use Automattic\WooCommerce\Internal\Admin\ProductReviews\ReviewsCommentsOverrides;
|
||||
use Automattic\WooCommerce\Internal\Admin\Settings;
|
||||
@@ -73,7 +72,6 @@ class Loader {
|
||||
|
||||
wc_get_container()->get( Reviews::class );
|
||||
wc_get_container()->get( ReviewsCommentsOverrides::class );
|
||||
wc_get_container()->get( BlockTemplatesController::class );
|
||||
|
||||
add_filter( 'admin_body_class', array( __CLASS__, 'add_admin_body_classes' ) );
|
||||
add_filter( 'admin_title', array( __CLASS__, 'update_admin_title' ) );
|
||||
|
||||
@@ -136,41 +136,34 @@ class MarketingSpecs {
|
||||
/**
|
||||
* Load knowledge base posts from WooCommerce.com
|
||||
*
|
||||
* @param string|null $term Term of posts to retrieve.
|
||||
* @param string|null $category Category of posts to retrieve.
|
||||
* @return array
|
||||
*/
|
||||
public function get_knowledge_base_posts( ?string $term ): array {
|
||||
$terms = array(
|
||||
'marketing' => array(
|
||||
'taxonomy' => 'category',
|
||||
'term_id' => 1744,
|
||||
'argument' => 'categories',
|
||||
),
|
||||
'coupons' => array(
|
||||
'taxonomy' => 'post_tag',
|
||||
'term_id' => 1377,
|
||||
'argument' => 'tags',
|
||||
),
|
||||
public function get_knowledge_base_posts( ?string $category ): array {
|
||||
$kb_transient = self::KNOWLEDGE_BASE_TRANSIENT;
|
||||
|
||||
$categories = array(
|
||||
'marketing' => 1744,
|
||||
'coupons' => 25202,
|
||||
);
|
||||
|
||||
// Default to the marketing category (if no term is set on the kb component).
|
||||
if ( empty( $term ) || ! array_key_exists( $term, $terms ) ) {
|
||||
$term = 'marketing';
|
||||
// Default to marketing category (if no category set on the kb component).
|
||||
if ( ! empty( $category ) && array_key_exists( $category, $categories ) ) {
|
||||
$category_id = $categories[ $category ];
|
||||
$kb_transient = $kb_transient . '_' . strtolower( $category );
|
||||
} else {
|
||||
$category_id = $categories['marketing'];
|
||||
}
|
||||
|
||||
$term_id = $terms[ $term ]['term_id'];
|
||||
$argument = $terms[ $term ]['argument'];
|
||||
$kb_transient = self::KNOWLEDGE_BASE_TRANSIENT . '_' . strtolower( $term );
|
||||
|
||||
$posts = get_transient( $kb_transient );
|
||||
|
||||
if ( false === $posts ) {
|
||||
$request_url = add_query_arg(
|
||||
array(
|
||||
$argument => $term_id,
|
||||
'page' => 1,
|
||||
'per_page' => 8,
|
||||
'_embed' => 1,
|
||||
'categories' => $category_id,
|
||||
'page' => 1,
|
||||
'per_page' => 8,
|
||||
'_embed' => 1,
|
||||
),
|
||||
'https://woocommerce.com/wp-json/wp/v2/posts?utm_medium=product'
|
||||
);
|
||||
|
||||
@@ -58,10 +58,10 @@ class COTRedirectionController {
|
||||
$params['_wpnonce'] = wp_create_nonce( 'bulk-posts' );
|
||||
}
|
||||
|
||||
// If an `id` array parameter is present, rename as `post`.
|
||||
if ( isset( $params['id'] ) && is_array( $params['id'] ) ) {
|
||||
$params['post'] = $params['id'];
|
||||
unset( $params['id'] );
|
||||
// If an `order` array parameter is present, rename as `post`.
|
||||
if ( isset( $params['order'] ) && is_array( $params['order'] ) ) {
|
||||
$params['post'] = $params['order'];
|
||||
unset( $params['order'] );
|
||||
}
|
||||
|
||||
$params['post_type'] = 'shop_order';
|
||||
|
||||
@@ -388,7 +388,6 @@ class Edit {
|
||||
<input type="hidden" id="hiddenaction" name="action" value="<?php echo esc_attr( $form_action ); ?>"/>
|
||||
<input type="hidden" id="original_order_status" name="original_order_status" value="<?php echo esc_attr( $this->order->get_status() ); ?>"/>
|
||||
<input type="hidden" id="referredby" name="referredby" value="<?php echo $referer ? esc_url( $referer ) : ''; ?>"/>
|
||||
<input type="hidden" id="post_ID" name="post_ID" value="<?php echo esc_attr( $this->order->get_id() ); ?>"/>
|
||||
<div id="poststuff">
|
||||
<div id="post-body"
|
||||
class="metabox-holder columns-<?php echo ( 1 === get_current_screen()->get_columns() ) ? '1' : '2'; ?>">
|
||||
|
||||
@@ -100,7 +100,7 @@ class EditLock {
|
||||
}
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! $order || ( ! current_user_can( get_post_type_object( $order->get_type() )->cap->edit_post, $order->get_id() ) && ! current_user_can( 'manage_woocommerce' ) ) ) {
|
||||
if ( ! current_user_can( get_post_type_object( $order->get_type() )->cap->edit_post, $order->get_id() ) && ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
@@ -867,7 +867,7 @@ class ListTable extends WP_List_Table {
|
||||
public function column_cb( $item ) {
|
||||
ob_start();
|
||||
?>
|
||||
<input id="cb-select-<?php echo esc_attr( $item->get_id() ); ?>" type="checkbox" name="id[]" value="<?php echo esc_attr( $item->get_id() ); ?>" />
|
||||
<input id="cb-select-<?php echo esc_attr( $item->get_id() ); ?>" type="checkbox" name="<?php echo esc_attr( $this->_args['singular'] ); ?>[]" value="<?php echo esc_attr( $item->get_id() ); ?>" />
|
||||
|
||||
<div class="locked-indicator">
|
||||
<span class="locked-indicator-icon" aria-hidden="true"></span>
|
||||
@@ -1197,7 +1197,7 @@ class ListTable extends WP_List_Table {
|
||||
|
||||
$action = 'delete';
|
||||
} else {
|
||||
$ids = isset( $_REQUEST['id'] ) ? array_reverse( array_map( 'absint', (array) $_REQUEST['id'] ) ) : array();
|
||||
$ids = isset( $_REQUEST['order'] ) ? array_reverse( array_map( 'absint', (array) $_REQUEST['order'] ) ) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1340,11 +1340,13 @@ class ListTable extends WP_List_Table {
|
||||
* @return int Number of orders that were trashed.
|
||||
*/
|
||||
private function do_delete( array $ids, bool $force_delete = false ): int {
|
||||
$orders_store = wc_get_container()->get( OrdersTableDataStore::class );
|
||||
$delete_args = $force_delete ? array( 'force_delete' => true ) : array();
|
||||
$changed = 0;
|
||||
|
||||
foreach ( $ids as $id ) {
|
||||
$order = wc_get_order( $id );
|
||||
$order->delete( $force_delete );
|
||||
$orders_store->delete( $order, $delete_args );
|
||||
$updated_order = wc_get_order( $id );
|
||||
|
||||
if ( ( $force_delete && false === $updated_order ) || ( ! $force_delete && $updated_order->get_status() === 'trash' ) ) {
|
||||
|
||||
@@ -290,6 +290,11 @@ class PageController {
|
||||
switch ( $this->current_action ) {
|
||||
case 'edit_order':
|
||||
case 'new_order':
|
||||
if ( ! isset( $this->order_edit_form ) ) {
|
||||
$this->order_edit_form = new Edit();
|
||||
$this->order_edit_form->setup( $this->order );
|
||||
}
|
||||
$this->order_edit_form->set_current_action( $this->current_action );
|
||||
$this->order_edit_form->display();
|
||||
break;
|
||||
case 'list_orders':
|
||||
@@ -335,22 +340,6 @@ class PageController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the order edit form for creating or editing an order.
|
||||
*
|
||||
* @see \Automattic\WooCommerce\Internal\Admin\Orders\Edit.
|
||||
* @since 8.1.0
|
||||
*/
|
||||
private function prepare_order_edit_form(): void {
|
||||
if ( ! $this->order || ! in_array( $this->current_action, array( 'new_order', 'edit_order' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->order_edit_form = $this->order_edit_form ?? new Edit();
|
||||
$this->order_edit_form->setup( $this->order );
|
||||
$this->order_edit_form->set_current_action( $this->current_action );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles initialization of the orders edit form.
|
||||
*
|
||||
@@ -362,8 +351,6 @@ class PageController {
|
||||
$this->verify_edit_permission();
|
||||
$this->handle_edit_lock();
|
||||
$theorder = $this->order;
|
||||
|
||||
$this->prepare_order_edit_form();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,8 +380,6 @@ class PageController {
|
||||
}
|
||||
|
||||
$theorder = $this->order;
|
||||
|
||||
$this->prepare_order_edit_form();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,7 +84,7 @@ class PostsRedirectionController {
|
||||
$new_url = add_query_arg(
|
||||
array(
|
||||
'action' => $action,
|
||||
'id' => $posts,
|
||||
'order' => $posts,
|
||||
'_wp_http_referer' => $this->page_controller->get_orders_url(),
|
||||
'_wpnonce' => wp_create_nonce( 'bulk-orders' ),
|
||||
),
|
||||
|
||||
@@ -400,16 +400,6 @@ class DefaultFreeExtensions {
|
||||
'value' => 'SE',
|
||||
'operation' => '=',
|
||||
),
|
||||
array(
|
||||
'type' => 'base_location_country',
|
||||
'value' => 'JP',
|
||||
'operation' => '=',
|
||||
),
|
||||
array(
|
||||
'type' => 'base_location_country',
|
||||
'value' => 'AE',
|
||||
'operation' => '=',
|
||||
),
|
||||
),
|
||||
),
|
||||
DefaultPaymentGateways::get_rules_for_cbd( false ),
|
||||
@@ -885,9 +875,9 @@ class DefaultFreeExtensions {
|
||||
'install_priority' => 3,
|
||||
),
|
||||
'jetpack' => array(
|
||||
'label' => __( 'Boost content creation with Jetpack AI Assistant', 'woocommerce' ),
|
||||
'label' => __( 'Enhance security with Jetpack', 'woocommerce' ),
|
||||
'image_url' => plugins_url( '/assets/images/core-profiler/logo-jetpack.svg', WC_PLUGIN_FILE ),
|
||||
'description' => __( 'Save time on content creation — unlock high-quality blog posts and pages using AI.', 'woocommerce' ),
|
||||
'description' => __( 'Get auto real-time backups, malware scans, and spam protection.', 'woocommerce' ),
|
||||
'learn_more_link' => 'https://woocommerce.com/products/jetpack',
|
||||
'install_priority' => 8,
|
||||
),
|
||||
|
||||
@@ -9,7 +9,6 @@ use Automattic\WooCommerce\Admin\API\Plugins;
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
|
||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||
use Automattic\WooCommerce\Internal\Admin\WCPayPromotion\Init as WCPayPromotionInit;
|
||||
use Automattic\WooCommerce\Utilities\FeaturesUtil;
|
||||
use WC_Marketplace_Suggestions;
|
||||
|
||||
@@ -237,8 +236,6 @@ class Settings {
|
||||
|
||||
$settings['features'] = $this->get_features();
|
||||
|
||||
$settings['isWooPayEligible'] = WCPayPromotionInit::is_woopay_eligible();
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,15 +141,6 @@ class Init {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get merchant WooPay eligibility.
|
||||
*/
|
||||
public static function is_woopay_eligible() {
|
||||
$wcpay_promotion = self::get_wc_pay_promotion_spec();
|
||||
|
||||
return $wcpay_promotion && 'woocommerce_payments:woopay' === $wcpay_promotion->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specs transient.
|
||||
*/
|
||||
|
||||
@@ -12,8 +12,7 @@ use Automattic\WooCommerce\Admin\PageController;
|
||||
* @package Automattic\WooCommerce\Admin\Features
|
||||
*/
|
||||
class WcPayWelcomePage {
|
||||
const CACHE_TRANSIENT_NAME = 'wcpay_welcome_page_incentive';
|
||||
const HAD_WCPAY_OPTION_NAME = 'wcpay_was_in_use';
|
||||
const TRANSIENT_NAME = 'wcpay_welcome_page_incentive';
|
||||
|
||||
/**
|
||||
* Plugin instance.
|
||||
@@ -53,11 +52,6 @@ class WcPayWelcomePage {
|
||||
* @return boolean
|
||||
*/
|
||||
public function must_be_visible(): bool {
|
||||
// The WooPayments plugin must not be active.
|
||||
if ( $this->is_wcpay_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suggestions not disabled via a setting.
|
||||
if ( get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) === 'no' ) {
|
||||
return false;
|
||||
@@ -74,7 +68,12 @@ class WcPayWelcomePage {
|
||||
return false;
|
||||
}
|
||||
|
||||
// An incentive must be available.
|
||||
// The WooPayments plugin must not be active.
|
||||
if ( $this->is_wcpay_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Incentive is available.
|
||||
if ( empty( $this->get_incentive() ) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -134,17 +133,11 @@ class WcPayWelcomePage {
|
||||
}
|
||||
|
||||
// Add badge.
|
||||
$badge = ' <span class="wcpay-menu-badge awaiting-mod count-1"><span class="plugin-count">1</span></span>';
|
||||
foreach ( $menu as $index => $menu_item ) {
|
||||
// Only add the badge markup if not already present and the menu item is the WooPayments menu item.
|
||||
if ( false === strpos( $menu_item[0], $badge )
|
||||
&& ( 'wc-admin&path=/wc-pay-welcome-page' === $menu_item[2]
|
||||
|| 'admin.php?page=wc-admin&path=/wc-pay-welcome-page' === $menu_item[2] )
|
||||
) {
|
||||
$menu[ $index ][0] .= $badge; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
|
||||
// One menu item with a badge is more than enough.
|
||||
break;
|
||||
if ( 'wc-admin&path=/wc-pay-welcome-page' === $menu_item[2]
|
||||
|| 'admin.php?page=wc-admin&path=/wc-pay-welcome-page' === $menu_item[2] ) {
|
||||
//phpcs:ignore
|
||||
$menu[ $index ][0] .= ' <span class="wcpay-menu-badge awaiting-mod count-1"><span class="plugin-count">1</span></span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,8 +154,8 @@ class WcPayWelcomePage {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
// Return early if the incentive must not be visible.
|
||||
if ( ! $this->must_be_visible() ) {
|
||||
// Return early if there is no eligible incentive.
|
||||
if ( empty( $this->get_incentive() ) ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
@@ -178,8 +171,8 @@ class WcPayWelcomePage {
|
||||
* @return array
|
||||
*/
|
||||
public function allowed_promo_notes( $promo_notes = [] ): array {
|
||||
// Return early if the incentive must not be visible.
|
||||
if ( ! $this->must_be_visible() ) {
|
||||
// Return early if there is no eligible incentive.
|
||||
if ( empty( $this->get_incentive() ) ) {
|
||||
return $promo_notes;
|
||||
}
|
||||
|
||||
@@ -190,34 +183,20 @@ class WcPayWelcomePage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the WooPayments payment gateway is active and set up or was at some point,
|
||||
* Check if the WooPayments payment gateway is active and set up,
|
||||
* or there are orders processed with it, at some moment.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function has_wcpay(): bool {
|
||||
// First, get the stored value, if it exists.
|
||||
// This way we avoid costly DB queries and API calls.
|
||||
// Basically, we only want to know if WooPayments was in use in the past.
|
||||
// Since the past can't be changed, neither can this value.
|
||||
$had_wcpay = get_option( self::HAD_WCPAY_OPTION_NAME );
|
||||
if ( false !== $had_wcpay ) {
|
||||
return $had_wcpay === 'yes';
|
||||
}
|
||||
|
||||
// We need to determine the value.
|
||||
// Start with the assumption that the store didn't have WooPayments in use.
|
||||
$had_wcpay = false;
|
||||
|
||||
// We consider the store to have WooPayments if there is meaningful account data in the WooPayments account cache.
|
||||
// This implies that WooPayments was active at some point and that it was connected.
|
||||
// If WooPayments is active right now, we will not get to this point since the plugin is active check is done first.
|
||||
// This implies that WooPayments is or was active at some point and that it was connected.
|
||||
if ( $this->has_wcpay_account_data() ) {
|
||||
$had_wcpay = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is at least one order processed with WooPayments, we consider the store to have WooPayments.
|
||||
if ( false === $had_wcpay && ! empty(
|
||||
if ( ! empty(
|
||||
wc_get_orders(
|
||||
[
|
||||
'payment_method' => 'woocommerce_payments',
|
||||
@@ -226,13 +205,10 @@ class WcPayWelcomePage {
|
||||
]
|
||||
)
|
||||
) ) {
|
||||
$had_wcpay = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Store the value for future use.
|
||||
update_option( self::HAD_WCPAY_OPTION_NAME, $had_wcpay ? 'yes' : 'no' );
|
||||
|
||||
return $had_wcpay;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,21 +240,14 @@ class WcPayWelcomePage {
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_incentive_dismissed(): bool {
|
||||
$dismissed_incentives = get_option( 'wcpay_welcome_page_incentives_dismissed', [] );
|
||||
|
||||
// If there are no dismissed incentives, return early.
|
||||
if ( empty( $dismissed_incentives ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return early if there is no eligible incentive.
|
||||
$incentive = $this->get_incentive();
|
||||
if ( empty( $incentive ) ) {
|
||||
if ( empty( $this->get_incentive() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Search the incentive ID in the dismissed incentives list.
|
||||
if ( in_array( $incentive['id'], $dismissed_incentives, true ) ) {
|
||||
$dismissed_incentives = get_option( 'wcpay_welcome_page_incentives_dismissed', [] );
|
||||
|
||||
if ( in_array( $this->get_incentive()['id'], $dismissed_incentives, true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -296,19 +265,6 @@ class WcPayWelcomePage {
|
||||
return $this->incentive;
|
||||
}
|
||||
|
||||
// Get the cached data.
|
||||
$cache = get_transient( self::CACHE_TRANSIENT_NAME );
|
||||
|
||||
// If the cached data is not expired and it's a WP_Error,
|
||||
// it means there was an API error previously and we should not retry just yet.
|
||||
if ( is_wp_error( $cache ) ) {
|
||||
// Initialize the in-memory cache and return it.
|
||||
$this->incentive = [];
|
||||
|
||||
return $this->incentive;
|
||||
}
|
||||
|
||||
// Gather the store context data.
|
||||
$store_context = [
|
||||
// Store ISO-2 country code, e.g. `US`.
|
||||
'country' => WC()->countries->get_base_country(),
|
||||
@@ -337,16 +293,25 @@ class WcPayWelcomePage {
|
||||
|
||||
// Use the transient cached incentive if it exists, it is not expired,
|
||||
// and the store context hasn't changed since we last requested from the WooPayments API (based on context hash).
|
||||
if ( false !== $cache
|
||||
&& ! empty( $cache['context_hash'] ) && is_string( $cache['context_hash'] )
|
||||
&& hash_equals( $store_context_hash, $cache['context_hash'] ) ) {
|
||||
$transient_cache = get_transient( self::TRANSIENT_NAME );
|
||||
if ( false !== $transient_cache ) {
|
||||
if ( is_null( $transient_cache ) ) {
|
||||
// This means there was an error and we shouldn't retry just yet.
|
||||
// Initialize the in-memory cache.
|
||||
$this->incentive = [];
|
||||
} elseif ( ! empty( $transient_cache['context_hash'] ) && is_string( $transient_cache['context_hash'] )
|
||||
&& hash_equals( $store_context_hash, $transient_cache['context_hash'] ) ) {
|
||||
|
||||
// We have a store context hash and it matches with the current context one.
|
||||
// We can use the cached incentive data.
|
||||
// Store the incentive in the in-memory cache and return it.
|
||||
$this->incentive = $cache['incentive'] ?? [];
|
||||
// We have a store context hash and it matches with the current context one.
|
||||
// We can use the cached incentive data.
|
||||
// Store the incentive in the in-memory cache.
|
||||
$this->incentive = $transient_cache['incentive'] ?? [];
|
||||
}
|
||||
|
||||
return $this->incentive;
|
||||
// If the in-memory cache has been set, return it.
|
||||
if ( isset( $this->incentive ) ) {
|
||||
return $this->incentive;
|
||||
}
|
||||
}
|
||||
|
||||
// By this point, we have an expired transient or the store context has changed.
|
||||
@@ -358,22 +323,16 @@ class WcPayWelcomePage {
|
||||
|
||||
$response = wp_remote_get(
|
||||
$url,
|
||||
[
|
||||
array(
|
||||
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
// Return early if there is an error, waiting 6 hours before the next attempt.
|
||||
if ( is_wp_error( $response ) ) {
|
||||
// Store a trimmed down, lightweight error.
|
||||
$error = new \WP_Error(
|
||||
$response->get_error_code(),
|
||||
$response->get_error_message(),
|
||||
wp_remote_retrieve_response_code( $response )
|
||||
);
|
||||
// Store the error in the transient so we know this is due to an API error.
|
||||
set_transient( self::CACHE_TRANSIENT_NAME, $error, HOUR_IN_SECONDS * 6 );
|
||||
// Initialize the in-memory cache and return it.
|
||||
// Store a null value in the transient so we know this is due to an API error.
|
||||
set_transient( self::TRANSIENT_NAME, null, HOUR_IN_SECONDS * 6 );
|
||||
// Initialize the in-memory cache.
|
||||
$this->incentive = [];
|
||||
|
||||
return $this->incentive;
|
||||
@@ -403,21 +362,19 @@ class WcPayWelcomePage {
|
||||
// Skip transient cache if `cache-for` header equals zero.
|
||||
if ( '0' === $cache_for ) {
|
||||
// If we have a transient cache that is not expired, delete it so there are no leftovers.
|
||||
if ( false !== $cache ) {
|
||||
delete_transient( self::CACHE_TRANSIENT_NAME );
|
||||
if ( false !== $transient_cache ) {
|
||||
delete_transient( self::TRANSIENT_NAME );
|
||||
}
|
||||
|
||||
return $this->incentive;
|
||||
}
|
||||
|
||||
// Store incentive in transient cache (together with the context hash) for the given number of seconds
|
||||
// or 1 day in seconds. Also attach a timestamp to the transient data so we know when we last fetched.
|
||||
// Store incentive in transient cache (together with the context hash) for the given number of seconds or 24h.
|
||||
set_transient(
|
||||
self::CACHE_TRANSIENT_NAME,
|
||||
self::TRANSIENT_NAME,
|
||||
[
|
||||
'incentive' => $this->incentive,
|
||||
'context_hash' => $store_context_hash,
|
||||
'timestamp' => time(),
|
||||
],
|
||||
! empty( $cache_for ) ? (int) $cache_for : DAY_IN_SECONDS
|
||||
);
|
||||
|
||||
@@ -194,41 +194,4 @@ abstract class CustomMetaDataStore {
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves metadata by meta key.
|
||||
*
|
||||
* @param \WC_Abstract_Order $object Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
*
|
||||
* @return \stdClass|bool Metadata object or FALSE if not found.
|
||||
*/
|
||||
public function get_metadata_by_key( &$object, string $meta_key ) {
|
||||
global $wpdb;
|
||||
|
||||
$db_info = $this->get_db_info();
|
||||
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$meta = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT {$db_info['meta_id_field']}, meta_key, meta_value, {$db_info['object_id_field']} FROM {$db_info['table']} WHERE meta_key = %s AND {$db_info['object_id_field']} = %d",
|
||||
$meta_key,
|
||||
$object->get_id(),
|
||||
)
|
||||
);
|
||||
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
|
||||
if ( empty( $meta ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $meta as $row ) {
|
||||
if ( isset( $row->meta_value ) ) {
|
||||
$row->meta_value = maybe_unserialize( $row->meta_value );
|
||||
}
|
||||
}
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,19 +23,12 @@ defined( 'ABSPATH' ) || exit;
|
||||
class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements \WC_Object_Data_Store_Interface, \WC_Order_Data_Store_Interface {
|
||||
|
||||
/**
|
||||
* Order IDs for which we are checking sync on read in the current request. In WooCommerce, using wc_get_order is a very common pattern, to avoid performance issues, we only sync on read once per request per order. This works because we consider out of sync orders to be an anomaly, so we don't recommend running HPOS with incompatible plugins.
|
||||
* Order IDs for which we are checking read on sync in the current request.
|
||||
*
|
||||
* @var array.
|
||||
*/
|
||||
private static $reading_order_ids = array();
|
||||
|
||||
/**
|
||||
* Keep track of order IDs that are actively being backfilled. We use this to prevent further read on sync from add_|update_|delete_postmeta etc hooks. If we allow this, then we would end up syncing the same order multiple times as it is being backfilled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $backfilling_order_ids = array();
|
||||
|
||||
/**
|
||||
* Data stored in meta keys, but not considered "meta" for an order.
|
||||
*
|
||||
@@ -569,18 +562,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements
|
||||
return;
|
||||
}
|
||||
|
||||
self::$backfilling_order_ids[] = $order->get_id();
|
||||
$this->update_order_meta_from_object( $order );
|
||||
$order_class = get_class( $order );
|
||||
$post_order = new $order_class();
|
||||
$post_order->set_id( $order->get_id() );
|
||||
$cpt_data_store->read( $post_order );
|
||||
|
||||
// This compares the order data to the post data and set changes array for props that are changed.
|
||||
$post_order->set_props( $order->get_data() );
|
||||
|
||||
$cpt_data_store->update_order_from_object( $post_order );
|
||||
|
||||
$cpt_data_store->update_order_from_object( $order );
|
||||
foreach ( $cpt_data_store->get_internal_data_store_key_getters() as $key => $getter_name ) {
|
||||
if (
|
||||
is_callable( array( $cpt_data_store, "set_$getter_name" ) ) &&
|
||||
@@ -598,7 +580,6 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements
|
||||
);
|
||||
}
|
||||
}
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $order->get_id() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -781,47 +762,6 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements
|
||||
$this->set_stock_reduced( $order, $set );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token ids for an order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return array
|
||||
*/
|
||||
public function get_payment_token_ids( $order ) {
|
||||
/**
|
||||
* We don't store _payment_tokens in props to preserve backward compatibility. In CPT data store, `_payment_tokens` is always fetched directly from DB instead of from prop.
|
||||
*/
|
||||
$payment_tokens = $this->data_store_meta->get_metadata_by_key( $order, '_payment_tokens' );
|
||||
if ( $payment_tokens ) {
|
||||
$payment_tokens = $payment_tokens[0]->meta_value;
|
||||
}
|
||||
if ( ! $payment_tokens && version_compare( $order->get_version(), '8.0.0', '<' ) ) {
|
||||
// Before 8.0 we were incorrectly storing payment_tokens in the order meta. So we need to check there too.
|
||||
$payment_tokens = get_post_meta( $order->get_id(), '_payment_tokens', true );
|
||||
}
|
||||
return array_filter( (array) $payment_tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update token ids for an order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $token_ids Payment token ids.
|
||||
*/
|
||||
public function update_payment_token_ids( $order, $token_ids ) {
|
||||
$meta = new \WC_Meta_Data();
|
||||
$meta->key = '_payment_tokens';
|
||||
$meta->value = $token_ids;
|
||||
$existing_meta = $this->data_store_meta->get_metadata_by_key( $order, '_payment_tokens' );
|
||||
if ( $existing_meta ) {
|
||||
$existing_meta = $existing_meta[0];
|
||||
$meta->id = $existing_meta->id;
|
||||
$this->data_store_meta->update_meta( $order, $meta );
|
||||
} else {
|
||||
$this->data_store_meta->add_meta( $order, $meta );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get amount already refunded.
|
||||
*
|
||||
@@ -1111,7 +1051,7 @@ WHERE
|
||||
}
|
||||
|
||||
$data_sync_enabled = $data_synchronizer->data_sync_is_enabled();
|
||||
$load_posts_for = array_diff( $order_ids, array_merge( self::$reading_order_ids, self::$backfilling_order_ids ) );
|
||||
$load_posts_for = array_diff( $order_ids, self::$reading_order_ids );
|
||||
$post_orders = $data_sync_enabled ? $this->get_post_orders_for_ids( array_intersect_key( $orders, array_flip( $load_posts_for ) ) ) : array();
|
||||
|
||||
foreach ( $data as $order_data ) {
|
||||
@@ -1716,11 +1656,9 @@ FROM $order_meta_table
|
||||
if ( 'create' === $context ) {
|
||||
$post_id = wp_insert_post(
|
||||
array(
|
||||
'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE,
|
||||
'post_status' => 'draft',
|
||||
'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0,
|
||||
'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
|
||||
'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
|
||||
'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE,
|
||||
'post_status' => 'draft',
|
||||
'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0,
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1858,8 +1796,8 @@ FROM $order_meta_table
|
||||
if ( $row ) {
|
||||
$result[] = array(
|
||||
'table' => self::get_orders_table_name(),
|
||||
'data' => array_merge( $row['data'], array( 'id' => $order->get_id(), 'type' => $order->get_type() ) ),
|
||||
'format' => array_merge( $row['format'], array( 'id' => '%d', 'type' => '%s' ) ),
|
||||
'data' => array_merge( $row['data'], array( 'id' => $order->get_id() ) ),
|
||||
'format' => array_merge( $row['format'], array( 'id' => '%d' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1928,6 +1866,8 @@ FROM $order_meta_table
|
||||
protected function get_db_row_from_order( $order, $column_mapping, $only_changes = false ) {
|
||||
$changes = $only_changes ? $order->get_changes() : array_merge( $order->get_data(), $order->get_changes() );
|
||||
|
||||
$changes['type'] = $order->get_type();
|
||||
|
||||
// Make sure 'status' is correctly prefixed.
|
||||
if ( array_key_exists( 'status', $column_mapping ) && array_key_exists( 'status', $changes ) ) {
|
||||
$changes['status'] = $this->get_post_status( $order );
|
||||
@@ -2161,6 +2101,16 @@ FROM $order_meta_table
|
||||
'_wp_trash_meta_time' => time(),
|
||||
);
|
||||
|
||||
foreach ( $trash_metadata as $meta_key => $meta_value ) {
|
||||
$this->add_meta(
|
||||
$order,
|
||||
(object) array(
|
||||
'key' => $meta_key,
|
||||
'value' => $meta_value,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$wpdb->update(
|
||||
self::get_orders_table_name(),
|
||||
array(
|
||||
@@ -2174,16 +2124,6 @@ FROM $order_meta_table
|
||||
|
||||
$order->set_status( 'trash' );
|
||||
|
||||
foreach ( $trash_metadata as $meta_key => $meta_value ) {
|
||||
$this->add_meta(
|
||||
$order,
|
||||
(object) array(
|
||||
'key' => $meta_key,
|
||||
'value' => $meta_value,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$data_synchronizer = wc_get_container()->get( DataSynchronizer::class );
|
||||
if ( $data_synchronizer->data_sync_is_enabled() ) {
|
||||
wp_trash_post( $order->get_id() );
|
||||
@@ -2315,11 +2255,6 @@ FROM $order_meta_table
|
||||
|
||||
$this->persist_save( $order );
|
||||
|
||||
// Do not fire 'woocommerce_new_order' for draft statuses for backwards compatibility.
|
||||
if ( 'auto-draft' === $order->get_status( 'edit') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when a new order is created.
|
||||
*
|
||||
@@ -2352,22 +2287,15 @@ FROM $order_meta_table
|
||||
$order->set_date_created( time() );
|
||||
}
|
||||
|
||||
if ( ! $order->get_date_modified( 'edit' ) ) {
|
||||
$order->set_date_modified( current_time( 'mysql' ) );
|
||||
}
|
||||
$this->update_order_meta( $order );
|
||||
|
||||
$this->persist_order_to_db( $order, $force_all_fields );
|
||||
|
||||
$this->update_order_meta( $order );
|
||||
|
||||
$order->save_meta_data();
|
||||
$order->apply_changes();
|
||||
|
||||
if ( $backfill ) {
|
||||
self::$backfilling_order_ids[] = $order->get_id();
|
||||
$r_order = wc_get_order( $order->get_id() ); // Refresh order to account for DB changes from post hooks.
|
||||
$this->maybe_backfill_post_record( $r_order );
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $order->get_id() ) );
|
||||
$this->maybe_backfill_post_record( $order );
|
||||
}
|
||||
$this->clear_caches( $order );
|
||||
}
|
||||
@@ -2378,9 +2306,6 @@ FROM $order_meta_table
|
||||
* @param \WC_Order $order Order object.
|
||||
*/
|
||||
public function update( &$order ) {
|
||||
$previous_status = ArrayUtil::get_value_or_default( $order->get_data(), 'status' );
|
||||
$changes = $order->get_changes();
|
||||
|
||||
// Before updating, ensure date paid is set if missing.
|
||||
if (
|
||||
! $order->get_date_paid( 'edit' )
|
||||
@@ -2414,18 +2339,6 @@ FROM $order_meta_table
|
||||
$order->apply_changes();
|
||||
$this->clear_caches( $order );
|
||||
|
||||
// For backwards compatibility, moving an auto-draft order to a valid status triggers the 'woocommerce_new_order' hook.
|
||||
if ( ! empty( $changes['status'] ) && 'auto-draft' === $previous_status ) {
|
||||
do_action( 'woocommerce_new_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
|
||||
return;
|
||||
}
|
||||
|
||||
// For backwards compat with CPT, trashing/untrashing and changing previously datastore-level props does not trigger the update hook.
|
||||
if ( ( ! empty( $changes['status'] ) && in_array( 'trash', array( $changes['status'], $previous_status ), true ) )
|
||||
|| ! array_diff_key( $changes, array_flip( $this->get_post_data_store_for_backfill()->get_internal_data_store_key_getters() ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_update_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
|
||||
}
|
||||
|
||||
@@ -2457,33 +2370,19 @@ FROM $order_meta_table
|
||||
$changes = $order->get_changes();
|
||||
|
||||
if ( ! isset( $changes['date_modified'] ) ) {
|
||||
$order->set_date_modified( current_time( 'mysql' ) );
|
||||
$order->set_date_modified( time() );
|
||||
}
|
||||
|
||||
$this->persist_order_to_db( $order );
|
||||
$order->save_meta_data();
|
||||
|
||||
if ( $backfill ) {
|
||||
$this->clear_caches( $order );
|
||||
self::$backfilling_order_ids[] = $order->get_id();
|
||||
$r_order = wc_get_order( $order->get_id() ); // Refresh order to account for DB changes from post hooks.
|
||||
$this->maybe_backfill_post_record( $r_order );
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $order->get_id() ) );
|
||||
$this->maybe_backfill_post_record( $order );
|
||||
}
|
||||
|
||||
return $changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check whether to backfill post record.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function should_backfill_post_record() {
|
||||
$data_sync = wc_get_container()->get( DataSynchronizer::class );
|
||||
return $data_sync->data_sync_is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to decide whether to backfill post record.
|
||||
*
|
||||
@@ -2492,7 +2391,8 @@ FROM $order_meta_table
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_backfill_post_record( $order ) {
|
||||
if ( $this->should_backfill_post_record() ) {
|
||||
$data_sync = wc_get_container()->get( DataSynchronizer::class );
|
||||
if ( $data_sync->data_sync_is_enabled() ) {
|
||||
$this->backfill_post_record( $order );
|
||||
}
|
||||
}
|
||||
@@ -2684,10 +2584,6 @@ FROM $order_meta_table
|
||||
$operational_data_table_name = $this->get_operational_data_table_name();
|
||||
$meta_table = $this->get_meta_table_name();
|
||||
|
||||
$max_index_length = $this->database_util->get_max_index_length();
|
||||
$composite_meta_value_index_length = max( $max_index_length - 8 - 100 - 1, 20 ); // 8 for order_id, 100 for meta_key, 10 minimum for meta_value.
|
||||
$composite_customer_id_email_length = max( $max_index_length - 20, 20 ); // 8 for customer_id, 20 minimum for email.
|
||||
|
||||
$sql = "
|
||||
CREATE TABLE $orders_table_name (
|
||||
id bigint(20) unsigned,
|
||||
@@ -2710,9 +2606,9 @@ CREATE TABLE $orders_table_name (
|
||||
PRIMARY KEY (id),
|
||||
KEY status (status),
|
||||
KEY date_created (date_created_gmt),
|
||||
KEY customer_id_billing_email (customer_id, billing_email({$composite_customer_id_email_length})),
|
||||
KEY billing_email (billing_email($max_index_length)),
|
||||
KEY type_status_date (type, status, date_created_gmt),
|
||||
KEY customer_id_billing_email (customer_id, billing_email),
|
||||
KEY billing_email (billing_email),
|
||||
KEY type_status (type, status),
|
||||
KEY parent_order_id (parent_order_id),
|
||||
KEY date_updated (date_updated_gmt)
|
||||
) $collate;
|
||||
@@ -2733,7 +2629,7 @@ CREATE TABLE $addresses_table_name (
|
||||
phone varchar(100) null,
|
||||
KEY order_id (order_id),
|
||||
UNIQUE KEY address_type_order_id (address_type, order_id),
|
||||
KEY email (email($max_index_length)),
|
||||
KEY email (email),
|
||||
KEY phone (phone)
|
||||
) $collate;
|
||||
CREATE TABLE $operational_data_table_name (
|
||||
@@ -2750,10 +2646,10 @@ CREATE TABLE $operational_data_table_name (
|
||||
order_stock_reduced tinyint(1) NULL,
|
||||
date_paid_gmt datetime NULL,
|
||||
date_completed_gmt datetime NULL,
|
||||
shipping_tax_amount decimal(26,8) NULL,
|
||||
shipping_total_amount decimal(26,8) NULL,
|
||||
discount_tax_amount decimal(26,8) NULL,
|
||||
discount_total_amount decimal(26,8) NULL,
|
||||
shipping_tax_amount decimal(26, 8) NULL,
|
||||
shipping_total_amount decimal(26, 8) NULL,
|
||||
discount_tax_amount decimal(26, 8) NULL,
|
||||
discount_total_amount decimal(26, 8) NULL,
|
||||
recorded_sales tinyint(1) NULL,
|
||||
UNIQUE KEY order_id (order_id),
|
||||
KEY order_key (order_key)
|
||||
@@ -2763,8 +2659,8 @@ CREATE TABLE $meta_table (
|
||||
order_id bigint(20) unsigned null,
|
||||
meta_key varchar(255),
|
||||
meta_value text null,
|
||||
KEY meta_key_value (meta_key(100), meta_value($composite_meta_value_index_length)),
|
||||
KEY order_id_meta_key_meta_value (order_id, meta_key(100), meta_value($composite_meta_value_index_length))
|
||||
KEY meta_key_value (meta_key, meta_value(100)),
|
||||
KEY order_id_meta_key_meta_value (order_id, meta_key, meta_value(100))
|
||||
) $collate;
|
||||
";
|
||||
|
||||
@@ -2785,28 +2681,16 @@ CREATE TABLE $meta_table (
|
||||
/**
|
||||
* Deletes meta based on meta ID.
|
||||
*
|
||||
* @param WC_Data $object WC_Data object.
|
||||
* @param \stdClass $meta (containing at least ->id).
|
||||
* @param WC_Data $object WC_Data object.
|
||||
* @param stdClass $meta (containing at least ->id).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_meta( &$object, $meta ) {
|
||||
if ( $this->should_backfill_post_record() && isset( $meta->id ) ) {
|
||||
// Let's get the actual meta key before its deleted for backfilling. We cannot delete just by ID because meta IDs are different in HPOS and posts tables.
|
||||
$db_meta = $this->data_store_meta->get_metadata_by_id( $meta->id );
|
||||
if ( $db_meta ) {
|
||||
$meta->key = $db_meta->meta_key;
|
||||
$meta->value = $db_meta->meta_value;
|
||||
}
|
||||
}
|
||||
$delete_meta = $this->data_store_meta->delete_meta( $object, $meta );
|
||||
|
||||
$delete_meta = $this->data_store_meta->delete_meta( $object, $meta );
|
||||
$changes_applied = $this->after_meta_change( $object, $meta );
|
||||
|
||||
if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() && isset( $meta->key ) ) {
|
||||
self::$backfilling_order_ids[] = $object->get_id();
|
||||
delete_post_meta( $object->get_id(), $meta->key, $meta->value );
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) );
|
||||
if ( $object instanceof WC_Abstract_Order ) {
|
||||
$this->maybe_backfill_post_record( $object );
|
||||
}
|
||||
|
||||
return $delete_meta;
|
||||
@@ -2815,20 +2699,16 @@ CREATE TABLE $meta_table (
|
||||
/**
|
||||
* Add new piece of meta.
|
||||
*
|
||||
* @param WC_Data $object WC_Data object.
|
||||
* @param \stdClass $meta (containing ->key and ->value).
|
||||
* @param WC_Data $object WC_Data object.
|
||||
* @param stdClass $meta (containing ->key and ->value).
|
||||
*
|
||||
* @return int|bool meta ID or false on failure
|
||||
*/
|
||||
public function add_meta( &$object, $meta ) {
|
||||
$add_meta = $this->data_store_meta->add_meta( $object, $meta );
|
||||
$meta->id = $add_meta;
|
||||
$changes_applied = $this->after_meta_change( $object, $meta );
|
||||
$add_meta = $this->data_store_meta->add_meta( $object, $meta );
|
||||
|
||||
if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() ) {
|
||||
self::$backfilling_order_ids[] = $object->get_id();
|
||||
add_post_meta( $object->get_id(), $meta->key, $meta->value );
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) );
|
||||
if ( $object instanceof WC_Abstract_Order ) {
|
||||
$this->maybe_backfill_post_record( $object );
|
||||
}
|
||||
|
||||
return $add_meta;
|
||||
@@ -2837,58 +2717,18 @@ CREATE TABLE $meta_table (
|
||||
/**
|
||||
* Update meta.
|
||||
*
|
||||
* @param WC_Data $object WC_Data object.
|
||||
* @param \stdClass $meta (containing ->id, ->key and ->value).
|
||||
* @param WC_Data $object WC_Data object.
|
||||
* @param stdClass $meta (containing ->id, ->key and ->value).
|
||||
*
|
||||
* @return
|
||||
* @return bool
|
||||
*/
|
||||
public function update_meta( &$object, $meta ) {
|
||||
$update_meta = $this->data_store_meta->update_meta( $object, $meta );
|
||||
$changes_applied = $this->after_meta_change( $object, $meta );
|
||||
$update_meta = $this->data_store_meta->update_meta( $object, $meta );
|
||||
|
||||
if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() ) {
|
||||
self::$backfilling_order_ids[] = $object->get_id();
|
||||
update_post_meta( $object->get_id(), $meta->key, $meta->value );
|
||||
self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) );
|
||||
if ( $object instanceof WC_Abstract_Order ) {
|
||||
$this->maybe_backfill_post_record( $object );
|
||||
}
|
||||
|
||||
return $update_meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform after meta change operations, including updating the date_modified field, clearing caches and applying changes.
|
||||
*
|
||||
* @param WC_Abstract_Order $order Order object.
|
||||
* @param \WC_Meta_Data $meta Metadata object.
|
||||
*
|
||||
* @return bool True if changes were applied, false otherwise.
|
||||
*/
|
||||
protected function after_meta_change( &$order, $meta ) {
|
||||
method_exists( $meta, 'apply_changes' ) && $meta->apply_changes();
|
||||
$this->clear_caches( $order );
|
||||
|
||||
// Prevent this happening multiple time in same request.
|
||||
if ( $this->should_save_after_meta_change( $order ) ) {
|
||||
$order->set_date_modified( current_time( 'mysql' ) );
|
||||
$order->save();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to check whether the modified date needs to be updated after a meta save.
|
||||
*
|
||||
* This method prevents order->save() call multiple times in the same request after any meta update by checking if:
|
||||
* 1. Order modified date is already the current date, no updates needed in this case.
|
||||
* 2. If there are changes already queued for order object, then we don't need to update the modified date as it will be updated ina subsequent save() call.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
*
|
||||
* @return bool Whether the modified date needs to be updated.
|
||||
*/
|
||||
private function should_save_after_meta_change( $order ) {
|
||||
$current_date_time = new \WC_DateTime( current_time( 'mysql', 1 ), new \DateTimeZone( 'GMT' ) );
|
||||
return $order->get_date_modified() < $current_date_time && empty( $order->get_changes() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
|
||||
|
||||
use WC_Meta_Data;
|
||||
|
||||
/**
|
||||
* Class OrdersTableRefundDataStore.
|
||||
*/
|
||||
@@ -161,17 +159,8 @@ class OrdersTableRefundDataStore extends OrdersTableDataStore {
|
||||
|
||||
$props_to_update = $this->get_props_to_update( $refund, $meta_key_to_props );
|
||||
foreach ( $props_to_update as $meta_key => $prop ) {
|
||||
$meta_object = new WC_Meta_Data();
|
||||
$meta_object->key = $meta_key;
|
||||
$meta_object->value = $refund->{"get_$prop"}( 'edit' );
|
||||
$existing_meta = $this->data_store_meta->get_metadata_by_key( $refund, $meta_key );
|
||||
if ( $existing_meta ) {
|
||||
$existing_meta = $existing_meta[0];
|
||||
$meta_object->id = $existing_meta->id;
|
||||
$this->update_meta( $refund, $meta_object );
|
||||
} else {
|
||||
$this->add_meta( $refund, $meta_object );
|
||||
}
|
||||
$value = $refund->{"get_$prop"}( 'edit' );
|
||||
$refund->update_meta_data( $meta_key, $value );
|
||||
$updated_props[] = $prop;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* BlockTemplatesServiceProvider class file.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\BlockTemplatesController;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\BlockTemplateRegistry;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\TemplateTransformer;
|
||||
|
||||
/**
|
||||
* Service provider for the block templates controller classes in the Automattic\WooCommerce\Internal\BlockTemplateRegistry namespace.
|
||||
*/
|
||||
class BlockTemplatesServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The classes/interfaces that are serviced by this service provider.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = array(
|
||||
BlockTemplateRegistry::class,
|
||||
BlockTemplatesController::class,
|
||||
TemplateTransformer::class,
|
||||
);
|
||||
|
||||
/**
|
||||
* Register the classes.
|
||||
*/
|
||||
public function register() {
|
||||
$this->share( TemplateTransformer::class );
|
||||
$this->share( BlockTemplateRegistry::class );
|
||||
$this->share( BlockTemplatesController::class )->addArguments(
|
||||
array(
|
||||
BlockTemplateRegistry::class,
|
||||
TemplateTransformer::class,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -233,62 +233,23 @@ class DatabaseUtil {
|
||||
*/
|
||||
public function insert_on_duplicate_key_update( $table_name, $data, $format ) : int {
|
||||
global $wpdb;
|
||||
if ( empty( $data ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$columns = array_keys( $data );
|
||||
$value_format = array();
|
||||
$values = array();
|
||||
$index = 0;
|
||||
// Directly use NULL for placeholder if the value is NULL, since otherwise $wpdb->prepare will convert it to empty string.
|
||||
foreach ( $data as $key => $value ) {
|
||||
if ( is_null( $value ) ) {
|
||||
$value_format[] = 'NULL';
|
||||
} else {
|
||||
$values[] = $value;
|
||||
$value_format[] = $format[ $index ];
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
$columns = array_keys( $data );
|
||||
$column_clause = '`' . implode( '`, `', $columns ) . '`';
|
||||
$value_format_clause = implode( ', ', $value_format );
|
||||
$value_placeholders = implode( ', ', array_values( $format ) );
|
||||
$on_duplicate_clause = $this->generate_on_duplicate_statement_clause( $columns );
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Values are escaped in $wpdb->prepare.
|
||||
$sql = $wpdb->prepare(
|
||||
"
|
||||
INSERT INTO $table_name ( $column_clause )
|
||||
VALUES ( $value_format_clause )
|
||||
VALUES ( $value_placeholders )
|
||||
$on_duplicate_clause
|
||||
",
|
||||
$values
|
||||
array_values( $data )
|
||||
);
|
||||
// phpcs:enable
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is prepared.
|
||||
return $wpdb->query( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get max index length.
|
||||
*
|
||||
* @return int Max index length.
|
||||
*/
|
||||
public function get_max_index_length() : int {
|
||||
/**
|
||||
* Filters the maximum index length in the database.
|
||||
*
|
||||
* Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
|
||||
* As of WP 4.2, however, they moved to utf8mb4, which uses 4 bytes per character. This means that an index which
|
||||
* used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
|
||||
*
|
||||
* Additionally, MyISAM engine also limits the index size to 1000 bytes. We add this filter so that interested folks on InnoDB engine can increase the size till allowed 3071 bytes.
|
||||
*
|
||||
* @param int $max_index_length Maximum index length. Default 191.
|
||||
*
|
||||
* @since 8.0.0
|
||||
*/
|
||||
$max_index_length = apply_filters( 'woocommerce_database_max_index_length', 191 );
|
||||
// Index length cannot be more than 768, which is 3078 bytes in utf8mb4 and max allowed by InnoDB engine.
|
||||
return min( absint( $max_index_length ), 767 );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user