post_content, 'get_attribute( 'src' ); $own = null !== $p->get_attribute( 'width' ) && null !== $p->get_attribute( 'height' ); if ( $own || ! is_string( $src ) || ! preg_match( '#^(https?:)?//[^/]#i', trim( $src ) ) || preg_match( '/(?:^|\s)wp-image-\d+(?:\s|$)/', (string) $p->get_attribute( 'class' ) ) ) { return ''; } return trim( $src ); }; $urls = array(); $p = new WP_HTML_Tag_Processor( $html ); while ( $p->next_tag( 'IMG' ) ) { $url = $named( $p ); if ( '' !== $url ) { $urls[] = $url; } } if ( ! $urls ) { return $html; } $known = self::media( $urls ); $p = new WP_HTML_Tag_Processor( $html ); while ( $p->next_tag( 'IMG' ) ) { $url = $named( $p ); $file = '' !== $url ? ( $known[ $url ] ?? 0 ) : 0; if ( is_int( $file ) && $file > 0 ) { $p->add_class( 'wp-image-' . $file ); } elseif ( is_string( $file ) && preg_match( '/^(\d+)x(\d+)$/', $file, $m ) ) { $p->set_attribute( 'width', $m[1] ); $p->set_attribute( 'height', $m[2] ); } } return $p->get_updated_html(); } private static function media( array $urls ) { $urls = array_values( array_unique( $urls ) ); $keys = array_map( 'md5', $urls ); $post = (int) get_the_ID(); $ext = wp_using_ext_object_cache(); $known = $ext ? wp_cache_get_multiple( $keys, self::CACHE_GROUP ) : ( $post ? get_transient( 'aieo_docs_media_' . $post ) : false ); $known = is_array( $known ) ? $known : array(); $found = array(); $asked = false; foreach ( $urls as $i => $url ) { if ( isset( $known[ $keys[ $i ] ] ) && false !== $known[ $keys[ $i ] ] ) { $found[ $url ] = $known[ $keys[ $i ] ]; continue; } $id = (int) attachment_url_to_postid( $url ); $found[ $url ] = $id ? $id : self::file_size( $url ); $asked = true; if ( $ext ) { wp_cache_set( $keys[ $i ], $found[ $url ], self::CACHE_GROUP, $found[ $url ] ? WEEK_IN_SECONDS : DAY_IN_SECONDS ); } } if ( $asked && ! $ext && $post ) { set_transient( 'aieo_docs_media_' . $post, array_combine( $keys, array_values( $found ) ), in_array( 0, $found, true ) ? DAY_IN_SECONDS : WEEK_IN_SECONDS ); } return $found; } private static function file_size( $url ) { $uploads = wp_get_upload_dir(); $base = (string) preg_replace( '#^https?:#i', '', (string) $uploads['baseurl'] ); $at = (string) preg_replace( '#^https?:#i', '', (string) strtok( $url, '?#' ) ); if ( '' === $base || 0 !== strpos( $at, $base . '/' ) ) { return 0; } $relative = rawurldecode( substr( $at, strlen( $base ) + 1 ) ); if ( '' === $relative || false !== strpos( $relative, '..' ) || ! preg_match( '/\.(png|jpe?g|gif|webp|avif)$/i', $relative ) ) { return 0; } $path = trailingslashit( (string) $uploads['basedir'] ) . $relative; $size = is_file( $path ) ? wp_getimagesize( $path ) : false; return is_array( $size ) && ! empty( $size[0] ) && ! empty( $size[1] ) ? (int) $size[0] . 'x' . (int) $size[1] : 0; } public static function no_core_lightbox( $parsed_block ) { if ( is_array( $parsed_block ) && 'core/image' === ( $parsed_block['blockName'] ?? '' ) && self::in_content() ) { $parsed_block['attrs']['lightbox'] = array( 'enabled' => false ); } return $parsed_block; } public static function core_lightbox( $on ) { return self::in_content() ? false : (bool) $on; } public static function wrap( $html ) { $html = (string) $html; $p = new AIEO_Docs_Viewer_Scanner( $html ); $inside = 0; $picture = null; $figures = array(); $caption = -1; $shots = array(); while ( $p->next_token() ) { $type = $p->get_token_type(); if ( '#text' === $type ) { if ( $caption >= 0 && isset( $figures[ $caption ] ) ) { $figures[ $caption ]['caption'] .= $p->get_modifiable_text(); } continue; } if ( '#tag' !== $type ) { continue; } $closer = $p->is_tag_closer(); switch ( $p->get_tag() ) { case 'A': case 'BUTTON': $inside = max( 0, $inside + ( $closer ? -1 : 1 ) ); break; case 'FIGURE': if ( ! $closer ) { $figures[] = array( 'caption' => '', 'unnamed' => array() ); break; } $figure = array_pop( $figures ); $name = $figure ? trim( (string) preg_replace( '/\s+/u', ' ', $figure['caption'] ) ) : ''; foreach ( $figure ? $figure['unnamed'] : array() as $i ) { $shots[ $i ]['name'] = $name; } $caption = -1; break; case 'FIGCAPTION': $caption = $closer || ! $figures ? -1 : count( $figures ) - 1; break; case 'PICTURE': if ( ! $closer ) { $picture = 0 === $inside ? array( 'start' => $p->span()[0], 'shot' => null ) : null; break; } if ( $picture && $picture['shot'] ) { $span = $p->span(); $picture['shot']['start'] = $picture['start']; $picture['shot']['end'] = $span[0] + $span[1]; self::add( $shots, $figures, $picture['shot'] ); } $picture = null; break; case 'IMG': if ( $inside > 0 || preg_match( '/(^|\s)(wp-smiley|emoji)(\s|$)/', (string) $p->get_attribute( 'class' ) ) ) { break; } $href = self::full_size( $p ); if ( '' === $href ) { break; } $alt = $p->get_attribute( 'alt' ); $span = $p->span(); $shot = array( 'start' => $span[0], 'end' => $span[0] + $span[1], 'href' => $href, 'name' => is_string( $alt ) ? trim( $alt ) : '' ); if ( null !== $picture ) { $picture['shot'] = $picture['shot'] ? $picture['shot'] : $shot; break; } self::add( $shots, $figures, $shot ); break; } } if ( ! $shots ) { return $html; } $out = ''; $at = 0; foreach ( $shots as $shot ) { $out .= substr( $html, $at, $shot['start'] - $at ) . self::link( $shot['href'], $shot['name'] ) . substr( $html, $shot['start'], $shot['end'] - $shot['start'] ) . ''; $at = $shot['end']; } return $out . substr( $html, $at ); } private static function add( array &$shots, array &$figures, array $shot ) { $shots[] = $shot; if ( '' === $shot['name'] && $figures ) { $figures[ count( $figures ) - 1 ]['unnamed'][] = count( $shots ) - 1; } } private static function full_size( WP_HTML_Tag_Processor $p ) { $id = preg_match( '/(?:^|\s)wp-image-(\d+)(?:\s|$)/', (string) $p->get_attribute( 'class' ), $m ) ? (int) $m[1] : 0; if ( ! $id && is_string( $p->get_attribute( 'data-id' ) ) && ctype_digit( $p->get_attribute( 'data-id' ) ) ) { $id = (int) $p->get_attribute( 'data-id' ); } $url = $id ? (string) wp_get_original_image_url( $id ) : ''; if ( '' === $url ) { $url = self::largest( $p->get_attribute( 'srcset' ) ); } if ( '' === $url && is_string( $p->get_attribute( 'src' ) ) ) { $url = trim( $p->get_attribute( 'src' ) ); } return preg_match( '#^(https?:)?//[^/]|^/[^/]#i', $url ) ? $url : ''; } private static function largest( $srcset ) { $best = ''; $size = 0.0; foreach ( is_string( $srcset ) ? explode( ',', $srcset ) : array() as $candidate ) { $parts = preg_split( '/\s+/', trim( $candidate ) ); $value = isset( $parts[1] ) ? (float) $parts[1] : 1.0; if ( '' !== (string) $parts[0] && $value > $size ) { $best = (string) $parts[0]; $size = $value; } } return $best; } private static function link( $href, $name ) { $label = '' !== $name ? sprintf( __( 'Full-size image: %s', 'ai-eshop-optimizer' ), $name ) : __( 'Full-size image', 'ai-eshop-optimizer' ); return ''; } public static function enqueue() { if ( ! self::active() ) { return; } $dir = dirname( __DIR__, 2 ) . '/'; $css = 'assets/css/aieo-docs-viewer.css'; $js = 'assets/js/aieo-docs-viewer.js'; wp_enqueue_style( 'aieo-docs-viewer', plugins_url( $css, dirname( __DIR__ ) ), array(), (string) filemtime( $dir . $css ) ); $src = plugins_url( $js, dirname( __DIR__ ) ); wp_register_script_module( self::MODULE, class_exists( 'AIEO_Asset_Min', false ) ? AIEO_Asset_Min::module_src( $dir . $js, $src ) : $src, array( '@wordpress/interactivity' ), (string) filemtime( $dir . $js ), array( 'fetchpriority' => 'low' ) ); wp_enqueue_script_module( self::MODULE ); } public static function print_template() { if ( ! self::active() ) { return; } $icon = static function ( $slug ) { return function_exists( 'rooster_icon' ) ? rooster_icon( $slug, array( 'width' => 20, 'height' => 20 ) ) : ''; }; $button = static function ( $part, $label, $keys, $key_name, $inner ) { return ''; }; $title_id = self::TEMPLATE_ID . '-title'; $html = ''; echo $html . "\n"; } } final class AIEO_Docs_Viewer_Scanner extends WP_HTML_Tag_Processor { public function span() { $this->set_bookmark( 'aieo-docs-viewer' ); $span = $this->bookmarks['aieo-docs-viewer']; return array( (int) $span->start, (int) $span->length ); } } }