sanitize_text_field( wp_unslash( $_POST['set_name'] ?? '' ) ), 'kind' => sanitize_text_field( wp_unslash( $_POST['set_kind'] ?? 'choices' ) ), 'shape' => sanitize_text_field( wp_unslash( $_POST['set_shape'] ?? '' ) ), 'pin_chips' => ! empty( $_POST['set_pin_chips'] ), 'show_stock' => addon_boss_option_stock_enabled() ? ! empty( $_POST['set_show_stock'] ) : null, 'multi' => '1' === sanitize_text_field( wp_unslash( $_POST['set_multi'] ?? '' ) ), 'min' => absint( $_POST['set_min'] ?? 0 ), 'max' => absint( $_POST['set_max'] ?? 0 ), 'options' => $rows, ); // Each registered kind reads its own panel's fields off the form, exactly // as the real save does. foreach ( addon_boss_option_set_kinds() as $bb_spec ) { if ( is_callable( $bb_spec['collect'] ?? null ) ) { $bb_raw = array_merge( $bb_raw, (array) call_user_func( $bb_spec['collect'] ) ); } } return $bb_raw; } // ----------------------------------------------------------------- // The panel, printed under the set editor form. // ----------------------------------------------------------------- function addon_boss_set_preview_panel(): void { ?>

__( 'Sorry, you are not allowed to do that.', 'addon-boss' ) ), 403 ); } $mode = sanitize_key( wp_unslash( $_POST['bb_epv_mode'] ?? 'draft' ) ); $sid = sanitize_text_field( wp_unslash( $_POST['set_id'] ?? '' ) ); if ( 'saved' === $mode ) { if ( '' === $sid || ! addon_boss_option_set( $sid ) ) { wp_send_json_error( array( 'message' => __( 'Save the option set once and its saved state previews here.', 'addon-boss' ) ) ); } $render_id = $sid; } else { // The serialized form IS the save contract: the same assembly and // sanitiser the real save runs, overlaid on the store for one read. $draft = addon_boss_sanitize_option_set( addon_boss_option_set_from_form() ); $draft['id'] = '' !== $sid ? $sid : 'bb-preview-draft'; $render_id = $draft['id']; $overlay = addon_boss_option_sets(); $overlay[ $render_id ] = $draft; add_filter( 'pre_option_' . ADDON_BOSS_OPTION_SETS_STORE, static function () use ( $overlay ) { return $overlay; } ); } // A throwaway in-memory product carries the set; nothing has an id and // nothing is saved. Purchasability is forced for the render only, because // an unsaved product can never pass the real check. $bb_product = new WC_Product_Simple(); $bb_product->set_name( __( 'Your product', 'addon-boss' ) ); $bb_product->set_regular_price( '25' ); $bb_product->set_price( '25' ); $bb_product->update_meta_data( ADDON_BOSS_PRODUCT_OPTIONS_META, // The full attachment row shape the resolver expects: no per-product // overrides, nothing hidden — the set previews exactly as stored. array( array( 'set' => $render_id, 'deltas' => array(), 'images' => array(), 'hide' => array(), ), ) ); add_filter( 'woocommerce_is_purchasable', '__return_true' ); $prev_global = $GLOBALS['product'] ?? null; $GLOBALS['product'] = $bb_product; ob_start(); addon_boss_render_standalone_options(); $component = (string) ob_get_clean(); $GLOBALS['product'] = $prev_global; remove_filter( 'woocommerce_is_purchasable', '__return_true' ); if ( '' === trim( $component ) ) { wp_send_json_error( array( 'message' => __( 'Add an option to see the preview.', 'addon-boss' ) ) ); } wp_send_json_success( array( 'html' => addon_boss_set_preview_document( $component ) ) ); } /** * A self-contained iframe document: the storefront stylesheet inlined (a * linked sheet cannot be enqueued into srcdoc), live controls muted. */ function addon_boss_set_preview_document( string $component ): string { // Every image loads NOW: lazy-loading inside a short iframe defers // anything below its fold forever, which reads as broken photos. $component = str_replace( ' loading="lazy"', ' loading="eager"', $component ); $css = (string) @file_get_contents( ADDON_BOSS_PATH . 'css/options.css' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- a missing stylesheet degrades to an unstyled preview, never an error page. $doc = ''; $doc .= ''; $doc .= ''; $doc .= ''; $doc .= '
'; $doc .= $component; $doc .= '
' . esc_html__( 'This is a preview of how the options look. Prices and Add to cart run on the product pages this set is attached to.', 'addon-boss' ) . '
'; $doc .= '
'; return $doc; }