next_tag() ) { if ( 'SOURCE' === $processor->get_tag() ) { $type = $processor->get_attribute( 'type' ); $srcset = $processor->get_attribute( 'srcset' ); if ( ! in_array( $type, array( 'image/webp', 'image/avif', 'image/jpeg', 'image/png' ), true ) || ! is_string( $srcset ) ) { return array(); } $sources[] = array( 'type' => $type, 'srcset' => $srcset, 'sizes' => (string) ( $processor->get_attribute( 'sizes' ) ?? '' ), ); } elseif ( 'IMG' === $processor->get_tag() ) { foreach ( array( 'src', 'srcset', 'sizes' ) as $key ) { $native[ $key ] = (string) ( $processor->get_attribute( $key ) ?? '' ); } if ( $processor->get_attribute( 'data-src' ) === $processor->get_attribute( 'data-large_image' ) ) { $zoom = (string) ( $processor->get_attribute( 'data-src' ) ?? '' ); } } } return $sources && ! empty( $native['src'] ) ? array( 'native' => $native, 'sources' => $sources, 'zoom' => $zoom, ) : array(); } /** * Put the plan on the picture element, for the gallery script. * * @param string $html The picture element. * @param bool $defer True to leave out the source elements until the gallery script has loaded (variable products). * @return string The element, with its plan. */ public static function decorate( string $html, bool $defer = false ): string { $plan = self::plan( $html ); if ( ! $plan ) { return $html; } $processor = new \WP_HTML_Tag_Processor( $html ); if ( $processor->next_tag( 'PICTURE' ) ) { $processor->set_attribute( 'data-afsd-im-woo', wp_json_encode( $plan, JSON_UNESCAPED_SLASHES ) ); } $out = $processor->get_updated_html(); // Variable sources are activated only by a successfully loaded coordinator. return $defer ? preg_replace( '/]*>/i', '', $out ) : $out; } /** * Whether a product's variation data may carry copies: delivery on with the public-pictures confirmation, a single * site, a public product, not cron or REST, and either a request Image Manager delivers on or WooCommerce's public * get_variation request. * * @param int $product The product. * @return bool True when it may. */ public static function data_allowed( int $product ): bool { $s = Settings::get(); if ( ! $s['delivery'] || ! $s['public_policy'] || is_multisite() || wp_doing_cron() || ! Sources::public_post( $product ) || 'product' !== get_post_type( $product ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { return false; } if ( Delivery::allowed() ) { return true; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only classification of WooCommerce public variation delivery; the owning endpoint controls its request and no settings are changed here. $action = isset( $_GET['wc-ajax'] ) && is_string( $_GET['wc-ajax'] ) ? sanitize_key( wp_unslash( $_GET['wc-ajax'] ) ) : ''; $method = isset( $_SERVER['REQUEST_METHOD'] ) && is_string( $_SERVER['REQUEST_METHOD'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) : ''; // WooCommerce's public variation endpoint owns selection and permissions. return 'get_variation' === $action && 'POST' === $method; } /** * Add the copies of a variation's picture to WooCommerce's variation data. * * @param mixed $data The variation data. * @param mixed $product The variable product. * @param mixed $variation The variation. * @return mixed The variation data. */ public static function variation( $data, $product, $variation ) { if ( ! is_array( $data ) || ! is_object( $product ) || ! method_exists( $product, 'get_id' ) || ! self::data_allowed( (int) $product->get_id() ) ) { return $data; } $plans = array(); $image = $data['image'] ?? array(); if ( is_array( $image ) && ! empty( $image['src'] ) && is_string( $image['src'] ) && self::$plans < 80 ) { $html = 'get_id() ); ++self::$plans; if ( $plan ) { $plans[] = $plan; } } // WooCommerce 10.9+ can replace the entire classic gallery. Inspect only its // bounded, already-rendered image markup, not arbitrary product metadata. $gallery = $data['gallery_images_html'] ?? ''; if ( is_string( $gallery ) && strlen( $gallery ) <= 131072 && preg_match_all( '/]*>/i', $gallery, $matches ) ) { foreach ( array_slice( $matches[0], 0, 16 ) as $html ) { if ( self::$plans >= 80 ) { break; } $plan = Delivery::variation_plan( $html, 0, (int) $product->get_id() ); ++self::$plans; if ( $plan ) { $plans[] = $plan; } } } if ( $plans ) { $data['afsd_im_display_plans'] = $plans; } return $data; } }