woocommerce / woocommerce

A customizable, open-source ecommerce platform built on WordPress. Build any commerce solution you can imagine.
https://woocommerce.com
9.31k stars 10.75k forks source link

Inconsistent Use of 'woocommerce_after_shop_loop' & 'woocommerce_after_shop_loop_item' #46810

Open BFTrick opened 4 months ago

BFTrick commented 4 months ago

Prerequisites

Describe the bug

Hello!

We have some custom code that uses these hooks:

We print some HTML after each product with woocommerce_after_shop_loop_item and we have some JavaScript that's printed after all products using woocommerce_after_shop_loop.

Specifically with the [products] shortcode.

WooCommerce will always fire woocommerce_after_shop_loop_item (assuming there's at least one product) but you will only fire woocommerce_after_shop_loop if you also have the pagination attribute set to true.

Expected behavior

Unfortunately we learned that there are some cases where woocommerce_after_shop_loop_item fires even though woocommerce_after_shop_loop will never fire.

(The same is true for woocommerce_before_shop_loop_item and woocommerce_before_shop_loop)

Actual behavior

Take a look at the WC_Shortcode_Products class. You'll see these two code blocks:

// Fire standard shop loop hooks when paginating results so we can show result counts and so on.
if ( wc_string_to_bool( $this->attributes['paginate'] ) ) {
    do_action( 'woocommerce_before_shop_loop' );
}
// Fire standard shop loop hooks when paginating results so we can show result counts and so on.
if ( wc_string_to_bool( $this->attributes['paginate'] ) ) {
    do_action( 'woocommerce_after_shop_loop' );
}

This, in my opinion, is where WooCommerce isn't doing something incorrectly. If you don't want to show pagination links, the gridlist toggle, the number of results, etc. that's fine. But Woo is still showing a collection of products. And other developers may want to use that hook.

If Woo wants to hide the pagination links, gridlist toggle, number of results, etc. I'd specifically remove those hooks instead of the entire action.

Steps to reproduce

Review the WC_Shortcode_Products class.

Alternatively use the [products] block with and without the pagination=true attribute.

If pagination=true isn't set then these two hooks won't fire:

WordPress Environment

`

WordPress Environment

WordPress address (URL): http://woo-core.local Site address (URL): http://woo-core.local WC Version: 8.8.2 REST API Version: ✔ 8.8.2 Action Scheduler Version: ✔ 3.7.4 Log Directory Writable: ✔ WP Version: 6.5.2 WP Multisite: – WP Memory Limit: 256 MB WP Debug Mode: – WP Cron: ✔ Language: en_US External object cache: –

Server Environment

Server Info: nginx/1.16.0 PHP Version: 8.1.23 PHP Post Max Size: 1,000 MB PHP Time Limit: 1200 PHP Max Input Vars: 4000 cURL Version: 8.4.0 (SecureTransport) LibreSSL/3.3.6

SUHOSIN Installed: – MySQL Version: 8.0.16 Max Upload Size: 300 MB Default Timezone is UTC: ✔ fsockopen/cURL: ✔ SoapClient: ✔ DOMDocument: ✔ GZip: ✔ Multibyte String: ✔ Remote Post: ✔ Remote Get: ✔

Database

WC Database Version: 8.5.2 WC Database Prefix: wp_ Total Database Size: 4.89MB Database Data Size: 3.20MB Database Index Size: 1.69MB wp_woocommerce_sessions: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_api_keys: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_attribute_taxonomies: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_downloadable_product_permissions: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_woocommerce_order_items: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_order_itemmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_tax_rates: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_woocommerce_tax_rate_locations: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_shipping_zones: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_woocommerce_shipping_zone_locations: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_shipping_zone_methods: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_woocommerce_payment_tokens: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_woocommerce_payment_tokenmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_woocommerce_log: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_actionscheduler_actions: Data: 0.02MB + Index: 0.11MB + Engine InnoDB wp_actionscheduler_claims: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_actionscheduler_groups: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_actionscheduler_logs: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_commentmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_comments: Data: 0.02MB + Index: 0.08MB + Engine InnoDB wp_links: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_options: Data: 2.06MB + Index: 0.06MB + Engine InnoDB wp_postmeta: Data: 0.06MB + Index: 0.03MB + Engine InnoDB wp_posts: Data: 0.06MB + Index: 0.06MB + Engine InnoDB wp_term_relationships: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_term_taxonomy: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_termmeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_terms: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_usermeta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_users: Data: 0.02MB + Index: 0.05MB + Engine InnoDB wp_wc_admin_note_actions: Data: 0.06MB + Index: 0.02MB + Engine InnoDB wp_wc_admin_notes: Data: 0.06MB + Index: 0.00MB + Engine InnoDB wp_wc_category_lookup: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_wc_customer_lookup: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_download_log: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_order_addresses: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_wc_order_coupon_lookup: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_order_operational_data: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_order_product_lookup: Data: 0.02MB + Index: 0.06MB + Engine InnoDB wp_wc_order_stats: Data: 0.02MB + Index: 0.05MB + Engine InnoDB wp_wc_order_tax_lookup: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_orders: Data: 0.02MB + Index: 0.11MB + Engine InnoDB wp_wc_orders_meta: Data: 0.02MB + Index: 0.03MB + Engine InnoDB wp_wc_product_attributes_lookup: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_product_download_directories: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_product_meta_lookup: Data: 0.02MB + Index: 0.09MB + Engine InnoDB wp_wc_rate_limits: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_reserved_stock: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_wc_tax_rate_classes: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_wc_webhooks: Data: 0.02MB + Index: 0.02MB + Engine InnoDB

Post Type Counts

attachment: 11 page: 7 post: 2 product: 18 revision: 3 wp_global_styles: 1 wp_navigation: 1 wp_template: 2

Security

Secure connection (HTTPS): ❌ Your store is not using HTTPS. Learn more about HTTPS and SSL Certificates. Hide errors from visitors: ✔

Active Plugins (1)

WooCommerce: by Automattic – 8.8.2

Inactive Plugins (0)

Settings

API Enabled: – Force SSL: – Currency: USD ($) Currency Position: left Thousand Separator: , Decimal Separator: . Number of Decimals: 2 Taxonomies: Product Types: external (external) grouped (grouped) simple (simple) variable (variable)

Taxonomies: Product Visibility: exclude-from-catalog (exclude-from-catalog) exclude-from-search (exclude-from-search) featured (featured) outofstock (outofstock) rated-1 (rated-1) rated-2 (rated-2) rated-3 (rated-3) rated-4 (rated-4) rated-5 (rated-5)

Connected to WooCommerce.com: – Enforce Approved Product Download Directories: ✔ HPOS feature screen enabled: ✔ HPOS feature enabled: ✔ Order datastore: Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore HPOS data sync enabled: –

Logging

Enabled: ✔ Handler: Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2 Retention period: 30 days Level threshold: – Log directory size: 13 B

WC Pages

Shop base: #7 - /shop/ Cart: #8 - /cart/ Checkout: #9 - /checkout/ My account: #10 - /my-account/ Terms and conditions: ❌ Page not set

Theme

Name: Storefront Version: 4.5.5 Author URL: https://woocommerce.com/ Child Theme: ❌ – If you are modifying WooCommerce on a parent theme that you did not build personally we recommend using a child theme. See: How to create a child theme WooCommerce Support: ✔

Templates

Overrides: –

Admin

Enabled Features: activity-panels analytics product-block-editor coupons core-profiler customize-store customer-effort-score-tracks import-products-task experimental-fashion-sample-products shipping-smart-defaults shipping-setting-tour homescreen marketing mobile-app-banner navigation onboarding onboarding-tasks product-variation-management product-virtual-downloadable product-external-affiliate product-grouped product-linked product-pre-publish-modal remote-inbox-notifications remote-free-extensions payment-gateway-suggestions shipping-label-banner subscriptions store-alerts transient-notices woo-mobile-welcome wc-pay-promotion wc-pay-welcome-page

Disabled Features: minified-js new-product-management-experience product-custom-fields settings async-product-editor-category-field launch-your-store

Daily Cron: ✔ Next scheduled: 2024-04-23 21:22:38 +00:00 Options: ✔ Notes: 78 Onboarding: completed

Action Scheduler

Complete: 3 Oldest: 2024-04-15 21:54:03 +0000 Newest: 2024-04-22 21:49:46 +0000

Failed: 1 Oldest: 2024-02-05 21:24:38 +0000 Newest: 2024-02-05 21:24:38 +0000

Pending: 3 Oldest: 2024-04-22 21:51:04 +0000 Newest: 2024-04-23 21:49:46 +0000

Status report information

Generated at: 2024-04-22 21:51:29 +00:00 `

Isolating the problem

tjcafferkey commented 2 weeks ago

Thanks for submitting this issue @BFTrick I can indeed see why this is confusing as it doesn't align with other usages of the same action relative to the loop. I'm going to do some investigation into why this was done, if its still required and if there is any danger in moving it out of the pagination conditional. One thing we don't want to do is change this and break stores who are using it knowing about its quirks.

I can see this change was introduced 7 years ago in this PR https://github.com/woocommerce/woocommerce/pull/18726 by @mikejolley. Mike, do you recall why it was only fired when pagination is enabled? It seems this was done intentionally looking at the commit history and PR description.

mikejolley commented 2 weeks ago

@tjcafferkey This is a case where a hook was introduced with a specific purpose in mind (in this case, paginated archives) and this was probably "shop" page specific at the time.

There are 2 alternative hooks fired in those exact locations however.

woocommerce_shortcode_before_{$this->type}_loop woocommerce_shortcode_after_{$this->type}_loop

These are not wrapped in a check for pagination.