string, 'title' => string, 'description' => string, * 'after' => string (optional: the step id an add-on step follows), * 'view' => string (optional: absolute view path of an add-on step) ]. * The Pro add-on inserts its steps (Smart Config detection, the * telemetry opt-in) through `cachingout_wizard_steps`; see steps(). * * @since 0.1.0 * @since 1.21.0 Free steps only. * @var array */ const STEPS = array( array( 'id' => 'welcome', 'title' => 'Welcome', 'description' => 'Let\'s get your site running at peak performance.', ), array( 'id' => 'caching', 'title' => 'Caching', 'description' => 'Configure how pages are cached and served.', ), array( 'id' => 'media', 'title' => 'Media', 'description' => 'Optimize images, iframes, and lazy loading.', ), array( 'id' => 'optimization', 'title' => 'File Optimization', 'description' => 'Minify CSS and JavaScript.', ), array( 'id' => 'finish', 'title' => 'Ready!', 'description' => 'Your site is optimized and ready to go.', ), ); /** * Every wizard step: the free STEPS with the add-on's steps inserted. * * An add-on entry carrying `after` is placed right after that step id * (unknown ids append before the finish step); entries without it append * before the finish step too, so "Ready!" always closes the wizard. * * @since 1.21.0 * @return array[] */ public static function steps(): array { /** * Filter the wizard steps. Callbacks ADD entries; they must not * remove or reorder the free steps. * * @since 1.21.0 * * @param array[] $extra Add-on steps (empty by default). */ $extra = apply_filters( 'cachingout_wizard_steps', array() ); $steps = self::STEPS; if ( ! is_array( $extra ) ) { return $steps; } foreach ( $extra as $step ) { if ( ! is_array( $step ) || empty( $step['id'] ) ) { continue; } $after = isset( $step['after'] ) ? (string) $step['after'] : ''; $at = null; foreach ( $steps as $i => $existing ) { if ( '' !== $after && $existing['id'] === $after ) { $at = $i + 1; break; } } if ( null === $at ) { $at = max( 0, count( $steps ) - 1 ); } array_splice( $steps, $at, 0, array( $step ) ); } return $steps; } /** * Constructor. * * @since 0.1.0 * * @param CachingOut_Settings $settings Settings instance. */ public function __construct( CachingOut_Settings $settings ) { $this->settings = $settings; } /** * Register hooks: activation redirect and the step-save handler. * * @since 0.1.0 * @return void */ public function register() { add_action( 'admin_init', array( $this, 'maybe_redirect' ) ); add_action( 'admin_post_cachingout_wizard_save', array( $this, 'handle_wizard_save' ) ); } /** * Redirect to the wizard on first activation if not yet completed. * * @since 0.1.0 * @return void */ public function maybe_redirect() { // Only redirect on activation. if ( ! get_transient( 'cachingout_activation_redirect' ) ) { return; } delete_transient( 'cachingout_activation_redirect' ); // Don't redirect if already completed or during bulk activation. if ( get_option( self::COMPLETED_OPTION, false ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( isset( $_GET['activate-multi'] ) ) { return; } wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG ) ); exit; } /** * Set the activation redirect transient. * * Called by CachingOut_Activator on plugin activation. * * @since 0.1.0 * @return void */ public static function set_activation_redirect() { set_transient( 'cachingout_activation_redirect', true, 30 ); } /** * Enqueue wizard assets. * * @since 0.1.0 * @return void */ public function enqueue_assets() { // The same shell as the settings page: admin.css and admin.js, // nothing else (spec 35). CachingOut_Admin::enqueue_shell_assets(); /** * Fires after the wizard shell assets are enqueued. The Pro add-on * enqueues the assets of the steps it adds here. * * @since 1.21.0 * * @param string $step The step being rendered. */ do_action( 'cachingout_wizard_enqueue_assets', $this->get_current_step() ); } /** * Render the full wizard page. * * @since 0.1.0 * @return void */ public function render_wizard() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'cachingout' ) ); } $this->enqueue_assets(); $current_step = $this->get_current_step(); $step_index = $this->get_step_index( $current_step ); $all_settings = $this->settings->get_all(); $steps = self::steps(); ?>