has_cap('manage_options')) { return false; } } return true; } /** * @param string $option - The option being written. * @return boolean */ private static function exempt($option) { // Core's transients and WPForms' own copy of them are cache entries, which escalate nothing. foreach (['_transient_', '_site_transient_', '_wpforms_transient_'] as $cache) { if (strpos($option, $cache) === 0) { return true; } } // A tool that writes settings names them for the duration of its own call. if (in_array($option, self::$permitted, true)) { return true; } // Core writes these as it registers a user, publishes a post or renders a calendar, // and WPForms as it saves a form, or its abilities abort with the form half-written. $caches = [ 'user_count', 'fresh_site', 'wp_calendar_block_has_published_posts', 'wpforms_dashboard_cache_generation', 'wpforms_forms_first_created', ]; if (in_array($option, $caches, true)) { return true; } // set_auto_updates writes these, and an update schedule grants nothing either. if (in_array($option, ['auto_update_plugins', 'auto_update_themes'], true)) { return true; } // Jobs::start() schedules here, and a cron event runs only code the site already hooks. if ($option === 'cron') { return true; } // A term write rebuilds this cache, and a term cache escalates nothing. return substr($option, -9) === '_children' && \is_taxonomy_hierarchical(substr($option, 0, -9)); } /** * @param string $option - The option refused. * @return string */ private static function optionMessage($option) { return sprintf('Changing the %s option is not something a connection may do.', $option); } /** * A network keeps one capabilities row per site, prefixed with that site's id. * * @return string */ private static function capabilitiesKey() { return '/^' . preg_quote($GLOBALS['wpdb']->base_prefix, '/') . '(\d+_)?capabilities$/'; } }