' . $printblob_notice . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in not_designable_notice(). } return; } $printblob_attr_terms = static function ( \WC_Product $product, string $taxonomy ): array { $terms = wc_get_product_terms( $product->get_id(), $taxonomy, array( 'fields' => 'all' ) ); return is_wp_error( $terms ) ? array() : $terms; }; $printblob_colors = array_map( static fn( \WP_Term $term ) => array( 'slug' => $term->slug, 'name' => $term->name, 'hex' => Shirt_Colors::get_hex( $term->term_id ), ), $printblob_attr_terms( $printblob_product, Shirt_Colors::taxonomy() ) ); $printblob_sizes = array_map( static fn( \WP_Term $term ) => array( 'slug' => $term->slug, 'name' => $term->name, ), $printblob_attr_terms( $printblob_product, Settings::size_attribute() ) ); $printblob_variations = array(); if ( $printblob_product->is_type( 'variable' ) ) { foreach ( $printblob_product->get_children() as $printblob_child_id ) { $printblob_variation = wc_get_product( $printblob_child_id ); if ( ! $printblob_variation || ! $printblob_variation->is_purchasable() ) { continue; } $printblob_variations[] = array( 'id' => $printblob_variation->get_id(), 'attributes' => $printblob_variation->get_variation_attributes(), 'price' => (float) wc_get_price_to_display( $printblob_variation ), 'inStock' => $printblob_variation->is_in_stock(), ); } } $printblob_sides = array(); foreach ( Product_Settings::offered_sides( $printblob_product ) as $printblob_side => $printblob_spec ) { $printblob_sides[] = array( 'key' => $printblob_side ) + $printblob_spec; } $printblob_fonts = Designer_Data::fonts(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only prefill from the home page. $printblob_initial_text = isset( $_GET['text'] ) ? sanitize_text_field( wp_unslash( $_GET['text'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only preselection from colour links. $printblob_initial_color = isset( $_GET['color'] ) ? sanitize_title( wp_unslash( $_GET['color'] ) ) : ''; if ( ! in_array( $printblob_initial_color, array_column( $printblob_colors, 'slug' ), true ) ) { $printblob_initial_color = ''; } // The product name's heading level: the block's own setting, else the page's (Product_Settings::heading_level()). $printblob_heading = isset( $attributes['headingLevel'] ) ? (int) $attributes['headingLevel'] : Product_Settings::heading_level( $printblob_product ); $printblob_heading = max( 1, min( 6, $printblob_heading ) ); $printblob_config = array( 'productId' => $printblob_product->get_id(), 'productName' => $printblob_product->get_name(), 'headingLevel' => $printblob_heading, 'basePrice' => (float) wc_get_price_to_display( $printblob_product ), 'colors' => array_values( $printblob_colors ), 'sizes' => array_values( $printblob_sizes ), 'variations' => $printblob_variations, 'sides' => $printblob_sides, 'fonts' => $printblob_fonts, 'initialText' => mb_substr( $printblob_initial_text, 0, Designer_Data::numbers()['initial_text_max'] ), 'initialColor' => $printblob_initial_color, 'attributes' => array( 'color' => Shirt_Colors::taxonomy(), 'size' => Settings::size_attribute(), ), 'maxUploadBytes' => Settings::max_upload_bytes(), 'maxPostBytes' => Settings::max_post_bytes(), // The customer's images go with the design, as they uploaded them (Design_Store keeps them with the order). 'sendUploads' => true, // Views other plugins add beside the sides (key and label), through printblob_designer_config. 'views' => array(), // Tools other plugins add beside Upload image and Add text (key and label), through printblob_designer_config. 'tools' => array(), // Choices beyond colour and size that other plugins offer, through printblob_designer_config: each a variation // attribute (field: `attribute_pa_material`; attribute: its name as the cart takes it; label; choices of value // and name), shown under Size and sent to the cart with the others. 'options' => array(), 'currency' => array( 'code' => get_woocommerce_currency(), 'symbol' => html_entity_decode( get_woocommerce_currency_symbol(), ENT_QUOTES ), 'position' => get_option( 'woocommerce_currency_pos', 'left' ), 'decimals' => wc_get_price_decimals(), 'decimal' => wc_get_price_decimal_separator(), 'thousand' => wc_get_price_thousand_separator(), ), 'endpoints' => array( 'designs' => esc_url_raw( rest_url( Design_Store::REST_NAMESPACE . Design_Store::REST_ROUTE ) ), 'storeApi' => esc_url_raw( rest_url( 'wc/store/v1/' ) ), 'cart' => esc_url_raw( wc_get_cart_url() ), ), ); /** * Filters the designer's configuration before the page is rendered. A plugin adds a view here (`views`: its * key and label, shown as a button beside the sides, and `initial` => true to open the designer on it where the * browser can show it) with the data the view needs; the view itself registers on the `printblob.designer.views` * JavaScript filter of @wordpress/hooks. A tool is added the same way (`tools`: key and label, shown as a button * beside Upload image and Add text), its panel registered on the `printblob.designer.tools` filter * (src/designer/app/tools.ts). A choice beyond colour and size is added to `options` (see above); the designer * shows it and the cart finds the variation from every choice. * * @param array $printblob_config The designer's configuration. * @param \WC_Product $printblob_product The product being designed. */ $printblob_config = (array) apply_filters( 'printblob_designer_config', $printblob_config, $printblob_product ); // The "3D · Pro" link, for a shop manager while PrintBlob Pro is not active: decided here, so customers' pages never carry it. $printblob_pro_chip = Pro::storefront_chip(); if ( $printblob_pro_chip ) { $printblob_config['proChip'] = $printblob_pro_chip; } // A variation that depends on an attribute the designer doesn't offer could only be ordered as the wrong one. $printblob_offered = array_merge( array( 'attribute_' . sanitize_title( Shirt_Colors::taxonomy() ), 'attribute_' . sanitize_title( Settings::size_attribute() ) ), array_column( (array) ( $printblob_config['options'] ?? array() ), 'field' ) ); $printblob_unoffered = array(); foreach ( $printblob_variations as $printblob_variation_entry ) { foreach ( $printblob_variation_entry['attributes'] as $printblob_field => $printblob_value ) { if ( '' !== $printblob_value && ! in_array( $printblob_field, $printblob_offered, true ) ) { $printblob_unoffered[ $printblob_field ] = wc_attribute_label( substr( $printblob_field, strlen( 'attribute_' ) ), $printblob_product ); } } } if ( $printblob_unoffered ) { if ( current_user_can( 'edit_products' ) ) { echo '' . esc_html( sprintf( /* translators: %s: attribute names, such as Material. */ __( 'The designer can’t show this product: its variations also depend on %s, which the designer doesn’t offer. Set it to “Any” in every variation, or stop using it for variations.', 'printblob' ), implode( ', ', $printblob_unoffered ) ) ) . '
'; } return; } $printblob_wrapper = get_block_wrapper_attributes( array( 'class' => 'printblob-designer', 'data-testid' => 'printblob-designer', 'data-printblob-config' => wp_json_encode( $printblob_config ), ) ); ?>