*/ private static function primeable(): array { $names = array( // Settings blobs, one per module with a front-end surface. 'airanksuite_ai_settings', 'airanksuite_ai_visibility_settings', 'airanksuite_analytics_settings', 'airanksuite_audit_alerts_settings', 'airanksuite_coexistence_settings', 'airanksuite_core_settings', 'airanksuite_crawler_controls_settings', 'airanksuite_feeds_settings', 'airanksuite_google_settings', 'airanksuite_hardening_settings', 'airanksuite_image_seo_settings', 'airanksuite_indexnow_settings', 'airanksuite_llms_txt_settings', 'airanksuite_local_seo_settings', 'airanksuite_redirects_settings', 'airanksuite_reports_settings', 'airanksuite_robots_settings', 'airanksuite_schema_settings', 'airanksuite_search_console_settings', 'airanksuite_seo_settings', 'airanksuite_sitemap_settings', 'airanksuite_social_settings', 'airanksuite_woocommerce_settings', // The schema version, and the key it was stored under up to 0.2.35: // Migrator::adopt_legacy() asks for both on every request. 'airanksuite_db_version', 'airs_db_version', // Bare options read outside the settings pattern. 'airanksuite_disabled_modules', 'airanksuite_snippets', 'airanksuite_snippet_running', // Transients with fixed names. Without a persistent object cache a // transient is two option reads, so the ones the front end always // touches belong in this query too. '_transient_timeout_airanksuite_redirect_shape', '_transient_airanksuite_redirect_shape', ); /** * Filter the options primed in a single query on each request. * * @param array $names Option names. */ return (array) apply_filters( 'airanksuite/options/prime', $names ); } /** * Fetch the whole set in one query and leave it in the object cache. * * Safe to call more than once — WordPress only queries the names it does * not already have cached, so the second call costs nothing. Also safe on a * site with a persistent object cache, where it usually costs nothing at * all. */ public static function prime( bool $force = false ): void { static $done = false; if ( ! function_exists( 'wp_prime_option_caches' ) || ( $done && ! $force ) ) { return; } $done = true; wp_prime_option_caches( self::primeable() ); } /** * Read a module's settings merged over defaults. * * @param string $module Module id. * @param array $defaults Default values. * @return array */ public function get( string $module, array $defaults = array() ): array { $stored = get_option( "airanksuite_{$module}_settings", array() ); if ( ! is_array( $stored ) ) { $stored = array(); } return array_merge( $defaults, $stored ); } /** * Persist a module's settings (only known keys survive). * * @param string $module Module id. * @param array $values New values. * @param array $defaults Allowed keys with defaults. */ public function set( string $module, array $values, array $defaults ): void { $clean = array_intersect_key( $values, $defaults ); $current = $this->get( $module, $defaults ); $next = array_merge( $current, $clean ); update_option( "airanksuite_{$module}_settings", $next, false ); /* * A saved setting that nobody can see is not saved. * * Nearly every setting here changes what a visitor is served — a title * template, a schema block, the robots line, the cookie banner. On a * cached site the old page keeps being served until the cache is * cleared, so the customer changes a setting, looks at the front end, * sees no difference and concludes the plugin is broken. * * Only when something actually changed: saving a form without editing * it should not throw away a site's whole page cache. */ if ( $next !== $current ) { Cache::purge(); } } }