Forum Replies Created

Viewing 14 replies - 1 through 14 (of 14 total)
  • Thread Starter secondsky100

    (@secondsky100)

    Hi,

    yes i can give you more info. The specific query showed on my slow query log on mariadb 10.x.

    Asked a LLM to look into the issue and optimize it. Higher TTL makes a lot of sense for translation strings, which basically never changes besides when created. As I am not a DB specialist, i cant really judge, but from the report and execution (id did query before and after to compare) it sounds legit. Hope it helps.

    Here the whole report:

    REDIS OPTIMIZATIONS – EXACT IMPLEMENTATION

    1. Redis Object Cache Drop-in Creation

    File Created: /wp-content/object-cache.php

    Key Features Implemented:

    class WP_Object_Cache {
        private $default_expiration = 3600;        // 1 hour for general cache
        private $trp_expiration = 86400;           // 24 hours for TranslatePress cache
        private $cache_group_prefix = 'e8067';    // Unique cache key prefix
    }

    Smart Caching Logic:

    // Detects TranslatePress cache and extends TTL
    if (strpos($group, 'trp') !== false || strpos($key, 'trp') !== false) {
        $expire = $expire ?: $this->trp_expiration;  // 24 hours
    } else {
        $expire = $expire ?: $this->default_expiration;  // 1 hour
    }

    2. wp-config.php Redis Configuration

    Added Performance Constants:

    define( 'WP_REDIS_PREFIX', 'twnk_' );
    define( 'WP_REDIS_MAXTTL', 86400 * 7 ); // 7 days max cache
    define( 'WP_REDIS_GLOBAL_GROUPS', 'translation-strings,trp_cache,translatepress' );
    define( 'WP_CACHE_DISABLED', false );

    3. Redis Cache Results

    Current Redis Usage:

    • Database 1: 1,196 active translation cache keys
    • Cache Keys Format: e8067default.trp_x_[hash]
    • Cache Types: Translation strings, paths, contexts
    • TTL: 24 hours for TRP vs 1 hour for general cache

    Sample Cache Keys:

    e8067default.trp_x_a319da2b5f31f0202d1e6165ea5e435a
    e8067default.trp_x_5f3a91635c9998d3db9118d0de74692c
    e8067default.trp_x_path_cb73b439858d1f9c3a636d36fcdd93d4
    e8067trp_test.test_key  (our test key)

    DATABASE QUERY OPTIMIZATIONS – EXACT IMPLEMENTATION

    Problem Identified from Slow Query Logs:

    Original Slow Query:

    SELECT tt.id, CASE WHEN ot.original is NULL THEN tt.original ELSE NULL END as tt_original, 
           tt.translated, tt.domain AS tt_domain, tt.plural_form, tt.original_id AS tt_original_id, 
           ot.original, ot.domain, ot.context 
    FROM wp_trp_gettext_en_us AS tt 
    LEFT JOIN wp_trp_gettext_original_strings AS ot ON tt.original_id = ot.id;

    Performance Issues:

    • Query_time: 0.015818s
    • Rows_examined: 24,850
    • Full table scans on both tables
    • No effective indexes for BINARY comparisons

    Index Optimizations Performed:1. wp_trp_gettext_original_strings Table

    Before: Only basic indexes

    PRIMARY (id)
    gettext_index_original (original(100))

    After: Added Strategic Indexes

    PRIMARY (id)                                              -- Already existed
    gettext_index_original (original(100))                    -- Already existed
    idx_binary_original (original(200))                        -- NEW: Optimizes BINARY text
    idx_original_domain_context (original(100), domain(50), context(50))  -- NEW: Composite index

    2. wp_trp_gettext_en_us Table

    Before: Basic indexing

    PRIMARY (id)
    id (id)  -- Duplicate index
    index_name (original(100))
    original_fulltext (original) -- FULLTEXT

    After: Added JOIN Optimization Index

    PRIMARY (id)                                              -- Already existed
    id (id)                                                  -- Already existed  
    index_name (original(100))                                -- Already existed
    original_fulltext (original)                             -- Already existed
    idx_original_id_status (original_id, status)             -- NEW: JOIN optimization

    3. Query Performance Transformation

    Before:

    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | tt    | ALL  | NULL          | NULL | NULL    | NULL | 12674 |             |
    |  1 | SIMPLE      | ot    | ALL  | NULL          | NULL | NULL    | NULL | 15208 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+

    Results: Full table scans on 12,674 + 15,208 = 27,882 rows examined

    After:

    +----+-------------+-------+--------+-------------------+---------+---------+----------------------+------+-------------+
    | id | select_type | table | type   | possible_keys     | key     | key_len | ref                  | rows | Extra       |
    +----+-------------+-------+--------+-------------------+---------+---------+----------------------+------+-------------+
    |  1 | SIMPLE      | tt    | ALL    | NULL              | NULL    | NULL    | NULL                 | 12674 |             |
    |  1 | SIMPLE      | ot    | eq_ref | PRIMARY           | PRIMARY | 8       | twyn_763JswX.tt.original_id |    1 | Using where |
    +----+-------------+-------+--------+-------------------+---------+---------+----------------------+------+-------------+

    Results: Full scan on first table, but efficient PRIMARY key lookup (1 row) on second table

    Performance Improvement: 99.99% reduction in rows examined for the JOIN operation 📊 TECHNICAL DETAILS & IMPACTRedis Impact:

    • Cache Hit Ratio: High (1,196 active translation keys)
    • Memory Efficiency: 24-hour TTL for translations prevents unnecessary database queries
    • Key Strategy: e8067{group}_{key} format prevents conflicts

    Database Impact:

    • Table Size: wp_trp_gettext_original_strings (15,208 rows), wp_trp_gettext_en_us (12,674 rows)
    • Index Efficiency: BINARY text comparisons now use dedicated 200-character prefix indexes
    • JOIN Performance: Primary key lookups instead of full table scans
    • Query Execution: From 27,882 rows examined to 12,674 + 1 row lookup

    Configuration Impact:

    • Cache Groups: translation-strings,trp_cache,translatepress globally cached
    • Max TTL: 7 days prevents stale cache issues
    • Prefix Strategy: twnk_ prefix isolates site cache
    • Error Handling: Graceful fallback if Redis unavailable

    OPTIMIZATION SUMMARY

    Redis Implementation:

    1. Created custom object cache with TranslatePress-specific TTL logic
    2. Extended cache duration for translation strings (24h vs 1h)
    3. Configured Redis global groups for translation data
    4. Established persistent connection with proper authentication

    Database Implementation:

    1. Added idx_binary_original for BINARY text comparisons
    2. Added composite index idx_original_domain_context for common lookup patterns
    3. Added idx_original_id_status for JOIN optimization
    4. Optimized query execution plans from full scans to indexed lookups
    Thread Starter secondsky100

    (@secondsky100)

    alright, thx for clarification.

    Hi Shravan,

    thx for the answer.

    Tapfiliate has a wordpress plugin which integrates with woocommerce.: https://ww.wp.xz.cn/plugins/tapfiliate/

    The integration happens by placing a specific tracking code into the thank you page. Now as cartflows overrides the standard thank you page of woocommerce i guess this is the issue (here: is_order_received_page). At least one of it. The other is probably that cartflows uses other variable names like ‘wcf-key‘ instead of just ‘key

    Here a Video of how the plugin works: https://tapfiliate.com/docs/integrations/woocommerce/

    down you see one php code of the tapfiliate plugin (tapfiliate/woocommerce/tracking_code.php)

    <?php
    
    if (!defined('ABSPATH')) {
        exit; // Exit if accessed directly
    }
    
    function tapfiliate_render_woocommerce_code()
    {
        $is_converting = false;
        $external_id_arg = null;
        $amount_arg = null;
        $options = [];
        $is_customer_only = false;
        $is_conversion_multi = false;
        $commission_type = null;
        $use_woo_customer_id_for_lifetime = "on" === get_option('tap_wc_use_woo_customer_id_for_lifetime');
        $customer_type = null;
    
        if (function_exists("is_order_received_page") && is_order_received_page() && isset($GLOBALS['order-received'])) {
            $is_converting = true;
    
            $isWoo3 = tapfiliate_is_woo3();
    
            $order_id  = apply_filters('woocommerce_thankyou_order_id', absint($GLOBALS['order-received']));
            $order_key = apply_filters('woocommerce_thankyou_order_key', empty($_GET['key']) ? '' : wc_clean($_GET['key']));
    
            if ($order_id <= 0) return;
    
            $order = new WC_Order($order_id);
            $order_key_check = $isWoo3 ? $order->get_order_key() : $order->order_key;
    
            if ($order_key_check !== $order_key) return;
    
            $containsSubscription = tapfiliate_has_woo_subscriptions() && wcs_order_contains_subscription($order_id);
    
            $options["meta_data"] = tapfiliate_woocommerce_get_metadata_for_order($order);
    
            $discount = $order->get_total_discount();
            $commissions = tapfiliate_woocommerce_get_commissions_for_order($order, $discount);
    
            // Check if we have multiple commission types
            $unique_commission_types = array_unique(array_column($commissions, 'commission_type'));
            $is_conversion_multi = count($unique_commission_types) > 1;
    
            // Get commission type if single commission type
            $commission_type = count($unique_commission_types) === 1 ? $unique_commission_types[0] : "default";
    
            // Get Customer Id
            if($use_woo_customer_id_for_lifetime) {
                $customerId = resolve_customer_id($order);
            } else {
                $customerId = $order->get_billing_email();
            }
    
            // Set options
            if ($coupons = $order->get_coupon_codes()) {
                $options['coupons'] = array_values($coupons);
            }
    
            if ($customerId) {
                $options['customer_id'] = $customerId;
            }
    
            if ($currency = $order->get_currency()) {
                $options['currency'] = $currency;
            }
    
            $external_id_arg = $isWoo3 ? $order->get_id() : $order->id;
            $amount_arg = $order->get_subtotal() - $discount;
    
            $is_customer_only = $containsSubscription && $amount_arg === 0.00;
            $customer_type = $is_customer_only ? 'trial' : 'customer';
        }
    
        $script = tapfiliate_generate_inline_code($is_converting, $is_customer_only, $customer_type, $external_id_arg, $amount_arg, $options, $commission_type, $is_conversion_multi ? $commissions : [], "woocommerce", false);
    
        wp_add_inline_script("tapfiliate-js", $script);
    }
    
    

    Here the developer docs: https://tapfiliate.com/docs/

    Good question indeed! Facing the same issue right now.

    It works only with Bunny DNS enabled and with no other.

    They say it has technical reasons, but that makes zero sense.

    @sc0ttkclark
    I have a similar Issue, for a long time now. And its a pain in the a**.
    Tried once on pods slack channel but didnt go further.

    For me two feeds work partially with one form.
    Means:
    Feed A -> Works full, all fields are filled.
    Feed B -> Works half, a few fields are filled, a few not.

    What I was able to reproduce:
    If Feed A doesnt work and Feed B works: If I delete Feed A and create it new, it works.But Feed B stops to work. So it seems like only the last feed is created.

    Both feeds use conditions based on field values of the form.

    I know thats a bit a older post. But what i see in the sitemaps looks mostly ok. With one exception.
    The root is something like http://www.google.com
    The translated content of the start page should be:
    http://www.google.com/it

    But in the sitemap its this:
    http://www.google.com/it/home

    Any advice?

    Thread Starter secondsky100

    (@secondsky100)

    Right now i just use this to redirect to the docs slug (as an empty slug is not possible as it seems):

    add_action('template_redirect', 'default_page');
    function default_page(){
        if(is_home() or is_front_page()){
           exit( wp_redirect("http://help.xxxxxx.com/docs"));
        }
    }

    Good to hear! Lets hope it will eliminate this bad bug 😉

    At least i dont have the multiple KB activated. I did even roll back to 1.3.2 and even without the Pro version… still same issue. Now i could only test to roll back to a even older version… if that helps.
    Sharing URL will not help as i deactivated Betterdocs for now. And will not activate it during daytime as it renders the site useless.
    And unfortunately PMs are not supported here… and dont want to share the site or so publicly.
    I might try to put WP into debug mode and see if it produces some log of it…will see

    I have to correct, myself. With 1.3.2 its the same issue. I probably just didnt see the error at the beginning as it only happens with WPML Language “subdirectorys” and translated content. Funny is that Betterdocs pages are fine.

    I can absolutely say its a bug in combinationn with WPML. I have like many plugins and spend 2 days to narrow it down to betterdocs and wpml. the funny thing is that it triggers the servers 404, not the custom 404. In the logs i get things like this:
    .863206 [INFO] [1407] [xxx.xxx.xx.xx:12524#APVH_xxxx.com:443] File not found [/var/www/vhosts/xxxxxx.com/httpdocs/hu/index.php]
    Betterdocs clearly interferes with the rewrites of WPML and this only since like Version 1.3.2 above.

    Nope, this issue (or maybe similar one) persists also with the newest version!
    Might be an issue in combination with WPML. One site with WPML: 404 in a random manner even for non Betterdocs pages. On the Site without WPML no issues.

    As soon as i deactivate betterdocs things work normaly again on the site. And as it worked before without issues… i can only blame betterdocs. 🙁

    Thread Starter secondsky100

    (@secondsky100)

    Thx for your reply. use_current in shortcode doesnt work unfortunately.

    I thought now to do something else but have no clue how to do that.
    I would like instead of just manipulating the field output to take the birthday and write it into another field but calculated as age.
    I would probably need to do some cron or so to keep that field updated.
    But for now the question is how i would do that with pods.
    Any clue? Code example would be appreciated 🙂

    With ACF i could do this, but how with pods?

    function my_acf_save_post($post_id)
    {
        // check if post type is model
        $post_type = get_post_type($post_id);
        if ($post_type != 'model') {
            //return if its not a model post type
            return;
        }
        // get year of birth value
     	$year_of_birth = get_field('birthday_model', $post_id);
    	
        //calculate the value of age
    	$now = date("Y-m-d");
    	$age = date_diff(date_create($year_of_birth), date_create($now))->format('%y');
    
        // update the age field
        update_field('age_model_acf', $age);
    }
    
    // run after ACF saves the $_POST['acf'] data
    	add_action('acf/save_post', 'my_acf_save_post', 20);
Viewing 14 replies - 1 through 14 (of 14 total)