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

Commit

Permalink
Permalink solution for the checkout endpoint/template (#9406)
Browse files Browse the repository at this point in the history
* Checkout endpoint work

* Move setting field to util

* Include link to edit the template

* Remove todo

* Refactor checkout templates to share logic (#9411)

* Sync endpoints with pages (#9426)

* Switch to page syncing

* Update settings descriptions

---------

Co-authored-by: Paulo Arromba <17236129+wavvves@users.noreply.github.com>
  • Loading branch information
mikejolley and wavvves committed Jun 20, 2023
1 parent c8ad4c6 commit 0535d9e
Show file tree
Hide file tree
Showing 8 changed files with 362 additions and 128 deletions.
115 changes: 110 additions & 5 deletions src/BlockTemplatesController.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?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;
Expand All @@ -10,6 +9,8 @@
use Automattic\WooCommerce\Blocks\Templates\SingleProductTemplateCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Blocks\Templates\OrderReceivedTemplate;
use Automattic\WooCommerce\Blocks\Utils\SettingsUtils;
use \WP_Post;

/**
* BlockTypesController class.
Expand Down Expand Up @@ -75,6 +76,12 @@ 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 );
add_action( 'after_switch_theme', array( $this, 'check_should_use_blockified_product_grid_templates' ), 10, 2 );

if ( wc_current_theme_is_fse_theme() ) {
add_filter( 'woocommerce_settings_pages', array( $this, 'template_permalink_settings' ) );
add_filter( 'pre_update_option', array( $this, 'update_template_permalink' ), 10, 2 );
add_action( 'woocommerce_admin_field_permalink', array( SettingsUtils::class, 'permalink_input_field' ) );
}
}

/**
Expand Down Expand Up @@ -578,18 +585,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 @@ -658,4 +665,102 @@ function_exists( 'is_shop' ) &&

return $post_type_name;
}

/**
* 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_placeholder_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 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_placeholder_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 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;
}

/**
* Syncs entered permalink with the pages and returns the correct value.
*
* @param string $value Value of the option.
* @param string $option Name of the option.
* @return string
*/
public function update_template_permalink( $value, $option ) {
if ( 'woocommerce_checkout_page_endpoint' === $option ) {
return $this->sync_endpoint_with_page( CheckoutTemplate::get_placeholder_page(), 'checkout', $value );
}
if ( 'woocommerce_cart_page_endpoint' === $option ) {
return $this->sync_endpoint_with_page( CartTemplate::get_placeholder_page(), 'cart', $value );
}
return $value;
}

/**
* Syncs the provided permalink with the actual WP page.
*
* @param WP_Post|null $page The page object, or null if it does not exist.
* @param string $page_slug The identifier for the page e.g. cart, checkout.
* @param string $permalink The new permalink to use.
* @return string THe actual permalink assigned to the page. May differ from $permalink if it was already taken.
*/
protected function sync_endpoint_with_page( $page, $page_slug, $permalink ) {
if ( ! $page ) {
$updated_page_id = wc_create_page(
esc_sql( $permalink ),
'woocommerce_' . $page_slug . '_page_id',
$page_slug,
'',
'',
'publish'
);
} else {
$updated_page_id = wp_update_post(
[
'ID' => $page->ID,
'post_name' => esc_sql( $permalink ),
]
);
}

// Get post again in case slug was updated with a suffix.
if ( $updated_page_id && ! is_wp_error( $updated_page_id ) ) {
return get_post( $updated_page_id )->post_name;
}
return $permalink;
}
}
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.
*
* @return \WP_Post|null Post object or null.
*/
abstract public static function get_placeholder_page();

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

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

/**
* 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_placeholder_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 0535d9e

Please sign in to comment.