woocommerce / woocommerce

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

Performance Issue with 'get_cart_contents()' Function Triggering Multiple Times #48053

Open Stas0238 opened 4 months ago

Stas0238 commented 4 months ago

Prerequisites

Describe the bug

Dear WooCommerce Team,

I am writing to report a performance issue related to the get_cart_contents() function in the WooCommerce plugin. We have observed that this function is being called an excessive number of times, which negatively impacts the loading time of any websites using.

Issue Description

We have noticed that on pages with active WooCommerce and our theme, the get_cart_contents() function, along with its associated filter woocommerce_get_cart_contents, is triggered 35 times—even on simple pages with no products added to cart. This repeated execution leads to unnecessary performance degradation.

Expected behavior

The get_cart_contents() function should ideally be called once per page load, or at most 2-3 times, to minimize performance impact.

Actual behavior

The function is being called 11-14 times with the Storefront theme and 8-9 times with the Hello Elementor theme, which is excessive and leads to increased load times due to repeated filter applications. The times amoung depends on the theme active and WooCommerce conditional functions used such as if (WC()->cart->is_empty()) { // custom php code }

Example Filter Code

add_filter('woocommerce_get_cart_contents', function($contents) {
    foreach ($contents as $item => $values) {
        // Modify the product item as needed
    }
    return $contents;
}, 20, 1);

This excessive calling of the get_cart_contents() function and its filter can cause significant performance issues, especially when multiple plugins or themes are modifying the cart contents.

Steps to reproduce

  1. Create a Logging Function: Add a custom logging function named write_custom_log directly in the main woocommerce.php file (https://prnt.sc/m-JiCP2wJHaK). if ( ! function_exists('write_custom_log')) { function write_custom_log ( $log ) { $bt = debug_backtrace(); $caller = array_shift($bt); if ( is_array( $log ) || is_object( $log ) ) { error_log( 'File:' . basename( $caller['file'] ) .':'.$caller['line'] . ' ' . print_r( $log, true ) ); } else { error_log( 'File:' . basename( $caller['file'] ) .':'.$caller['line'] . ' ' . $log ); } } }

  2. Modify get_cart_contents() Function: Insert a call to the write_custom_log function within the get_cart_contents() function (https://prnt.sc/KfVt7V3sTC9U). function get_cart_contents() { write_custom_log('get_cart_contents triggered'); // existing code... }

  3. Clear debug.log and Load a Simple Page:

  4. Test with Conditional Function: Add the following code in storefront/page.php: if (class_exists('WooCommerce')) { if (WC()->cart->is_empty()) { echo 'cart is empty'; } } Before adding this code, the function was triggered 11 times (https://prnt.sc/PiCNbUj7j9l7). After adding it, the function was triggered 12 times (https://prnt.sc/Vw6BivXP8bMH), confirming our suspicions.

  5. Test with Hello Elementor Theme:

WordPress Environment

WordPress Environment

WordPress address (URL): http://tester01.local Site address (URL): http://tester01.local WC Version: 8.9.1 REST API Version: ✔ 8.9.1 Action Scheduler Version: ✔ 3.7.4 Log Directory Writable: ✔ WP Version: 6.5.3 WP Multisite: – WP Memory Limit: 512 MB WP Debug Mode: ✔ WP Cron: ✔ Language: en_US External object cache: –

Server Environment

Server Info: nginx/1.16.0 PHP Version: 7.4.30 PHP Post Max Size: 1,000 MB PHP Time Limit: 1200 PHP Max Input Vars: 4000 cURL Version: 7.84.0 (SecureTransport) OpenSSL/1.1.1q

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.9.1 WC Database Prefix: wp_ Total Database Size: 10.95MB Database Data Size: 8.85MB Database Index Size: 2.10MB 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.09MB + Engine InnoDB wp_e_events: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_e_submissions: Data: 0.02MB + Index: 0.23MB + Engine InnoDB wp_e_submissions_actions_log: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_e_submissions_values: Data: 0.02MB + Index: 0.00MB + Engine InnoDB wp_links: Data: 0.02MB + Index: 0.02MB + Engine InnoDB wp_options: Data: 4.05MB + Index: 0.06MB + Engine InnoDB wp_postmeta: Data: 1.52MB + Index: 0.20MB + Engine InnoDB wp_posts: Data: 2.19MB + 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.05MB + 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: 233 customize_changeset: 1 elementor_library: 9 mc4wp-form: 1 nav_menu_item: 28 page: 13 post: 12 product: 15 product_variation: 2 revision: 21 wp_navigation: 1 wpcf7_contact_form: 2

Security

Secure connection (HTTPS): ❌ Your store is not using HTTPS. Learn more about HTTPS and SSL Certificates. Hide errors from visitors: ❌Error messages should not be shown to visitors.

Active Plugins (1)

WooCommerce: by Automattic – 8.9.1

Inactive Plugins (5)

Contact Form 7: by Takayuki Miyoshi – 5.9.3 Elementor: by Elementor.com – 3.21.4

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 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: 65 KB

WC Pages

Shop base: #20 - /shop/ Cart: ❌ Page does not contain the [woocommerce_cart] shortcode or the woocommerce/cart block. Checkout: ❌ Page does not contain the [woocommerce_checkout] shortcode or the woocommerce/checkout block. My account: #24 - /my-account/ Terms and conditions: ❌ Page not set

Theme

Name: Storefront Version: 4.6.0 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 product-custom-fields 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 settings async-product-editor-category-field launch-your-store

Daily Cron: ✔ Next scheduled: 2024-05-31 14:14:52 +00:00 Options: ✔ Notes: 71 Onboarding: -

Status report information

Generated at: 2024-05-31 09:50:07 +00:00 `

Isolating the problem

wavvves commented 3 months ago

Hi @Stas0238 , thank for reporting this. This issue will focus on investigating get_cart_contents() within the WooCommerce codebase. I recommend that additional findings regarding themes and plugins should reported on their own repositories/support system so they can be investigated in parallel by the respective teams, as we don't have ownership over those codebases.

github-actions[bot] commented 3 months ago

As a part of this repository's maintenance, this issue is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.

After 7 days with no activity this issue will be automatically be closed.
Stas0238 commented 2 months ago

Dear @wavvves,

I agree with your idea. However, if it is a Premium WordPress theme, it makes sense that there isn't an open repository for it, as the code is proprietary and not publicly accessible. Anyway, I would ask the WooCommerce's developers to review this request in detail, as the main issue and solution need to be addressed on their end.

Kind regards, @Stas0238