is_type( 'variable' ) && '1' === (string) $product->get_meta( self::META ); } /** * Scripts, enqueued only where the button is shown. */ public static function register_assets() { wp_register_style( 'eazign', EAZIGN_URL . 'assets/css/frontend.css', array(), EAZIGN_VERSION ); wp_register_script( 'eazign-loader', EAZIGN_URL . 'assets/js/loader.js', array(), EAZIGN_VERSION, true ); wp_localize_script( 'eazign-loader', 'eazignData', array( 'configUrl' => esc_url_raw( rest_url( 'eazign/v1/config' ) ), 'cartUrl' => esc_url_raw( WC_AJAX::get_endpoint( 'eazign_add_to_cart' ) ), 'nonce' => wp_create_nonce( 'eazign_cart' ), 'locale' => substr( get_locale(), 0, 2 ), 'error' => __( 'The designer could not be loaded. Please try again later.', 'eazign' ), ) ); // Styles in the head on designer product pages (no flash of the normal button). if ( is_product() && Eazign_Client::is_connected() && self::is_designer_product( wc_get_product( get_queried_object_id() ) ) ) { wp_enqueue_style( 'eazign' ); } } /** * Classic add-to-cart form. */ public static function print_in_form() { global $product; echo self::markup( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in markup(). } /** * Block themes: after the add-to-cart block (if the form hook did not run). * * @param string $content Block HTML. * @param array $block Block. * @return string */ public static function append_to_block( $content, $block ) { $product = wc_get_product( get_the_ID() ); return $content . self::markup( $product ); } /** * Shortcode [eazign_designer id="123"]. * * @param array $atts Attributes. * @return string */ public static function shortcode( $atts ) { $atts = shortcode_atts( array( 'id' => get_the_ID() ), $atts, 'eazign_designer' ); return self::markup( wc_get_product( (int) $atts['id'] ) ); } /** * Button and product data for the loader. * * @param WC_Product|null $product Product. * @return string */ public static function markup( $product ) { if ( ! self::is_designer_product( $product ) || ! Eazign_Client::is_connected() || isset( self::$printed[ $product->get_id() ] ) ) { return ''; } self::$printed[ $product->get_id() ] = true; wp_enqueue_style( 'eazign' ); wp_enqueue_script( 'eazign-loader' ); return sprintf( '', $product->get_id(), esc_html__( 'Design now', 'eazign' ), esc_html__( 'Add your text, images and motifs – we print exactly what you see.', 'eazign' ), wp_json_encode( self::product_json( $product ), JSON_HEX_TAG | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE ) ); } /** * Product in the format the editor expects (options and variants with * option values in attribute order, prices in cents as displayed). * * @param WC_Product_Variable $product Product. * @return array */ public static function product_json( $product ) { $attributes = $product->get_variation_attributes(); $names = array_keys( $attributes ); $variants = array(); foreach ( $product->get_children() as $child_id ) { $variation = wc_get_product( $child_id ); if ( ! $variation || ! $variation->exists() || 'publish' !== $variation->get_status() ) { continue; } $values = array(); $chosen = $variation->get_variation_attributes(); foreach ( $names as $name ) { $value = $chosen[ 'attribute_' . sanitize_title( $name ) ] ?? ''; $values[] = taxonomy_exists( $name ) && $value ? ( get_term_by( 'slug', $value, $name )->name ?? $value ) : $value; } $variants[] = array( 'id' => $variation->get_id(), 'title' => implode( ' / ', $values ), 'options' => $values, 'price' => (int) round( (float) wc_get_price_to_display( $variation ) * 100 ), 'available' => $variation->is_purchasable() && $variation->is_in_stock(), ); } return array( 'id' => $product->get_id(), 'title' => $product->get_name(), 'options' => array_map( function ( $name ) use ( $product ) { return wc_attribute_label( $name, $product ); }, $names ), 'variants' => $variants, 'currency' => get_woocommerce_currency(), ); } /** * REST route for the loader. */ public static function routes() { register_rest_route( 'eazign/v1', '/config', array( 'methods' => 'GET', 'permission_callback' => '__return_true', 'callback' => array( __CLASS__, 'config' ), 'args' => array( 'product' => array( 'required' => true, 'sanitize_callback' => 'absint', ), ), ) ); } /** * Editor configuration of a product (cached briefly; it carries a * storefront token valid for six hours). * * @param WP_REST_Request $request Request. * @return WP_REST_Response */ public static function config( $request ) { $product = wc_get_product( (int) $request['product'] ); // Public endpoint: only published, non-protected designer products. if ( ! self::is_designer_product( $product ) || 'publish' !== $product->get_status() || post_password_required( $product->get_id() ) || ! Eazign_Client::is_connected() ) { return rest_ensure_response( array( 'enabled' => false ) ); } $key = 'eazign_config_' . $product->get_id(); $config = get_transient( $key ); if ( ! is_array( $config ) ) { $config = Eazign_Client::get( 'config?product=' . $product->get_id() ); if ( is_wp_error( $config ) ) { return rest_ensure_response( array( 'enabled' => false ) ); } set_transient( $key, $config, 10 * MINUTE_IN_SECONDS ); } $response = rest_ensure_response( $config ); $response->header( 'Cache-Control', 'no-store' ); return $response; } }