Hello B2BKing Support Team,
I am reaching out to report a technical issue identified while running B2BKing in combination with WooCommerce 9.3.4. The problem results in excessive transient creation in the wp_options table and leads to significant database growth and performance degradation.
After analyzing both the plugin code and production logs, I have identified several underlying issues.
First, the price filter (woocommerce_get_price_html) is applied globally whenever the “show B2C price” setting is enabled. This can be seen in:
b2bking/public/class-b2bking-public.php b2bking/includes/class-b2bking.php
Code:
if (intval(get_option('b2bking_show_b2c_price_setting', 0)) === 1){ add_filter('woocommerce_get_price_html', array($this, 'b2bking_show_both_prices'), 99995, 2);
}
This means the function b2bking_show_both_prices() runs on all price renders (archives, single products, related products, widgets), not only for B2B users.
Second, transient keys are generated using get_current_user_id():
get_current_user_id()
Resulting in keys such as:
b2bking_display_price_both{product_id}_0
For guest users (user ID = 0). This causes transients to be created for anonymous visitors, which represents the majority of traffic.
Third, transients are written even when the current user is not a B2B user. The logic includes:
$is_b2b_user = get_user_meta(get_current_user_id(),'b2bking_b2buser', true);
if ($is_b2b_user === 'yes'){ // B2B logic
}
// Later in the function:
set_transient('b2bking_display_price_both'.$product_id.'_'.get_current_user_id(), $price);
The set_transient() call executes regardless of whether the user is B2B, meaning guests and B2C users also trigger writes.
Fourth, and most critically, the caching logic is effectively disabled by default:
if ( !get_transient('b2bking_display_price_both'.$product_id.'_'.get_current_user_id()) || apply_filters('b2bking_display_both_cache_disable', true)
)
Because the filter default is true, this condition always evaluates to true. As a result:
- the cache is never reused
- the price is recalculated on every request
- set_transient() is executed on every price render
This defeats the purpose of caching entirely.
Fifth, due to this behavior, every call to:
woocommerce_get_price_html
results in a database write. On archive pages displaying multiple products, this leads to dozens of writes per request. Under crawler or bot traffic, this scales significantly.
Additionally, the plugin maintains a global transient that is updated on shutdown:
b2bking/includes/class-b2bking-global-helper.php b2bking/includes/class-b2bking.php
Code:
add_action('shutdown', function(){ b2bking()->set_global_data_update();
});
And:
set_transient('b2bking_global_data', $b2bking_data, 30 * DAY_IN_SECONDS);
This can result in repeated writes of large serialized datasets, even when no meaningful changes have occurred.
In production, this behavior has resulted in:
- tens of thousands of _transient_* rows
- a wp_options table exceeding several hundred megabytes
- continuous INSERT and UPDATE operations
- performance degradation under load
From an expected behavior standpoint:
- the price filter should only execute for relevant B2B users
- transients should not be created for guest or B2C users
- caching should be enabled by default and reused properly
- global transients should only be updated when underlying data changes
Based on this analysis, I recommend the following improvements:
- Restrict execution of the price filter:
if (!is_user_logged_in() || get_user_meta(get_current_user_id(),'b2bking_b2buser', true) !== 'yes') { return $price;
}
- Prevent transient creation for guests:
if (get_current_user_id() === 0) { return $price;
}
- Fix cache logic default:
apply_filters('b2bking_display_both_cache_disable', false)
- Only call set_transient() when necessary (B2B users and when value changes)
- Avoid unnecessary global transient updates by checking if data actually changed before writing
The current implementation effectively causes unbounded transient creation due to global execution combined with ineffective caching logic. This leads to database bloat and performance issues, especially on larger WooCommerce installations.
Kind regards, Timothy