array( 'moderate' => __( 'Prerender on hover (moderate)', 'ai-eshop-optimizer' ), 'conservative' => __( 'Prerender on pointer down (conservative)', 'ai-eshop-optimizer' ), 'eager' => __( 'Prerender eagerly', 'ai-eshop-optimizer' ), 'off' => __( 'Off', 'ai-eshop-optimizer' ), ), 'third_party' => array( 'delay' => __( 'Load after the first human interaction and consent', 'ai-eshop-optimizer' ), 'off' => __( 'Load as the plugins enqueue them', 'ai-eshop-optimizer' ), ), 'cart_mode' => array( 'blocks' => __( 'WooCommerce Cart block: shows after its scripts ran', 'ai-eshop-optimizer' ), 'classic' => __( 'Classic cart, rendered on the server: shows at once (fastest)', 'ai-eshop-optimizer' ), ), 'checkout_mode' => array( 'blocks' => __( 'WooCommerce Checkout block (some payment methods support only this one)', 'ai-eshop-optimizer' ), 'classic' => __( 'Classic checkout, rendered on the server: check that every payment method supports it', 'ai-eshop-optimizer' ), ), ); } private static function switches() { return array( 'device_variants' => __( 'One DOM per device: serve the -mobile template parts to phones (requires a cache that varies on Sec-CH-UA-Mobile or a separate mobile cache)', 'ai-eshop-optimizer' ), 'defer' => __( 'Deferred layer: regions marked "Load later" leave the first HTML and arrive after the first human interaction', 'ai-eshop-optimizer' ), 'inline_critical_css' => __( 'Inline small stylesheets: the base sheet when it is under 8 KB gzipped, and the local block and plugin sheets a page needs, up to 160 KB in total, so the first paint waits for no stylesheet', 'ai-eshop-optimizer' ), 'used_css' => __( 'Used CSS per page: visitors get only the style rules each page uses, inline; the full stylesheets follow at the first touch, scroll, key or pointer move (worked out on this site, kept in the uploads folder; for visitors who are not logged in)', 'ai-eshop-optimizer' ), 'defer_scripts' => __( 'Defer classic scripts: every script a plugin puts in the head loads with defer (WordPress keeps the ones that cannot be deferred blocking), and script modules load at low priority', 'ai-eshop-optimizer' ), 'delay_scripts' => __( 'Load plugin scripts after the first interaction: classic scripts wait for the first touch, scroll, key or pointer move and then run in order (not on the checkout, nor scripts that render the page with React)', 'ai-eshop-optimizer' ), 'delay_modules' => __( 'Load interactive blocks after the page: script modules (menus, galleries, add to cart, filters) load once the page has loaded or at the first interaction, which they then answer (not on the checkout)', 'ai-eshop-optimizer' ), 'trim_products_state' => __( 'Trim the products data of listings: on a shop, category or home page, the product data WooCommerce prints for its blocks keeps only what the add to cart buttons read (the full data comes with the rest of the page after the first interaction; product pages keep it whole)', 'ai-eshop-optimizer' ), ); } public function ajax_save() { AIEO_DMM::verify_ajax_request(); if ( ! class_exists( 'AIEO_Engine_Settings' ) ) { wp_send_json_error( array( 'message' => __( 'The performance engine runs under the Rooster Zero theme only.', 'ai-eshop-optimizer' ) ) ); } $before = AIEO_Engine_Settings::all(); $values = array(); foreach ( array_keys( self::switches() ) as $key ) { $values[ $key ] = ! empty( $_POST[ $key ] ); } foreach ( self::choices() as $key => $options ) { $v = isset( $_POST[ $key ] ) ? sanitize_key( wp_unslash( $_POST[ $key ] ) ) : ''; $values[ $key ] = isset( $options[ $v ] ) ? $v : $before[ $key ]; } $allow = isset( $_POST['third_party_allow'] ) ? (string) wp_unslash( $_POST['third_party_allow'] ) : ''; $values['third_party_allow'] = array_values( array_unique( array_filter( array_map( static function ( $line ) { return (string) preg_replace( '/[^A-Za-z0-9._\/-]/', '', trim( $line ) ); }, preg_split( '/\r\n|\r|\n|,/', $allow ) ) ) ) ); AIEO_Engine_Settings::save( $values ); if ( is_callable( array( '\Rooster\Core\UsedCss', 'clear' ) ) ) { \Rooster\Core\UsedCss::clear(); } do_action( 'aieo_purge_page_cache' ); wp_send_json_success( array( 'message' => __( 'Performance settings saved.', 'ai-eshop-optimizer' ) ) ); } public function render_subtab() { if ( ! class_exists( 'AIEO_Engine_Settings' ) ) { list( $open, $close ) = AIEO_DMM_UI::card( array( 'icon' => 'gauge', 'title' => $this->get_label() ) ); echo $open; echo \Rooster\Admin\Ui::notice( esc_html__( 'The performance engine runs under the Rooster Zero theme only. With another theme, its caching and optimisation plugins do this work.', 'ai-eshop-optimizer' ), 'info', array( 'inline' => true ) ); echo $close; return; } $s = AIEO_Engine_Settings::all(); $row = static function ( $name, $label, $control, $help = '' ) { return \Rooster\Admin\Ui::field_row( array( 'id' => 'aieo-perf-' . str_replace( '_', '-', $name ), 'label' => $label, 'control' => $control, 'help' => $help ) ); }; $switch = static function ( $name, $text ) use ( $s ) { return \Rooster\Admin\Ui::toggle( $name, ! empty( $s[ $name ] ), array( 'id' => 'aieo-perf-' . str_replace( '_', '-', $name ), 'hidden' => false, 'label' => $text ) ); }; $choices = self::choices(); $select = static function ( $name ) use ( $s, $choices ) { return \Rooster\Admin\Ui::select( $name, $choices[ $name ], (string) $s[ $name ], array( 'id' => 'aieo-perf-' . str_replace( '_', '-', $name ) ) ); }; $switches = self::switches(); $card = static function ( $anchor, $icon, $title, $col, $fields, $extra = array() ) { $form_id = 'aieo-card-' . $anchor . '-form'; list( $open, $close ) = AIEO_DMM_UI::card( array( 'anchor' => $anchor, 'icon' => $icon, 'title' => $title, 'col' => $col, 'footer' => class_exists( '\Rooster\Admin\States' ) ? \Rooster\Admin\States::save_button( $form_id ) : '', ) + $extra ); echo $open; echo AIEO_DMM_UI::card_form( 'aieo_dmm_performance_save', 'performance', $form_id, '