Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@markjaquith
Created September 11, 2022 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markjaquith/f21566334133d2843598c064e76f1142 to your computer and use it in GitHub Desktop.
Save markjaquith/f21566334133d2843598c064e76f1142 to your computer and use it in GitHub Desktop.
Proof of concept alloptions optimizer
<?php
/**
* Plugin Name: Alloptions Optimizer
* Author: Mark Jaquith
*/
class AllOptionsOptimizer {
private static $usedOptions = [];
private static $allOptions = [];
private static $allOptionsBytes;
const LAST_RUN_TIMESTAMP = 'alloptions_optimizer_last_run';
const RUN_EVERY = WEEK_IN_SECONDS;
public static function init() {
$allOptions = wp_load_alloptions();
self::$allOptionsBytes = strlen(implode('', $allOptions));
self::$allOptions = array_keys($allOptions);
add_action('all', [self::class, 'monitorOptions']);
add_action('wp_footer', [self::class, 'showStats']);
if (self::isOptimizing()) {
add_action('shutdown', [self::class, 'saveResults']);
}
}
private static function shouldBeOptimized() {
if (defined('WP_CLI') && WP_CLI) {
return false;
}
if (defined('DOING_CRON') && DOING_CRON) {
return false;
}
if (defined('DOING_AJAX') && DOING_AJAX) {
return false;
}
if (is_admin()) {
return false;
}
$lastRun = get_transient(self::LAST_RUN_TIMESTAMP) ?: 0;
return (time() - $lastRun) > self::RUN_EVERY;
}
private static function isOptimizing() {
return self::userWantsToOptimize() || self::shouldBeOptimized();
}
private static function userWantsToOptimize() {
return isset($_GET['alloptions']) && $_GET['alloptions'];
}
private static function usingOption($option) {
self::$usedOptions[$option] = true;
if (!self::isOptimizing() && !self::isAutoloadedOption($option)) {
self::makeOptionsAutoloaded([$option]);
}
}
public static function monitorOptions($filter) {
if (strpos($filter, 'option_') !== 0) {
return;
}
$option = substr($filter, 7);
if (strpos($option, '_transient_') === 0 || strpos($option, '_site_transient_') === 0) {
return;
}
self::usingOption($option);
}
private static function isAutoloadedOption($option) {
return in_array($option, self::$allOptions, true);
}
private static function getUnusedOptions() {
return array_diff(self::$allOptions, array_keys(self::$usedOptions));
}
private static function makeOptionsNotAutoloaded($optionNames) {
return self::makeOptionsAutoloaded($optionNames, false);
}
private static function makeOptionsAutoloaded($optionNames, $autoload = true) {
global $wpdb;
$autoload = $autoload ? 'yes' : 'no';
$optionNames = array_map(fn ($option) => "\"$option\"", $optionNames);
$optionNames = implode(',', $optionNames);
$wpdb->query(sprintf("UPDATE $wpdb->options SET autoload = '%s' WHERE option_name IN(%s)", $autoload, $optionNames));
}
public function wasUsed($option) {
return isset(self::$usedOptions[$option]);
}
public static function showStats() {
echo "<div style='display: flex; align-content: center'><div style='display: inline-block; border: 1px solid black; padding: 10px; margin: 10px auto;'>";
echo "<p id='alloptions' style='text-align: center'>WordPress used " . count(self::$usedOptions) . " of " . count(self::$allOptions) . " autoloaded options.</p>";
echo "<p id='alloptions' style='text-align: center'>autoloaded options are " . round(self::$allOptionsBytes/1024) . " KB</p>";
if (!self::isOptimizing()) {
echo "<p style='text-align: center'><a href='/?alloptions=1#alloptions'>Optimize Now</a></p>";
}
echo "</div></div>";
if (self::userWantsToOptimize()) {
echo "<script>window.location = window.location.href.replace(/alloptions=1/, '');</script>";
}
}
public static function saveResults() {
// Make unused options not be autoloaded.
self::makeOptionsNotAutoloaded(self::getUnusedOptions());
// Update the timestamp.
set_transient(self::LAST_RUN_TIMESTAMP, time(), time());
}
}
AllOptionsOptimizer::init();
@markjaquith
Copy link
Author

substr is probably faster. We have to bail ASAP on the all hook.

@markjaquith
Copy link
Author

My set_transient TTL is wrong. Should be self::RUN_EVERY

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment