rebase on oct-10-2023

This commit is contained in:
Rachit Bhargava
2023-10-10 17:23:21 -04:00
parent d37566ffb6
commit d096058d7d
4789 changed files with 254611 additions and 307223 deletions

View File

@@ -0,0 +1,177 @@
<?php
namespace Automattic\WooCommerce\Blocks\Utils;
/**
* Utility methods used for migrating pages to block templates.
* {@internal This class and its methods should only be used within the BlockTemplateController.php and is not intended for public use.}
*/
class BlockTemplateMigrationUtils {
/**
* Check if a page has been migrated to a template.
*
* @param string $page_id Page ID.
* @return boolean
*/
public static function has_migrated_page( $page_id ) {
return (bool) get_option( 'has_migrated_' . $page_id, false );
}
/**
* Stores an option to indicate that a template has been migrated.
*
* @param string $page_id Page ID.
* @param string $status Status of the migration.
*/
public static function set_has_migrated_page( $page_id, $status = 'success' ) {
update_option( 'has_migrated_' . $page_id, $status );
}
/**
* Migrates a page to a template if needed.
*
* @param string $template_slug Template slug.
* @param \WP_Post $page Page object.
*/
public static function migrate_page( $template_slug, $page ) {
// Get the block template for this page. If it exists, we won't migrate because the user already has custom content.
$block_template = BlockTemplateUtils::get_block_template( 'woocommerce/woocommerce//' . $template_slug, 'wp_template' );
// If we were unable to get the block template, bail. Try again later.
if ( ! $block_template ) {
return;
}
// If a custom template is present already, no need to migrate.
if ( $block_template->wp_id ) {
return self::set_has_migrated_page( $template_slug, 'custom-template-exists' );
}
// Use the page template if it exists, which we'll use over our default template if found.
$page_template = self::get_page_template( $page );
$default_template = self::get_default_template( $page );
$template_content = $page_template ?: $default_template;
// If at this point we have no content to migrate, bail.
if ( ! $template_content ) {
return self::set_has_migrated_page( $template_slug, 'no-content' );
}
if ( self::create_custom_template( $block_template, $template_content ) ) {
return self::set_has_migrated_page( $template_slug );
}
}
/**
* Get template for a page following the page hierarchy.
*
* @param \WP_Post|null $page Page object.
* @return string
*/
protected static function get_page_template( $page ) {
$templates = array();
if ( $page && $page->ID ) {
$template = get_page_template_slug( $page->ID );
if ( $template && 0 === validate_file( $template ) ) {
$templates[] = $template;
}
$pagename = $page->post_name;
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) {
$templates[] = "page-{$pagename_decoded}";
}
$templates[] = "page-{$pagename}";
}
}
$block_template = false;
foreach ( $templates as $template ) {
$block_template = BlockTemplateUtils::get_block_template( get_stylesheet() . '//' . $template, 'wp_template' );
if ( $block_template && ! empty( $block_template->content ) ) {
break;
}
}
return $block_template ? $block_template->content : '';
}
/**
* Prepare default page template.
*
* @param \WP_Post $page Page object.
* @return string
*/
protected static function get_default_template( $page ) {
if ( ! $page || empty( $page->post_content ) ) {
return '';
}
$default_template_content = '
<!-- wp:group {"layout":{"inherit":true}} -->
<div class="wp-block-group">
<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading">' . wp_kses_post( $page->post_title ) . '</h1>
<!-- /wp:heading -->
' . wp_kses_post( $page->post_content ) . '
</div>
<!-- /wp:group -->
';
return self::get_block_template_part( 'header' ) . $default_template_content . self::get_block_template_part( 'footer' );
}
/**
* Create a custom template with given content.
*
* @param \WP_Block_Template|null $template Template object.
* @param string $content Template content.
* @return boolean Success.
*/
protected static function create_custom_template( $template, $content ) {
$term = get_term_by( 'slug', $template->theme, 'wp_theme', ARRAY_A );
if ( ! $term ) {
$term = wp_insert_term( $template->theme, 'wp_theme' );
}
$template_id = wp_insert_post(
[
'post_name' => $template->slug,
'post_type' => 'wp_template',
'post_status' => 'publish',
'tax_input' => array(
'wp_theme' => $template->theme,
),
'meta_input' => array(
'origin' => $template->source,
),
'post_content' => $content,
],
true
);
wp_set_post_terms( $template_id, array( $term['term_id'] ), 'wp_theme' );
return $template_id && ! is_wp_error( $template_id );
}
/**
* Returns the requested template part.
*
* @param string $part The part to return.
* @return string
*/
protected static function get_block_template_part( $part ) {
$template_part = BlockTemplateUtils::get_block_template( get_stylesheet() . '//' . $part, 'wp_template_part' );
if ( ! $template_part || empty( $template_part->content ) ) {
return '';
}
return $template_part->content;
}
}

View File

@@ -1,11 +1,15 @@
<?php
namespace Automattic\WooCommerce\Blocks\Utils;
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
use Automattic\WooCommerce\Blocks\Options;
use Automattic\WooCommerce\Blocks\Templates\CartTemplate;
use Automattic\WooCommerce\Blocks\Templates\CheckoutHeaderTemplate;
use Automattic\WooCommerce\Blocks\Templates\CheckoutTemplate;
use Automattic\WooCommerce\Blocks\Templates\MiniCartTemplate;
use Automattic\WooCommerce\Blocks\Templates\OrderConfirmationTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
/**
* Utility methods used for serving block templates from WooCommerce Blocks.
@@ -215,6 +219,11 @@ class BlockTemplateUtils {
$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 = 'uncategorized';
// Force the Mini-Cart template part to be in the Mini-Cart template part area.
if ( 'wp_template_part' === $template_type && 'mini-cart' === $template_file->slug ) {
$template->area = 'mini-cart';
}
return $template;
}
@@ -302,38 +311,52 @@ class BlockTemplateUtils {
* @return array The plugin template types.
*/
public static function get_plugin_block_template_types() {
$plugin_template_types = array(
'single-product' => array(
return array(
'single-product' => array(
'title' => _x( 'Single Product', 'Template name', 'woocommerce' ),
'description' => __( 'Displays a single product.', 'woocommerce' ),
),
'archive-product' => array(
'archive-product' => array(
'title' => _x( 'Product Catalog', 'Template name', 'woocommerce' ),
'description' => __( 'Displays your products.', 'woocommerce' ),
),
'taxonomy-product_cat' => array(
'taxonomy-product_cat' => array(
'title' => _x( 'Products by Category', 'Template name', 'woocommerce' ),
'description' => __( 'Displays products filtered by a category.', 'woocommerce' ),
),
'taxonomy-product_tag' => array(
'taxonomy-product_tag' => array(
'title' => _x( 'Products by Tag', 'Template name', 'woocommerce' ),
'description' => __( 'Displays products filtered by a tag.', 'woocommerce' ),
),
ProductAttributeTemplate::SLUG => array(
ProductAttributeTemplate::SLUG => array(
'title' => _x( 'Products by Attribute', 'Template name', 'woocommerce' ),
'description' => __( 'Displays products filtered by an attribute.', 'woocommerce' ),
),
ProductSearchResultsTemplate::SLUG => array(
ProductSearchResultsTemplate::SLUG => array(
'title' => _x( 'Product Search Results', 'Template name', 'woocommerce' ),
'description' => __( 'Displays search results for your store.', 'woocommerce' ),
),
MiniCartTemplate::SLUG => array(
'title' => _x( 'Mini Cart', 'Template name', 'woocommerce' ),
'description' => __( 'Template used to display the Mini Cart drawer.', 'woocommerce' ),
MiniCartTemplate::SLUG => array(
'title' => _x( 'Mini-Cart', 'Template name', 'woocommerce' ),
'description' => __( 'Template used to display the Mini-Cart drawer.', 'woocommerce' ),
),
CartTemplate::get_slug() => array(
'title' => _x( 'Cart', 'Template name', 'woocommerce' ),
'description' => __( 'The Cart template displays the items selected by the user for purchase, including quantities, prices, and discounts. It allows users to review their choices before proceeding to checkout.', 'woocommerce' ),
),
CheckoutTemplate::get_slug() => array(
'title' => _x( 'Checkout', 'Template name', 'woocommerce' ),
'description' => __( 'The Checkout template guides users through the final steps of the purchase process. It enables users to enter shipping and billing information, select a payment method, and review order details.', 'woocommerce' ),
),
CheckoutHeaderTemplate::SLUG => array(
'title' => _x( 'Checkout Header', 'Template name', 'woocommerce' ),
'description' => __( 'Template used to display the simplified Checkout header.', 'woocommerce' ),
),
OrderConfirmationTemplate::get_slug() => array(
'title' => _x( 'Order Confirmation', 'Template name', 'woocommerce' ),
'description' => __( 'The Order Confirmation template provides customers with a summary of their completed purchase, including ordered items, shipping details, and order total. It serves as a receipt and confirmation of the successful transaction.', 'woocommerce' ),
),
);
return $plugin_template_types;
}
/**
@@ -422,25 +445,25 @@ class BlockTemplateUtils {
/**
* Checks to see if they are using a compatible version of WP, or if not they have a compatible version of the Gutenberg plugin installed.
*
* @param string $template_type Optional. Template type: `wp_template` or `wp_template_part`.
* Default `wp_template`.
* @return boolean
*/
public static function supports_block_templates() {
if (
! wc_current_theme_is_fse_theme() &&
( ! function_exists( 'gutenberg_supports_block_templates' ) || ! gutenberg_supports_block_templates() )
) {
return false;
public static function supports_block_templates( $template_type = 'wp_template' ) {
if ( 'wp_template_part' === $template_type && ( wc_current_theme_is_fse_theme() || current_theme_supports( 'block-template-parts' ) ) ) {
return true;
} elseif ( 'wp_template' === $template_type && wc_current_theme_is_fse_theme() ) {
return true;
}
return true;
return false;
}
/**
* Retrieves a single unified template object using its id.
*
* @param string $id Template unique identifier (example: theme_slug//template_slug).
* @param string $template_type Optional. Template type: `'wp_template'` or '`wp_template_part'`.
* Default `'wp_template'`.
* @param string $template_type Optional. Template type: `wp_template` or 'wp_template_part`.
* Default `wp_template`.
*
* @return WP_Block_Template|null Template.
*/
@@ -675,4 +698,41 @@ class BlockTemplateUtils {
public static function template_has_legacy_template_block( $template ) {
return has_block( 'woocommerce/legacy-template', $template->content );
}
/**
* Gets the templates saved in the database.
*
* @param array $slugs An array of slugs to retrieve templates for.
* @param string $template_type wp_template or wp_template_part.
*
* @return int[]|\WP_Post[] An array of found templates.
*/
public static function get_block_templates_from_db( $slugs = array(), $template_type = 'wp_template' ) {
$check_query_args = array(
'post_type' => $template_type,
'posts_per_page' => -1,
'no_found_rows' => true,
'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'terms' => array( self::DEPRECATED_PLUGIN_SLUG, self::PLUGIN_SLUG, get_stylesheet() ),
),
),
);
if ( is_array( $slugs ) && count( $slugs ) > 0 ) {
$check_query_args['post_name__in'] = $slugs;
}
$check_query = new \WP_Query( $check_query_args );
$saved_woo_templates = $check_query->posts;
return array_map(
function( $saved_woo_template ) {
return self::build_template_result_from_post( $saved_woo_template );
},
$saved_woo_templates
);
}
}

View File

@@ -12,6 +12,21 @@ class CartCheckoutUtils {
* @return bool true if the WC cart page is using the Cart block.
*/
public static function is_cart_block_default() {
if ( wc_current_theme_is_fse_theme() ) {
// Ignore the pages and check the templates.
$templates_from_db = BlockTemplateUtils::get_block_templates_from_db( array( 'cart' ), 'wp_template' );
// If there is no template file, we're using default which does use the block.
if ( empty( $templates_from_db ) ) {
return true;
}
foreach ( $templates_from_db as $template ) {
if ( has_block( 'woocommerce/cart', $template->content ) ) {
return true;
}
}
}
$cart_page_id = wc_get_page_id( 'cart' );
return $cart_page_id && has_block( 'woocommerce/cart', $cart_page_id );
}
@@ -22,7 +37,72 @@ class CartCheckoutUtils {
* @return bool true if the WC checkout page is using the Checkout block.
*/
public static function is_checkout_block_default() {
if ( wc_current_theme_is_fse_theme() ) {
// Ignore the pages and check the templates.
$templates_from_db = BlockTemplateUtils::get_block_templates_from_db( array( 'checkout' ), 'wp_template' );
// If there is no template file, we're using default which does use the block.
if ( empty( $templates_from_db ) ) {
return true;
}
foreach ( $templates_from_db as $template ) {
if ( has_block( 'woocommerce/checkout', $template->content ) ) {
return true;
}
}
}
$checkout_page_id = wc_get_page_id( 'checkout' );
return $checkout_page_id && has_block( 'woocommerce/checkout', $checkout_page_id );
}
/**
* Gets country codes, names, states, and locale information.
*
* @return array
*/
public static function get_country_data() {
$billing_countries = WC()->countries->get_allowed_countries();
$shipping_countries = WC()->countries->get_shipping_countries();
$country_locales = wc()->countries->get_country_locale();
$country_states = wc()->countries->get_states();
$all_countries = self::deep_sort_with_accents( array_unique( array_merge( $billing_countries, $shipping_countries ) ) );
$country_data = [];
foreach ( array_keys( $all_countries ) as $country_code ) {
$country_data[ $country_code ] = [
'allowBilling' => isset( $billing_countries[ $country_code ] ),
'allowShipping' => isset( $shipping_countries[ $country_code ] ),
'states' => self::deep_sort_with_accents( $country_states[ $country_code ] ?? [] ),
'locale' => $country_locales[ $country_code ] ?? [],
];
}
return $country_data;
}
/**
* Removes accents from an array of values, sorts by the values, then returns the original array values sorted.
*
* @param array $array Array of values to sort.
* @return array Sorted array.
*/
protected static function deep_sort_with_accents( $array ) {
if ( ! is_array( $array ) || empty( $array ) ) {
return $array;
}
$array_without_accents = array_map(
function( $value ) {
return is_array( $value )
? self::deep_sort_with_accents( $value )
: remove_accents( wc_strtolower( html_entity_decode( $value ) ) );
},
$array
);
asort( $array_without_accents );
return array_replace( $array_without_accents, $array );
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Automattic\WooCommerce\Blocks\Utils;
/**
* Utility methods used for the Mini Cart block.
*/
class MiniCartUtils {
/**
* Migrate attributes to color panel component format.
*
* @param array $attributes Any attributes that currently are available from the block.
* @return array Reformatted attributes that are compatible with the color panel component.
*/
public static function migrate_attributes_to_color_panel( $attributes ) {
if ( isset( $attributes['priceColorValue'] ) && ! isset( $attributes['priceColor'] ) ) {
$attributes['priceColor'] = array(
'color' => $attributes['priceColorValue'],
);
unset( $attributes['priceColorValue'] );
}
if ( isset( $attributes['iconColorValue'] ) && ! isset( $attributes['iconColor'] ) ) {
$attributes['iconColor'] = array(
'color' => $attributes['iconColorValue'],
);
unset( $attributes['iconColorValue'] );
}
if ( isset( $attributes['productCountColorValue'] ) && ! isset( $attributes['productCountColor'] ) ) {
$attributes['productCountColor'] = array(
'color' => $attributes['productCountColorValue'],
);
unset( $attributes['productCountColorValue'] );
}
return $attributes;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Automattic\WooCommerce\Blocks\Utils;
use WC_Admin_Settings;
/**
* WooSettingsUtils class
*/
class SettingsUtils {
/**
* Input field for permalink settings/pages.
*
* @param array $value Input value.
*/
public static function permalink_input_field( $value ) {
$field_description = WC_Admin_Settings::get_field_description( $value );
$description = $field_description['description'];
$tooltip_html = $field_description['tooltip_html'];
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo wp_kses_post( $tooltip_html ); ?></label>
</th>
<td class="forminp forminp-text">
<span class="code" style="width: 400px; display:flex; align-items:center; gap:5px;">
<code class="permalink-custom" style="vertical-align: middle;">
<?php echo esc_html( get_site_url( null, '/' ) ); ?>
</code>
<input
name="<?php echo esc_attr( $value['field_name'] ); ?>"
id="<?php echo esc_attr( $value['id'] ); ?>"
type="text"
required
style="vertical-align: middle;"
value="<?php echo esc_attr( $value['value'] ); ?>"
class="<?php echo esc_attr( $value['class'] ); ?>"
placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
/><?php echo esc_html( $value['suffix'] ); ?>
</span>
<?php echo wp_kses_post( $description ); ?>
</td>
</tr>
<?php
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Automattic\WooCommerce\Blocks\Utils;
/**
* Utils class
*/
class Utils {
/**
* Compare the current WordPress version with a given version. It's a wrapper around `version-compare`
* that additionally takes into account the suffix (like `-RC1`).
* For example: version 6.3 is considered lower than 6.3-RC2, so you can do
* wp_version_compare( '6.3', '>=' ) and that will return true for 6.3-RC2.
*
* @param string $version The version to compare against.
* @param string|null $operator Optional. The comparison operator. Defaults to null.
* @return bool|int Returns true if the current WordPress version satisfies the comparison, false otherwise.
*/
public static function wp_version_compare( $version, $operator = null ) {
$current_wp_version = get_bloginfo( 'version' );
if ( preg_match( '/^([0-9]+\.[0-9]+)/', $current_wp_version, $matches ) ) {
$current_wp_version = (float) $matches[1];
}
return version_compare( $current_wp_version, $version, $operator );
}
}