Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Refactor checkout templates to share logic (#9411)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikejolley authored May 10, 2023
1 parent 20bc253 commit 58cb700
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 241 deletions.
136 changes: 131 additions & 5 deletions src/BlockTemplatesController.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<?php
namespace Automattic\WooCommerce\Blocks;

use Automattic\WooCommerce\Admin\Overrides\Order;
use Automattic\WooCommerce\Blocks\Domain\Package;
use Automattic\WooCommerce\Blocks\Templates\CartTemplate;
use Automattic\WooCommerce\Blocks\Templates\CheckoutTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Templates\SingleProductTemplateCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Blocks\Templates\OrderReceivedTemplate;
use Automattic\WooCommerce\Blocks\Utils\SettingsUtils;

/**
* BlockTypesController class.
Expand Down Expand Up @@ -74,6 +74,19 @@ protected function init() {
add_filter( 'taxonomy_template_hierarchy', array( $this, 'add_archive_product_to_eligible_for_fallback_templates' ), 10, 1 );
add_filter( 'post_type_archive_title', array( $this, 'update_product_archive_title' ), 10, 2 );

if ( wc_current_theme_is_fse_theme() ) {
add_action( 'init', array( $this, 'register_template_endpoints' ) );
add_filter( 'woocommerce_is_checkout', array( $this, 'is_checkout_endpoint' ) );
add_filter( 'woocommerce_is_cart', array( $this, 'is_cart_endpoint' ) );
add_filter( 'woocommerce_get_cart_url', array( $this, 'get_cart_url' ) );
add_filter( 'woocommerce_get_checkout_url', array( $this, 'get_checkout_url' ) );
add_filter( 'woocommerce_settings_pages', array( $this, 'template_permalink_settings' ) );
add_action( 'woocommerce_admin_field_permalink', array( SettingsUtils::class, 'permalink_input_field' ) );
add_action( 'after_switch_theme', 'flush_rewrite_rules' );
add_action( 'update_option_woocommerce_checkout_page_endpoint', 'flush_rewrite_rules' );
add_action( 'update_option_woocommerce_cart_page_endpoint', 'flush_rewrite_rules' );
}

if ( $this->package->is_experimental_build() ) {
add_action( 'after_switch_theme', array( $this, 'check_should_use_blockified_product_grid_templates' ), 10, 2 );
}
Expand Down Expand Up @@ -566,18 +579,18 @@ public function render_block_template() {
}
} elseif (
is_cart() &&
! BlockTemplateUtils::theme_has_template( CartTemplate::SLUG ) && $this->block_template_is_available( CartTemplate::SLUG )
! BlockTemplateUtils::theme_has_template( CartTemplate::get_slug() ) && $this->block_template_is_available( CartTemplate::get_slug() )
) {
add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 );
} elseif (
is_checkout() &&
! BlockTemplateUtils::theme_has_template( CheckoutTemplate::SLUG ) && $this->block_template_is_available( CheckoutTemplate::SLUG )
! BlockTemplateUtils::theme_has_template( CheckoutTemplate::get_slug() ) && $this->block_template_is_available( CheckoutTemplate::get_slug() )
) {
add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 );
} elseif (
is_wc_endpoint_url( 'order-received' )
&& ! BlockTemplateUtils::theme_has_template( OrderReceivedTemplate::SLUG )
&& $this->block_template_is_available( OrderReceivedTemplate::SLUG )
&& ! BlockTemplateUtils::theme_has_template( OrderReceivedTemplate::get_slug() )
&& $this->block_template_is_available( OrderReceivedTemplate::get_slug() )
) {
add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 );
} else {
Expand Down Expand Up @@ -646,4 +659,117 @@ function_exists( 'is_shop' ) &&

return $post_type_name;
}

/**
* Registers rewrite endpoints for templates during init.
*/
public function register_template_endpoints() {
$query_vars = WC()->query->get_query_vars();
$cart_page = CartTemplate::get_legacy_page();
$cart_endpoint = get_option( 'woocommerce_cart_page_endpoint', $cart_page ? $cart_page->post_name : CartTemplate::get_slug() );
$checkout_page = CheckoutTemplate::get_legacy_page();
$checkout_endpoint = get_option( 'woocommerce_checkout_page_endpoint', $checkout_page ? $checkout_page->post_name : CheckoutTemplate::get_slug() );

add_rewrite_endpoint( $checkout_endpoint . '/' . $query_vars['order-received'], \EP_ROOT, $query_vars['order-received'] );
add_rewrite_endpoint( $checkout_endpoint . '/' . $query_vars['order-pay'], \EP_ROOT, $query_vars['order-pay'] );
add_rewrite_endpoint( $checkout_endpoint, \EP_ROOT, CheckoutTemplate::get_slug() );
add_rewrite_endpoint( $cart_endpoint, \EP_ROOT, CartTemplate::get_slug() );
}

/**
* Filters the `is_checkout` function so we can return true when the endpoint is active, or if one of its other endpoints are in use (e.g. order received).
*
* @param boolean $return True when on the checkout page.
* @return boolean
*/
public function is_checkout_endpoint( $return ) {
global $wp;

if ( isset( $wp->query_vars[ CheckoutTemplate::get_slug() ] ) || isset( $wp->query_vars[ OrderReceivedTemplate::get_slug() ] ) ) {
return true;
}

return $return;
}

/**
* Filters the `is_cart` function so we can return true when the endpoint is active.
*
* @param boolean $return True when on the checkout page.
* @return boolean
*/
public function is_cart_endpoint( $return ) {
global $wp;

if ( isset( $wp->query_vars[ CartTemplate::get_slug() ] ) ) {
return true;
}

return $return;
}

/**
* Replace the cart PAGE URL with the template endpoint URL.
*
* @return string
*/
public function get_cart_url() {
return site_url( '/' . CartTemplate::get_slug() );
}

/**
* Replace the checkout PAGE URL with the template endpoint URL.
*
* @return string
*/
public function get_checkout_url() {
return site_url( '/' . CheckoutTemplate::get_slug() );
}

/**
* Replaces page settings in WooCommerce with text based permalinks which point to a template.
*
* @param array $settings Settings pages.
* @return array
*/
public function template_permalink_settings( $settings ) {
foreach ( $settings as $key => $setting ) {
if ( 'woocommerce_checkout_page_id' === $setting['id'] ) {
$checkout_page = CheckoutTemplate::get_legacy_page();
$settings[ $key ] = [
'title' => __( 'Checkout page', 'woo-gutenberg-products-block' ),
'desc' => sprintf(
// translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
__( 'The checkout page template can be %1$s edited here%2$s.', 'woo-gutenberg-products-block' ),
'<a href="' . esc_url( admin_url( 'site-editor.php?postType=wp_template&postId=woocommerce%2Fwoocommerce%2F%2F' . CheckoutTemplate::get_slug() ) ) . '" target="_blank">',
'</a>'
),
'desc_tip' => __( 'This is the URL to the checkout page.', 'woo-gutenberg-products-block' ),
'id' => 'woocommerce_checkout_page_endpoint',
'type' => 'permalink',
'default' => $checkout_page ? $checkout_page->post_name : CheckoutTemplate::get_slug(),
'autoload' => false,
];
}
if ( 'woocommerce_cart_page_id' === $setting['id'] ) {
$cart_page = CartTemplate::get_legacy_page();
$settings[ $key ] = [
'title' => __( 'Cart page', 'woo-gutenberg-products-block' ),
'desc' => sprintf(
// translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
__( 'The cart page template can be %1$s edited here%2$s.', 'woo-gutenberg-products-block' ),
'<a href="' . esc_url( admin_url( 'site-editor.php?postType=wp_template&postId=woocommerce%2Fwoocommerce%2F%2F' . CartTemplate::get_slug() ) ) . '" target="_blank">',
'</a>'
),
'desc_tip' => __( 'This is the URL to the cart page.', 'woo-gutenberg-products-block' ),
'id' => 'woocommerce_cart_page_endpoint',
'type' => 'permalink',
'default' => $cart_page ? $cart_page->post_name : CartTemplate::get_slug(),
'autoload' => false,
];
}
}

return $settings;
}
}
2 changes: 1 addition & 1 deletion src/BlockTypes/ClassicTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected function render( $attributes, $content, $block ) {
$frontend_scripts::load_scripts();
}

if ( OrderReceivedTemplate::SLUG === $attributes['template'] ) {
if ( OrderReceivedTemplate::get_slug() === $attributes['template'] ) {
return $this->render_order_received();
}

Expand Down
138 changes: 138 additions & 0 deletions src/Templates/AbstractPageTemplate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php
namespace Automattic\WooCommerce\Blocks\Templates;

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

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

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

/**
* Returns the page object assigned to this template/page used for legacy purposes. Pages are no longer required.
*
* @return \WP_Post|null Post object or null.
*/
abstract public static function get_legacy_page();

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

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

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

/**
* Get the default content for a template.
*
* Overridden by child class to include their own logic.
*
* @param string $template_content The original content of the template.
* @return string
*/
protected function get_default_template_content( $template_content ) {
return $template_content;
}

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

/**
* Returns the default template content.
*
* @param string $template_content The content of the template.
* @param object $template_file The template file object.
* @return string
*/
public function page_template_content( $template_content, $template_file ) {
if ( $this->get_slug() !== $template_file->slug ) {
return $template_content;
}
return $this->get_default_template_content( $template_content );
}

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

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

/**
* Filter the page title when the template is active.
*
* @param string $title Page title.
* @return string
*/
public function page_template_title( $title ) {
if ( $this->is_active_template() ) {
return $this->get_template_title();
}
return $title;
}
}
Loading

0 comments on commit 58cb700

Please sign in to comment.