• Resolved Yan Knudtskov

    (@yannielsen)


    Hi support

    We’ve run into an issue with flush_rewrite_rules() being called excessively when using ApplePay.

    The symptoms of the issue is the site showing sporadic 404 for all front-facing URLs.
    All admin pages will work as long as they don’t require the REST API as those will also fail with 404s.

    We first detected this by hooking in like this:

    <?php

    add_filter('rewrite_rules_array', 'yanco_rewrite_rules_detector');
    function yanco_rewrite_rules_detector($rules)
    {
    // Mail about rewrite being flushed
    wp_mail('[email protected]', 'Rewrite Rules Detector', print_r($rules, true));

    return $rules;
    }

    This would send us an e-mail when ever the rewrite rules got flushed, this is a sample from a 1-hour timeframe – Notice there’s 18 flushes in just one hour(!) that’s quite excessive.

    Then we setup a more in-depth logging by temporarily modifying /wp-includes/rewrite.php as there’s not other real way to know what calles flush_rewrite_rules()

    <?php
    /**
    * Removes rewrite rules and then recreate rewrite rules.
    *
    * @since 3.0.0
    *
    * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
    *
    * @param bool $hard Whether to update .htaccess (hard flush) or just update
    * rewrite_rules option (soft flush). Default is true (hard).
    */
    function flush_rewrite_rules($hard = true)
    {
    global $wp_rewrite;

    if (is_callable(array( $wp_rewrite, 'flush_rules' ))) {
    $wp_rewrite->flush_rules($hard);
    }

    // Get the backtrace
    $backtrace = debug_backtrace();

    // Log or email the backtrace for debugging
    $log_message = "flush_rewrite_rules() was called!\n";
    foreach ($backtrace as $trace) {
    if (isset($trace['file']) && isset($trace['line'])) {
    $log_message .= sprintf("Called in %s on line %d\n", $trace['file'], $trace['line']);
    }
    }

    // Send an email or log the backtrace
    wp_mail('[email protected]', 'Rewrite Rules Detector', $log_message);
    }

    Checking each of those entries we could see this backtrace

    flush_rewrite_rules() was called! 
    Called in /home/kbhkollegier/public_html/wp-content/plugins/woocommerce-gateway-stripe/includes/class-wc-stripe-apple-pay-registration.php on line 326
    Called in /home/kbhkollegier/public_html/wp-content/plugins/woocommerce-gateway-stripe/includes/class-wc-stripe-apple-pay-registration.php on line 113
    Called in /home/kbhkollegier/public_html/wp-includes/class-wp-hook.php on line 324
    Called in /home/kbhkollegier/public_html/wp-includes/class-wp-hook.php on line 348
    Called in /home/kbhkollegier/public_html/wp-includes/plugin.php on line 517
    Called in /home/kbhkollegier/public_html/wp-admin/admin-ajax.php on line 45

    Diving into that particular file we can tell this is happening:

    public function verify_domain_if_configured() {
    $secret_key = $this->get_secret_key();

    if ( ! $this->is_enabled() || empty( $secret_key ) ) {
    return;
    }

    if ( ! $this->is_available() ) {
    return;
    }

    // Ensure that domain association file will be served.
    flush_rewrite_rules();

    // The rewrite rule method doesn't work if permalinks are set to Plain.
    // Create/update domain association file by copying it from the plugin folder as a fallback.
    $this->update_domain_association_file();

    // Register the domain with Apple Pay.
    $verification_complete = $this->register_domain_with_apple( $secret_key );

    // Show/hide notes if necessary.
    WC_Stripe_Inbox_Notes::notify_on_apple_pay_domain_verification( $verification_complete );
    }

    If we check the WooCommerce logs for the woocommerce-gateway-stripe we can see a lot of entries like this

    2024-09-18T00:00:25+00:00 Fejlret 
    ====Stripe Version: 8.7.0====
    ====Stripe Plugin API Version: 2024-06-20====
    ====Start Log====
    Your domain has been verified with Apple Pay!
    ====End Log====

    Checking just yesterday we can see no less than 674 entries of those, that would be around 28 per hour (!) which looking into the code base all would result in a flush_rewrite_rules().

    It would seem there’s some sort of bug in the codebase as triggering those flushes probably should not be happening 28 times per hour.

    The page I need help with: [log in to see the link]

Viewing 5 replies - 1 through 5 (of 5 total)
  • Plugin Support Zubair Zahid (woo-hc)

    (@doublezed2)

    Hello Yan Knudtskov,

    Thank you for contacting Woo support.

    I understand flush_rewrite_rules() is being called excessively when using Apple Pay, causing 404 errors for URLs and issues with the REST API.

    To help resolve this, could you check when this problem first started by reviewing the log entries?
    Also, try disabling Express Checkout temporarily to see if that resolves the issue.

    To assist you further, I’d like to understand your setup better.
    Please provide a copy of your site’s System Status Report by navigating to WooCommerce > Status, selecting “Get system report,” and then “Copy for support.”

    Once I have more details, I will be in a better position to assist you further.

    Best regards.

    Thread Starter Yan Knudtskov

    (@yannielsen)

    Hi Zubair Zahid (woo-hc)

    This started at Sep 2nd at 17:09 according to our log files.

    Disable Express Checkout does resolve the issue, but as the client needs to use ApplePay that is not an option or a way to solve the issue.

    As outlined in my quite thorough description, I’ve narrowed down the issue for you, so there’s no doubt at all the problem comes from the ApplePay part of the plugin.

    From reviewing the codebase of Stripe for WooCommerce, the entire issue stems from this:

    includes/class-wc-stripe-apple-pay-registration.php, line 47

    add_action( 'admin_init', [ $this, 'verify_domain_on_domain_name_change' ] );

    This hook would will call:

    /**
    * Trigger Apple Pay registration upon domain name change.
    *
    * @since 4.9.0
    */
    public function verify_domain_on_domain_name_change() {
    if ( $this->domain_name !== $this->get_option( 'apple_pay_verified_domain' ) ) {
    $this->verify_domain_if_configured();
    }
    }

    Which then calls (note the flush_rewrite_rules() call in the function):

    /**
    * Process the Apple Pay domain verification if proper settings are configured.
    *
    * @since 4.5.4
    * @version 4.9.0
    */
    public function verify_domain_if_configured() {
    $secret_key = $this->get_secret_key();

    if ( ! $this->is_enabled() || empty( $secret_key ) ) {
    return;
    }

    if ( ! $this->is_available() ) {
    return;
    }

    // Ensure that domain association file will be served.
    flush_rewrite_rules();

    // The rewrite rule method doesn't work if permalinks are set to Plain.
    // Create/update domain association file by copying it from the plugin folder as a fallback.
    $this->update_domain_association_file();

    // Register the domain with Apple Pay.
    $verification_complete = $this->register_domain_with_apple( $secret_key );

    // Show/hide notes if necessary.
    WC_Stripe_Inbox_Notes::notify_on_apple_pay_domain_verification( $verification_complete );
    }

    Hooking into admin_init seems to be a very unsure way to go, as that would potentially cause the flush_rewrite_rules() every time the /wp-admin/ is initialized – For a site with 10s of thousands of visitors and a very active /wp-admin/ order handling, that can easily drown a system.

    The right way to go about it would be to setup a WP-CRON scheduled task or using the Action Scheduler to do this check on a regular basis – it really should not be hooked I believe.

    Please relay that to the developers ??

    Plugin Support omarfpg a11n

    (@omarfpg)

    Hi @yannielsen,

    Thank you for the very detailed breakdown of the issue. You’ve done a great job hunting this one down. I’d be happy to help you report this to our developers. We can do that here.

    Before proceeding with the report, though, can you confirm that this issue happens even with a default theme and no other third-party plugin? This is meant to rule out any possible third-party interference.

    I’d be more inclined to check on why the conditional within the verify_domain_on_domain_name_change function is failing all the time:

    if ( $this->domain_name !== $this->get_option( 'apple_pay_verified_domain' ) )

    Can you do a quick check on your site for what’s being stored on both of those, please?

    Thanks!
    -OP

    Thread Starter Yan Knudtskov

    (@yannielsen)

    Hi omarfpg (woo-hc)

    Thank you for getting back to me, I also saw that conditional within the code

    if ( $this->domain_name !== $this->get_option( 'apple_pay_verified_domain' ) )

    and was wondering why it even got past that one, because I validated both the option inside the wp_options table as well as the value of $this->domain_name and everytime I checked, they we’re identical (I logged them to a log file).

    Check domain_name: kbh-kollegier.dk
    Check apple_pay_verified_domain: kbh-kollegier.dk

    I’m quite puzzled by that fact, because the check shouldn’t be passing that point but the other logging methods I described earlier with debug_backtrace() proves that it does somehow ??

    I tried it with default theme and no other third-party plugin and still it occured, although not as frequently, as that was on a staging site with less traffic, and because of that, less of admin_init being triggered.

    add_action( 'admin_init', [ $this, 'verify_domain_on_domain_name_change' ] );

    However, even if it’s not reproducible on your end, as I would also assume the check should work, from a developers standpoint (I’m a developer my self with 20+ years of experience) the admin_init is the wrong hook to use for this check I believe.

    Even if the check does work, it will still produce an excessive amount of

    $this->get_option( 'apple_pay_verified_domain' )

    to get that value everytime the admin_init hook is called, which it will be everytime someone does anything inside the WordPress Dashboard – even if it’s not related to the Stripe for WooCommerce settings.

    I know that using auto_load true for the option tries to address this, the value could be cached, etc. but it would still be wrong practice on every load of the admin.

    I don’t know the indepth reason of the validation of the ApplePay domain, but I’m assuming it has to do with something like

    • Guidelines from Apple
    • Making sure no transactions are made with an unverified domain

    Both are very valid reasons to do the check, but the check could easily be placed on for example

    • a recurring CRON job via the wp_schedule_event()
    • a recurring ActionScheduler action
    • if an extra safeguard was needed it could be invoked when the customer went to checkout on the
      • woocommerce_checkout_process: Triggered before checkout validation
      • woocommerce_before_checkout_process: Fires right before WooCommerce starts processing the checkout.

    Kind Regards

    Plugin Support Shameem R. a11n

    (@shameemreza)

    Hi @yannielsen

    I appreciate your in-depth analysis of the issue you’re encountering with the flush_rewrite_rules() function being called excessively when using Apple Pay.

    For reference, this particular forum is meant for general support with the core functionality of WooCommerce Stripe Payment Gateway itself. For development and custom coding questions, it’s best to ask for insight related to those on either the WooCommerce Advanced Facebook group or the WooCommerce Community Slack. Many of our developers hang out there and will be able to offer insights into your question.

    You can also create a bug or enhancement report on our GitHub repo here so our developer team can check and provide further insights.

    I wish I could help more, but hopefully, this gets you going in the right direction to get some further insight/information.

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘flush_rewrite_rules() called excessively’ is closed to new replies.