Question:
Where is the proper WordPress place to add a filter for pre_get_table_charset
, prior to it getting executed?
The pre_get_table_charset
filter is triggered in wp-db.php::get_table_charset()
.
Update: Solution
Mark Kaplun pointed me in the right direction, which is to put the filter into a drop-in. Because we’re using an MU setup (as evidenced by my table-name), the easiest and simplest drop-in was sunrise.php
, which as I understand it, is designed to be loaded super-early anyway.
Update: Caveat
Once you successfully have the filter loaded, you will start getting these errors:
PHP Notice: Undefined index: wp_2_options in /srv/www/wordpress/web/wp/wp-includes/wp-db.php on line 25xx
This is because wp-db.php doesn’t cache the result the same way it would if it had to look it up from the DB, and this cache is used by both wp-db.php::get_table_charset()
and and wp-db.php::get_col_charset()
.
Solution: define a second filter, pre_get_col_charset
, with 3 parameters, which returns the same value as your pre_get_table_charset
filter.
add_filter('pre_get_col_charset', function($charset, $table, $column) {
return 'utf8mb4';
}, 10, 2);
Background:
WordPress generates a consistently slow query on our server:
SHOW FULL COLUMNS FROM `wp_2_options`
This is generated in wp-db.php::get_table_charset()
, and is used to determine the charset for a table. It is, of course, entirely unnecessary, because we know what the charset is. The most recent WordPress update ensured all our tables were utf8mb4, so surely we can hard-code this, and reduce the page-load speed?
Yes, we can. WordPress even provides a filter for it.
/**
* Filters the table charset value before the DB is checked.
*
* Passing a non-null value to the filter will effectively short-circuit
* checking the DB for the charset, returning that value instead.
*....
*/
$charset = apply_filters( 'pre_get_table_charset', null, $table );
Writing the code for this is trivial:
add_filter('pre_get_table_charset', function($charset, $table) {return 'utf8mb4'; }, 10, 2);
However, this filter is called VERY early in the WordPress execution stack. It is called before plugins are loaded and before mu-plugins are loaded.
It is called AFTER config/application.php
, but at that point, the add_filter()
function is not yet defined.
I know there are a billion and one places where I can hack the WordPress core and insert that line, but I’d prefer not to if I can.
Also, we’re using a WordPress Bedrock setup, if that helps at all.