> Argument schemas. */ public static function import_args(): array { return [ 'settings' => [ 'type' => 'object', 'required' => true, 'validate_callback' => 'rest_validate_request_arg', ], ]; } /** * What the plugin can tell about the site it is installed on. * * The detection is memoized per request and a write may already have * happened in this one — the wizard saving a step and then asking what * changed — so it is dropped before being read. * * @return array Detection result. */ public function environment(): array { Environment::reset(); return Environment::detect(); } /** * Drops every cached file and asks for the rewrite rules to be rebuilt. * * Deliberately sets `acid_aeo_flush_needed` instead of calling * `flush_rewrite_rules()` here, and this is the correction of the obvious * reading, not an oversight. A module that was switched off when the plugin * booted never ran `register()`, so it added no file to `Endpoints\Router` * and no rewrite rule on this request. Flushing now would compute the rule * set from what happens to be registered and persist that as the truth — * writing the missing rules out of existence at the exact moment an * administrator pressed the button that was meant to bring them back. * `Plugin::maybe_flush_rewrites()` flushes on the next `init`, by which * time every enabled module has registered. * * @return array Key `ok`. */ public function flush_cache(): array { Cache::invalidate_all(); Loopback::flush(); Controller::forget_derived_data(); update_option( Controller::FLUSH_OPTION, 1 ); return [ 'ok' => true ]; } /** * Writes the generated files to disk, when that module is installed. * * @return array|WP_Error Key `result`, or a 501 while the module does not exist. */ public function write_static_files() { if ( ! class_exists( self::STATIC_FILES ) || ! method_exists( self::STATIC_FILES, 'write_all' ) ) { return new WP_Error( 'acid_aeo_unavailable', __( 'Writing static files is not available in this version.', 'acid-aeo' ), [ 'status' => 501 ] ); } $module = Controller::module( 'static_files', self::STATIC_FILES ); if ( null === $module ) { return new WP_Error( 'acid_aeo_unavailable', __( 'Writing static files is not available in this version.', 'acid-aeo' ), [ 'status' => 501 ] ); } return [ 'result' => $module->write_all() ]; } /** * Every setting, in a shape `POST /import` accepts back. * * Static so that `wp acid-aeo export` writes the same envelope this route * returns rather than a second one that could drift from it. WordPress * calls it through `[ $tools, 'export' ]` either way. * * @return array Keys `version`, `exported_at` and `settings`. */ public static function export(): array { return [ 'version' => ACID_AEO_VERSION, 'exported_at' => gmdate( 'c' ), 'settings' => Options::all(), ]; } /** * Replaces every setting with an exported file. * * `Options::set_all()` sanitizes against the schema, so an export from an * older version, or one edited by hand, cannot store a value the settings * screen could not have produced. * * @param WP_REST_Request $request The request. * @return array|WP_Error Key `settings`, or a 400. */ public function import( WP_REST_Request $request ) { $settings = $request->get_param( 'settings' ); if ( ! is_array( $settings ) || [] === $settings ) { return new WP_Error( 'acid_aeo_invalid_import', __( 'Send the settings object from an export file.', 'acid-aeo' ), [ 'status' => 400 ] ); } Options::set_all( $settings ); Loopback::flush(); Controller::forget_derived_data(); // An import can switch any module on or off, so the rules are rebuilt // on the next `init` whatever the file happened to contain. update_option( Controller::FLUSH_OPTION, 1 ); return [ 'settings' => Options::all() ]; } /** * Everything a support request needs, in one response. * * @return array Versions, environment, plugins, theme, files and rewrite state. */ public function system_info(): array { $theme = wp_get_theme(); return [ 'plugin' => ACID_AEO_VERSION, 'php' => PHP_VERSION, 'wp' => get_bloginfo( 'version' ), 'environment' => Environment::detect(), 'active_plugins' => self::active_plugins(), 'theme' => [ 'name' => (string) $theme->get( 'Name' ), 'version' => (string) $theme->get( 'Version' ), ], 'file_urls' => SiteData::file_urls(), 'files' => Router::files(), 'rewrite' => [ 'permalink_structure' => (string) get_option( 'permalink_structure', '' ), 'flush_needed' => (bool) get_option( Controller::FLUSH_OPTION ), ], ]; } /** * The name and version of every active plugin. * * `get_plugins()` lives in an admin file the REST request has not loaded. * * @return array Plugin names, alphabetically. */ private static function active_plugins(): array { if ( ! function_exists( 'get_plugins' ) || ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $names = []; foreach ( get_plugins() as $file => $data ) { if ( ! is_plugin_active( (string) $file ) ) { continue; } $name = trim( (string) ( $data['Name'] ?? '' ) ); $version = trim( (string) ( $data['Version'] ?? '' ) ); if ( '' === $name ) { continue; } $names[] = '' !== $version ? $name . ' ' . $version : $name; } sort( $names ); return $names; } }