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;
}
}