render_block_data` instead.' ) ); } $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $parsed_block['blockName'] ); $element_block_styles = isset( $parsed_block['attrs']['style']['elements'] ) ? $parsed_block['attrs']['style']['elements'] : null; if ( ! $element_block_styles ) { return $parsed_block; } $skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); $skip_heading_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'heading' ); $skip_button_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'button' ); $skips_all_element_color_serialization = $skip_link_color_serialization && $skip_heading_color_serialization && $skip_button_color_serialization; if ( $skips_all_element_color_serialization ) { return $parsed_block; } $options = array( 'button' => array( 'skip' => $skip_button_color_serialization ), 'link' => array( 'skip' => $skip_link_color_serialization ), 'heading' => array( 'skip' => $skip_heading_color_serialization ), ); if ( ! wp_should_add_elements_class_name( $parsed_block, $options ) ) { return $parsed_block; } $class_name = wp_get_elements_class_name( $parsed_block ); $updated_class_name = isset( $parsed_block['attrs']['className'] ) ? $parsed_block['attrs']['className'] . " $class_name" : $class_name; _wp_array_set( $parsed_block, array( 'attrs', 'className' ), $updated_class_name ); // Generate element styles based on selector and store in style engine for enqueuing. $element_types = array( 'button' => array( 'selector' => ".$class_name .wp-element-button, .$class_name .wp-block-button__link", 'skip' => $skip_button_color_serialization, ), 'link' => array( 'selector' => ".$class_name a:where(:not(.wp-element-button))", 'hover_selector' => ".$class_name a:where(:not(.wp-element-button)):hover", 'skip' => $skip_link_color_serialization, ), 'heading' => array( 'selector' => ".$class_name h1, .$class_name h2, .$class_name h3, .$class_name h4, .$class_name h5, .$class_name h6", 'skip' => $skip_heading_color_serialization, 'elements' => array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ), ), ); foreach ( $element_types as $element_type => $element_config ) { if ( $element_config['skip'] ) { continue; } $element_style_object = isset( $element_block_styles[ $element_type ] ) ? $element_block_styles[ $element_type ] : null; // Process primary element type styles. if ( $element_style_object ) { wp_style_engine_get_styles( $element_style_object, array( 'selector' => $element_config['selector'], 'context' => 'block-supports', ) ); if ( isset( $element_style_object[':hover'] ) ) { wp_style_engine_get_styles( $element_style_object[':hover'], array( 'selector' => $element_config['hover_selector'], 'context' => 'block-supports', ) ); } } // Process related elements e.g. h1-h6 for headings. if ( isset( $element_config['elements'] ) ) { foreach ( $element_config['elements'] as $element ) { $element_style_object = isset( $element_block_styles[ $element ] ) ? $element_block_styles[ $element ] : null; if ( $element_style_object ) { wp_style_engine_get_styles( $element_style_object, array( 'selector' => ".$class_name $element", 'context' => 'block-supports', ) ); } } } } return $parsed_block; } /** * Ensure the elements block support class name generated, and added to * block attributes, in the `render_block_data` filter gets applied to the * block's markup. * * @see wp_render_elements_support_styles * @since 6.6.0 * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_render_elements_class_name( $block_content, $block ) { $class_string = $block['attrs']['className'] ?? ''; preg_match( '/\bwp-elements-\S+\b/', $class_string, $matches ); if ( empty( $matches ) ) { return $block_content; } $tags = new WP_HTML_Tag_Processor( $block_content ); if ( $tags->next_tag() ) { $tags->add_class( $matches[0] ); } return $tags->get_updated_html(); } add_filter( 'render_block', 'wp_render_elements_class_name', 10, 2 ); add_filter( 'render_block_data', 'wp_render_elements_support_styles', 10, 1 ); ring The URL. * @throws Exception If the ID is invalid. */ protected function get_url( int $id, string $type ): string { if ( $type === 'post' ) { $url = get_permalink( $id ); } elseif ( $type === 'term' ) { $url = get_term_link( $id ); } else { $url = get_bloginfo( 'url' ); } if ( is_wp_error( $url ) || empty( $url ) ) { throw new Exception( /* translators: 1: is an integer representing an unknown Term ID */ sprintf( __( 'Invalid Term ID or Post ID or site url %1$d', 'google-listings-and-ads' ), $id ) ); } return $url; } /** * Get other campaigns' assets from the specific url. * * @param int $id Post or Term ID. * @param string $type Only possible values are post or term. */ protected function get_asset_group_asset_suggestions( int $id, string $type ): array { $final_url = $this->get_url( $id, $type ); // Suggest the assets from the first asset group if exists. $asset_group_assets = $this->asset_group_asset->get_assets_by_final_url( $final_url, true ); if ( empty( $asset_group_assets ) ) { return []; } return array_merge( $this->get_suggestions_common_fields( [] ), [ 'final_url' => $final_url ], $asset_group_assets ); } /** * Get assets from specific post or term. * * @param int $id Post or Term ID, or self::HOMEPAGE_KEY_ID. * @param string $type Only possible values are post or term. * * @return array All assets available for specific term, post or homepage. * @throws Exception If the ID is invalid. */ protected function get_wp_assets( int $id, string $type ): array { if ( $type === 'post' ) { return $this->get_post_assets( $id ); } elseif ( $type === 'term' ) { return $this->get_term_assets( $id ); } else { return $this->get_homepage_assets(); } } /** * Get assets from the homepage. * * @return array Assets available for the homepage. * @throws Exception If the homepage id is invalid. */ protected function get_homepage_assets(): array { $home_page = $this->wp->get_static_homepage(); // Static homepage. if ( $home_page ) { return $this->get_post_assets( $home_page->ID ); } // Get images from the latest posts. $posts = $this->wp->get_posts( [] ); $inserted_images_ids = array_map( [ $this, 'get_html_inserted_images' ], array_column( $posts, 'post_content' ) ); $ids = array_merge( $this->get_post_image_attachments( [ 'post_parent__in' => array_column( $posts, 'ID' ) ] ), ...$inserted_images_ids ); $marketing_images = $this->get_url_attachments_by_ids( $ids ); // Non static homepage. return array_merge( [ AssetFieldType::HEADLINE => [ __( 'Homepage', 'google-listings-and-ads' ) ], AssetFieldType::LONG_HEADLINE => [ get_bloginfo( 'name' ) . ': ' . __( 'Homepage', 'google-listings-and-ads' ) ], AssetFieldType::DESCRIPTION => ArrayUtil::remove_empty_values( [ __( 'Homepage', 'google-listings-and-ads' ), get_bloginfo( 'description' ) ] ), 'display_url_path' => [], 'final_url' => get_bloginfo( 'url' ), ], $this->get_suggestions_common_fields( $marketing_images ) ); } /** * Get assets from specific post. * * @param int $id Post ID. * * @return array All assets for specific post. * @throws Exception If the Post ID is invalid. */ protected function get_post_assets( int $id ): array { $post = get_post( $id ); if ( ! $post || $post->post_status === 'trash' ) { throw new Exception( /* translators: 1: is an integer representing an unknown Post ID */ sprintf( __( 'Invalid Post ID %1$d', 'google-listings-and-ads' ), $id ) ); } $attachments_ids = $this->get_post_image_attachments( [ 'post_parent' => $id, ] ); if ( $id === wc_get_page_id( 'shop' ) ) { $attachments_ids = [ ...$attachments_ids, ...$this->get_shop_attachments() ]; } if ( $post->post_type === 'product' || $post->post_type === 'product_variation' ) { $product = $this->wc->maybe_get_product( $id ); $attachments_ids = [ ...$attachments_ids, ...$product->get_gallery_image_ids() ]; } $attachments_ids = [ ...$attachments_ids, ...$this->get_gallery_images_ids( $id ), ...$this->get_html_inserted_images( $post->post_content ), get_post_thumbnail_id( $id ) ]; $marketing_images = $this->get_url_attachments_by_ids( $attachments_ids ); $long_headline = get_bloginfo( 'name' ) . ': ' . $post->post_title; return array_merge( [ AssetFieldType::HEADLINE => [ $post->post_title ], AssetFieldType::LONG_HEADLINE => [ $long_headline ], AssetFieldType::DESCRIPTION => ArrayUtil::remove_empty_values( [ $post->post_excerpt, get_bloginfo( 'description' ) ] ), 'display_url_path' => [ $post->post_name ], 'final_url' => get_permalink( $id ), ], $this->get_suggestions_common_fields( $marketing_images ) ); } /** * Get assets from specific term. * * @param int $id Term ID. * * @return array All assets for specific term. * @throws Exception If the Term ID is invalid. */ protected function get_term_assets( int $id ): array { $term = get_term( $id ); if ( ! $term ) { throw new Exception( /* translators: 1: is an integer representing an unknown Term ID */ sprintf( __( 'Invalid Term ID %1$d', 'google-listings-and-ads' ), $id ) ); } $posts_assigned_to_term = $this->get_posts_assigned_to_a_term( $term->term_id, $term->taxonomy ); $posts_ids_assigned_to_term = []; $attachments_ids = []; foreach ( $posts_assigned_to_term as $post ) { $attachments_ids[] = get_post_thumbnail_id( $post->ID ); $posts_ids_assigned_to_term[] = $post->ID; } if ( count( $posts_assigned_to_term ) ) { $attachments_ids = [ ...$this->get_post_image_attachments( [ 'post_parent__in' => $posts_ids_assigned_to_term ] ), ...$attachments_ids ]; } $marketing_images = $this->get_url_attachments_by_ids( $attachments_ids ); return array_merge( [ AssetFieldType::HEADLINE => [ $term->name ], AssetFieldType::LONG_HEADLINE => [ get_bloginfo( 'name' ) . ': ' . $term->name ], AssetFieldType::DESCRIPTION => ArrayUtil::remove_empty_values( [ wp_strip_all_tags( $term->description ), get_bloginfo( 'description' ) ] ), 'display_url_path' => [ $term->slug ], 'final_url' => get_term_link( $term->term_id ), ], $this->get_suggestions_common_fields( $marketing_images ) ); } /** * Get inserted images from HTML. * * @param string $html HTML string. * * @return array Array of image IDs. */ protected function get_html_inserted_images( string $html ): array { if ( empty( $html ) ) { return []; } // Malformed HTML can cause DOMDocument to throw warnings. With the below line, we can suppress them and work only with the HTML that has been parsed. libxml_use_internal_errors( true ); $dom = new DOMDocument(); if ( $dom->loadHTML( $html ) ) { $images = $dom->getElementsByTagName( 'img' ); $images_ids = []; $pattern = '/-\d+x\d+\.(jpg|jpeg|png)$/i'; foreach ( $images as $image ) { $url_unscaled = preg_replace( $pattern, '.${1}', $image->getAttribute( 'src' ), ); $image_id = attachment_url_to_postid( $url_unscaled ); // Look for scaled image if the original image is not found. if ( $image_id === 0 ) { $url_scaled = preg_replace( $pattern, '-scaled.${1}', $image->getAttribute( 'src' ), ); $image_id = attachment_url_to_postid( $url_scaled ); } if ( $image_id > 0 ) { $images_ids[] = $image_id; } } } return $images_ids; } /** * Get logo images urls. * * @return array Logo images urls. */ protected function get_logo_images(): array { $logo_images = $this->get_url_attachments_by_ids( [ get_theme_mod( 'custom_logo' ) ], [ self::LOGO_IMAGE_KEY ] ); return $logo_images[ self::LOGO_IMAGE_KEY ] ?? []; } /** * Get posts linked to a specific term. * * @param int $term_id Term ID. * @param string $taxonomy_name Taxonomy name. * * @return array List of posts assigned to the term. */ protected function get_posts_assigned_to_a_term( int $term_id, string $taxonomy_name ): array { $args = [ 'post_type' => 'any', 'numberposts' => self::DEFAULT_MAXIMUM_MARKETING_IMAGES, 'tax_query' => [ [ 'taxonomy' => $taxonomy_name, 'terms' => $term_id, 'field' => 'term_id', 'include_children' => false, ], ], ]; return $this->wp->get_posts( $args ); } /** * Get attachments related to the shop page. * * @return array Shop attachments. */ protected function get_shop_attachments(): array { return $this->get_post_image_attachments( [ 'post_parent__in' => $this->get_shop_products(), ] ); } /** * * Get products that will be use to offer image assets. * * @param array $args See WP_Query::parse_query() for all available arguments. * @return array Shop products. */ protected function get_shop_products( array $args = [] ): array { $defaults = [ 'post_type' => 'product', 'numberposts' => self::DEFAULT_MAXIMUM_MARKETING_IMAGES, 'fields' => 'ids', ]; $args = wp_parse_args( $args, $defaults ); return $this->wp->get_posts( $args ); } /** * Get gallery images ids. * * @param int $post_id Post ID that contains the gallery. * * @return array List of gallery images ids. */ protected function get_gallery_images_ids( int $post_id ): array { $gallery = get_post_gallery( $post_id, false ); if ( ! $gallery || ! isset( $gallery['ids'] ) ) { return []; } return explode( ',', $gallery['ids'] ); } /** * Get unique attachments ids converted to int values. * * @param array $ids Attachments ids. * @param int $maximum_images Maximum number of images to return. * * @return array List of unique attachments ids converted to int values. */ protected function prepare_image_ids( array $ids, int $maximum_images = self::DEFAULT_MAXIMUM_MARKETING_IMAGES ): array { $ids = array_unique( ArrayUtil::remove_empty_values( $ids ) ); $ids = array_map( 'intval', $ids ); return array_slice( $ids, 0, $maximum_images ); } /** * Get URL for each attachment using an array of attachment ids and a list of subsizes. * * @param array $ids Attachments ids. * @param array $size_keys Image subsize keys. * @param int $maximum_images Maximum number of images to return. * * @return array A list of attachments urls. */ protected function get_url_attachments_by_ids( array $ids, array $size_keys = [ self::SQUARE_MARKETING_IMAGE_KEY, self::MARKETING_IMAGE_KEY, self::PORTRAIT_MARKETING_IMAGE_KEY ], $maximum_images = self::DEFAULT_MAXIMUM_MARKETING_IMAGES ): array { $ids = $this->prepare_image_ids( $ids, $maximum_images ); $marketing_images = []; foreach ( $ids as $id ) { $metadata = wp_get_attachment_metadata( $id ); if ( ! $metadata ) { continue; } foreach ( $size_keys as $size_key ) { if ( count( $marketing_images[ $size_key ] ?? [] ) >= self::IMAGE_REQUIREMENTS[ $size_key ]['max_qty'] ) { continue; } $minimum_size = new DimensionUtility( ...self::IMAGE_REQUIREMENTS[ $size_key ]['minimum'] ); $recommended_size = new DimensionUtility( ...self::IMAGE_REQUIREMENTS[ $size_key ]['recommended'] ); $image_size = new DimensionUtility( $metadata['width'], $metadata['height'] ); $suggested_size = $this->image_utility->recommend_size( $image_size, $recommended_size, $minimum_size ); // If the original size matches the suggested size with a precision of +-1px. if ( $suggested_size && $suggested_size->equals( $image_size ) ) { $marketing_images[ $size_key ][] = wp_get_attachment_url( $id ); } elseif ( isset( $metadata['sizes'][ $size_key ] ) ) { // use the sub size. $marketing_images[ $size_key ][] = wp_get_attachment_image_url( $id, $size_key ); } elseif ( $suggested_size && $this->image_utility->maybe_add_subsize_image( $id, $size_key, $suggested_size ) ) { // use the resized image. $marketing_images[ $size_key ][] = wp_get_attachment_image_url( $id, $size_key ); } } } return $marketing_images; } /** * Get Attachmets for specific posts. * * @param array $args See WP_Query::parse_query() for all available arguments. * * @return array List of attachments */ protected function get_post_image_attachments( array $args = [] ): array { $defaults = [ 'post_type' => 'attachment', 'post_mime_type' => [ 'image/jpeg', 'image/png', 'image/jpg' ], 'fields' => 'ids', 'numberposts' => self::DEFAULT_MAXIMUM_MARKETING_IMAGES, ]; $args = wp_parse_args( $args, $defaults ); return $this->wp->get_posts( $args ); } /** * Get posts that can be used to suggest assets * * @param string $search The search query. * @param int $per_page Number of items per page. * @param int $offset Used in the get_posts query. * * @return array formatted post suggestions */ protected function get_post_suggestions( string $search, int $per_page, int $offset = 0 ): array { if ( $per_page <= 0 ) { return []; } $post_suggestions = []; $excluded_post_types = [ 'attachment' ]; $post_types = $this->wp->get_post_types( [ 'exclude_from_search' => false, 'public' => true, ] ); // Exclude attachment post_type $filtered_post_types = array_diff( $post_types, $excluded_post_types ); $args = [ 'post_type' => $filtered_post_types, 'posts_per_page' => $per_page, 'post_status' => 'publish', 'search_title' => $search, 'offset' => $offset, 'suppress_filters' => false, ]; add_filter( 'posts_where', [ $this, 'title_filter' ], 10, 2 ); $posts = $this->wp->get_posts( $args ); remove_filter( 'posts_where', [ $this, 'title_filter' ] ); foreach ( $posts as $post ) { $post_suggestions[] = $this->format_final_url_response( $post->ID, 'post', $post->post_title, get_permalink( $post->ID ) ); } return $post_suggestions; } /** * Filter for the posts_where hook, adds WHERE clause to search * for the 'search_title' parameter in the post titles (when present). * * @param string $where The WHERE clause of the query. * @param WP_Query $wp_query The WP_Query instance (passed by reference). * * @return string The updated WHERE clause. */ public function title_filter( string $where, WP_Query $wp_query ): string { $search_title = $wp_query->get( 'search_title' ); if ( $search_title ) { $title_search = '%' . $this->wpdb->esc_like( $search_title ) . '%'; $where .= $this->wpdb->prepare( " AND `{$this->wpdb->posts}`.`post_title` LIKE %s", $title_search ); // phpcs:ignore WordPress.DB.PreparedSQL } return $where; } /** * Get terms that can be used to suggest assets * * @param string $search The search query * @param int $per_page Number of items per page * * @return array formatted terms suggestions */ protected function get_terms_suggestions( string $search, int $per_page ): array { $terms_suggestions = []; // get_terms evaluates $per_page_terms = 0 as a falsy, therefore it will not add the LIMIT clausure returning all the results. // See: https://github.com/WordPress/WordPress/blob/abe134c2090e84080adc46187884201a4badd649/wp-includes/class-wp-term-query.php#L868 if ( $per_page <= 0 ) { return []; } // Get all taxonomies that are public, show_in_menu = true helps to exclude taxonomies such as "product_shipping_class". $taxonomies = $this->wp->get_taxonomies( [ 'public' => true, 'show_in_menu' => true, ], ); $terms = $this->wp->get_terms( [ 'taxonomy' => $taxonomies, 'hide_empty' => false, 'number' => $per_page, 'name__like' => $search, ] ); foreach ( $terms as $term ) { $terms_suggestions[] = $this->format_final_url_response( $term->term_id, 'term', $term->name, get_term_link( $term->term_id, $term->taxonomy ) ); } return $terms_suggestions; } /** * Return a list of final urls that can be used to suggest assets. * * @param string $search The search query * @param int $per_page Number of items per page * @param string $order_by Order by: type, title, url * * @return array final urls with their title, id & type. */ public function get_final_url_suggestions( string $search = '', int $per_page = 30, string $order_by = 'title' ): array { if ( empty( $search ) ) { return $this->get_defaults_final_url_suggestions(); } $homepage = []; // If the search query contains the word "homepage" add the homepage to the results. if ( strpos( 'homepage', strtolower( $search ) ) !== false ) { $homepage[] = $this->get_homepage_final_url(); --$per_page; } // Split possible results between posts and terms. $per_page_posts = (int) ceil( $per_page / 2 ); $posts = $this->get_post_suggestions( $search, $per_page_posts ); // Try to get more results using the terms $per_page_terms = $per_page - count( $posts ); $terms = $this->get_terms_suggestions( $search, $per_page_terms ); $pending_results = $per_page - count( $posts ) - count( $terms ); $more_results = []; // Try to get more results using posts if ( $pending_results > 0 && count( $posts ) === $per_page_posts ) { $more_results = $this->get_post_suggestions( $search, $pending_results, $per_page_posts ); } $result = array_merge( $homepage, $posts, $terms, $more_results ); return $this->sort_results( $result, $order_by ); } /** * Get the final url for the homepage. * * @return array final url for the homepage. */ protected function get_homepage_final_url(): array { return $this->format_final_url_response( self::HOMEPAGE_KEY_ID, 'homepage', __( 'Homepage', 'google-listings-and-ads' ), get_bloginfo( 'url' ) ); } /** * Get defaults final urls suggestions. * * @return array default final urls. */ protected function get_defaults_final_url_suggestions(): array { $defaults = [ $this->get_homepage_final_url() ]; $shop_page = $this->wp->get_shop_page(); if ( $shop_page ) { $defaults[] = $this->format_final_url_response( $shop_page->ID, 'post', $shop_page->post_title, get_permalink( $shop_page->ID ) ); } return $defaults; } /** * Order suggestions alphabetically * * @param array $results Results as an associative array * @param string $field Sort by a specific field * * @return array response sorted alphabetically */ protected function sort_results( array $results, string $field ): array { usort( $results, function ( $a, $b ) use ( $field ) { return strcmp( strtolower( (string) $a[ $field ] ), strtolower( (string) $b[ $field ] ) ); } ); return $results; } /** * Return an assotiave array with the page suggestion response format. * * @param int $id post id, term id or self::HOMEPAGE_KEY_ID. * @param string $type post|term * @param string $title page|term title * @param string $url page|term url * * @return array response formated. */ protected function format_final_url_response( int $id, string $type, string $title, string $url ): array { return [ 'id' => $id, 'type' => $type, 'title' => $title, 'url' => $url, ]; } /** * Get the suggested common fieds. * * @param array $marketing_images Marketing images. * * @return array Suggested common fields. */ protected function get_suggestions_common_fields( array $marketing_images ): array { return [ AssetFieldType::LOGO => $this->get_logo_images(), AssetFieldType::BUSINESS_NAME => get_bloginfo( 'name' ), AssetFieldType::SQUARE_MARKETING_IMAGE => $marketing_images[ self::SQUARE_MARKETING_IMAGE_KEY ] ?? [], AssetFieldType::MARKETING_IMAGE => $marketing_images [ self::MARKETING_IMAGE_KEY ] ?? [], AssetFieldType::PORTRAIT_MARKETING_IMAGE => $marketing_images [ self::PORTRAIT_MARKETING_IMAGE_KEY ] ?? [], AssetFieldType::CALL_TO_ACTION_SELECTION => null, ]; } }
Warning: class_implements(): Class Automattic\WooCommerce\GoogleListingsAndAds\Ads\AssetSuggestionsService does not exist and could not be loaded in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php on line 73

Warning: foreach() argument must be of type array|object, bool given in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php on line 73
Shop - NPS-Machines d'impression maroc