*/ public static function extract_post( int $post_id, string $base, bool $include_images = true ): array { return self::extract( self::raw( $post_id ), $base, $include_images ); } /** * Extract links from an Elementor JSON document. * * @param string $json JSON string. * @param string $base Base URL. * @param bool $include_images Include images. * @return array */ public static function extract( string $json, string $base, bool $include_images = true ): array { if ( '' === $json ) { return array(); } $data = json_decode( $json, true ); if ( ! is_array( $data ) ) { return array(); } $found = array(); self::walk( $data, $base, $include_images, $found, '', 'Elementor', '' ); return $found; } /** * Recursive walker. * * @param array $node Current node. * @param string $base Base URL. * @param bool $include_images Include images. * @param array $found Accumulator. * @param string $anchor Inherited anchor text. * @param string $context Inherited context label. * @param string $parent_key Key under which this node sits. */ private static function walk( array $node, string $base, bool $include_images, array &$found, string $anchor, string $context, string $parent_key ): void { if ( isset( $node['elType'] ) && is_string( $node['elType'] ) ) { $type = isset( $node['widgetType'] ) && is_string( $node['widgetType'] ) ? $node['widgetType'] : $node['elType']; $context = 'Elementor ' . $type; $anchor = ''; if ( isset( $node['settings'] ) && is_array( $node['settings'] ) ) { $anchor = self::text_from( $node['settings'] ); } } else { $own = self::text_from( $node ); if ( '' !== $own ) { $anchor = $own; } } foreach ( $node as $key => $value ) { if ( '__dynamic__' === $key ) { continue; } if ( is_array( $value ) ) { self::walk( $value, $base, $include_images, $found, $anchor, $context, is_string( $key ) ? $key : $parent_key ); continue; } if ( ! is_string( $value ) || '' === $value ) { continue; } if ( 'url' === $key ) { if ( ! AttributeParser::looks_like_url( $value ) ) { continue; } $element = self::is_image_container( $node, $parent_key ) ? 'img' : 'a'; if ( 'img' === $element && ! $include_images ) { continue; } $url = Url::normalize( $value, $base ); if ( null !== $url ) { $found[] = array( 'url' => $url, 'element' => $element, 'anchor_text' => HtmlParser::truncate( $anchor, 255 ), 'context' => $context, 'source_key' => self::META_KEY, ); } continue; } if ( false !== strpos( $value, '<' ) && ( false !== stripos( $value, 'href' ) || false !== stripos( $value, 'src' ) ) ) { foreach ( HtmlParser::extract( $value, $base, self::META_KEY, $include_images ) as $link ) { $found[] = $link; } } } } /** * First non-empty text-like value in an object. * * @param array $node Node. */ private static function text_from( array $node ): string { foreach ( self::TEXT_KEYS as $key ) { if ( isset( $node[ $key ] ) && is_string( $node[ $key ] ) && '' !== trim( $node[ $key ] ) ) { return HtmlParser::squash( wp_strip_all_tags( $node[ $key ] ) ); } } return ''; } /** * Whether an object holding a `url` represents an image (Elementor media control). * * @param array $node Object holding the url. * @param string $parent_key Key of the object. */ private static function is_image_container( array $node, string $parent_key ): bool { if ( preg_match( '/image|background|media|gallery|src|thumbnail|poster/i', $parent_key ) ) { return true; } return isset( $node['id'] ) && ( isset( $node['source'] ) || isset( $node['alt'] ) ) && ! isset( $node['is_external'] ); } }