Term data object.
* @param int $depth Depth of category, used for padding.
* @param array $args An array of arguments.
* @param int $current_object_id ID of the current category.
*/
$atts = apply_filters( 'category_list_link_attributes', $atts, $category, $depth, $args, $current_object_id );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( is_scalar( $value ) && '' !== $value && false !== $value ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$link = sprintf(
'%s',
$attributes,
$cat_name
);
if ( ! empty( $args['feed_image'] ) || ! empty( $args['feed'] ) ) {
$link .= ' ';
if ( empty( $args['feed_image'] ) ) {
$link .= '(';
}
$link .= '';
}
$link .= '';
if ( empty( $args['feed_image'] ) ) {
$link .= ')';
}
}
if ( ! empty( $args['show_count'] ) ) {
$link .= ' (' . number_format_i18n( $category->count ) . ')';
}
if ( 'list' === $args['style'] ) {
$output .= "\t
term_id,
);
if ( ! empty( $args['current_category'] ) ) {
// 'current_category' can be an array, so we use `get_terms()`.
$_current_terms = get_terms(
array(
'taxonomy' => $category->taxonomy,
'include' => $args['current_category'],
'hide_empty' => false,
)
);
foreach ( $_current_terms as $_current_term ) {
if ( $category->term_id === $_current_term->term_id ) {
$css_classes[] = 'current-cat';
$link = str_replace( 'term_id === $_current_term->parent ) {
$css_classes[] = 'current-cat-parent';
}
while ( $_current_term->parent ) {
if ( $category->term_id === $_current_term->parent ) {
$css_classes[] = 'current-cat-ancestor';
break;
}
$_current_term = get_term( $_current_term->parent, $category->taxonomy );
}
}
}
/**
* Filters the list of CSS classes to include with each category in the list.
*
* @since 4.2.0
*
* @see wp_list_categories()
*
* @param string[] $css_classes An array of CSS classes to be applied to each list item.
* @param WP_Term $category Category data object.
* @param int $depth Depth of page, used for padding.
* @param array $args An array of wp_list_categories() arguments.
*/
$css_classes = implode( ' ', apply_filters( 'category_css_class', $css_classes, $category, $depth, $args ) );
$css_classes = $css_classes ? ' class="' . esc_attr( $css_classes ) . '"' : '';
$output .= $css_classes;
$output .= ">$link\n";
} elseif ( isset( $args['separator'] ) ) {
$output .= "\t$link" . $args['separator'] . "\n";
} else {
$output .= "\t$link
\n";
}
}
/**
* Ends the element output, if needed.
*
* @since 2.1.0
* @since 5.9.0 Renamed `$page` to `$data_object` to match parent class for PHP 8 named parameter support.
*
* @see Walker::end_el()
*
* @param string $output Used to append additional content (passed by reference).
* @param object $data_object Category data object. Not used.
* @param int $depth Optional. Depth of category. Not used.
* @param array $args Optional. An array of arguments. Only uses 'list' for whether should
* append to output. See wp_list_categories(). Default empty array.
*/
public function end_el( &$output, $data_object, $depth = 0, $args = array() ) {
if ( 'list' !== $args['style'] ) {
return;
}
$output .= "\n";
}
}
/**
* Returns the image entries for a given term.
*
* @since 4.0.0
*
* @param \WP_Term $term The term object.
* @return array The image entries.
*/
public function term( $term ) {
if ( aioseo()->sitemap->helpers->excludeImages() ) {
return [];
}
$id = get_term_meta( $term->term_id, 'thumbnail_id', true );
if ( ! $id ) {
return [];
}
return $this->buildEntries( [ $id ] );
}
/**
* Builds the image entries.
*
* @since 4.0.0
*
* @param array $images The images, consisting of attachment IDs or external URLs.
* @return array The image entries.
*/
private function buildEntries( $images ) {
$entries = [];
foreach ( $images as $image ) {
$idOrUrl = $this->getImageIdOrUrl( $image );
$imageUrl = is_numeric( $idOrUrl ) ? wp_get_attachment_url( $idOrUrl ) : $idOrUrl;
$imageUrl = aioseo()->sitemap->helpers->formatUrl( $imageUrl );
if ( ! $imageUrl || ! preg_match( $this->getImageExtensionRegexPattern(), (string) $imageUrl ) ) {
continue;
}
$entries[ $idOrUrl ] = [ 'image:loc' => $imageUrl ];
}
return array_values( $entries );
}
/**
* Returns the ID of the image if it's hosted on the site. Otherwise it returns the external URL.
*
* @since 4.1.3
*
* @param int|string $image The attachment ID or URL.
* @return int|string The attachment ID or URL.
*/
private function getImageIdOrUrl( $image ) {
if ( is_numeric( $image ) ) {
return $image;
}
$attachmentId = false;
if ( aioseo()->helpers->isValidAttachment( $image ) ) {
$attachmentId = aioseo()->helpers->attachmentUrlToPostId( $image );
}
return $attachmentId ? $attachmentId : $image;
}
/**
* Extracts all image URls and IDs from the post.
*
* @since 4.0.0
*
* @return array The image URLs and IDs.
*/
private function extract() {
$images = [];
if ( has_post_thumbnail( $this->post ) ) {
$images[] = get_the_post_thumbnail_url( $this->post );
}
// Get the galleries here before doShortcodes() runs below to prevent buggy behaviour.
// WordPress is supposed to only return the attached images but returns a different result if the shortcode has no valid attributes, so we need to grab them manually.
$images = array_merge( $images, $this->getPostGalleryImages() );
// Now, get the remaining images from image tags in the post content.
$parsedPostContent = do_blocks( $this->post->post_content );
$parsedPostContent = aioseo()->helpers->doShortcodes( $parsedPostContent, true, $this->post->ID );
$parsedPostContent = preg_replace( '/\s\s+/u', ' ', (string) trim( $parsedPostContent ) ); // Trim both internal and external whitespace.
// Get the images from any third-party plugins/themes that are active.
$thirdParty = new ThirdParty( $this->post, $parsedPostContent );
$images = array_merge( $images, $thirdParty->extract() );
preg_match_all( '#<(amp-)?img[^>]+src="([^">]+)"#', (string) $parsedPostContent, $matches );
foreach ( $matches[2] as $url ) {
$images[] = aioseo()->helpers->makeUrlAbsolute( $url );
}
return array_unique( $images );
}
/**
* Returns all images from WP Core post galleries.
*
* @since 4.2.2
*
* @return array[string] The image URLs.
*/
private function getPostGalleryImages() {
$images = [];
$galleries = get_post_galleries( $this->post, false );
foreach ( $galleries as $gallery ) {
foreach ( $gallery['src'] as $imageUrl ) {
$images[] = $imageUrl;
}
}
// Now, get rid of them so that we don't process the shortcodes again.
$regex = get_shortcode_regex( [ 'gallery' ] );
$this->post->post_content = preg_replace( "/$regex/i", '', (string) $this->post->post_content );
return $images;
}
/**
* Removes image dimensions from the slug.
*
* @since 4.0.0
*
* @param array $urls The image URLs.
* @return array $preparedUrls The formatted image URLs.
*/
private function removeImageDimensions( $urls ) {
$preparedUrls = [];
foreach ( $urls as $url ) {
$preparedUrls[] = aioseo()->helpers->removeImageDimensions( $url );
}
return array_unique( array_filter( $preparedUrls ) );
}
/**
* Stores the image data for a given post in our DB table.
*
* @since 4.0.5
*
* @param int $postId The post ID.
* @param array $images The images.
* @return void
*/
private function updatePost( $postId, $images = [] ) {
$post = \AIOSEO\Plugin\Common\Models\Post::getPost( $postId );
$meta = $post->exists() ? [] : aioseo()->migration->meta->getMigratedPostMeta( $postId );
$meta['post_id'] = $postId;
$meta['images'] = ! empty( $images ) ? $images : null;
$meta['image_scan_date'] = gmdate( 'Y-m-d H:i:s' );
$post->set( $meta );
$post->save();
}
/**
* Returns the image extension regex pattern.
*
* @since 4.2.2
*
* @return string
*/
public function getImageExtensionRegexPattern() {
static $pattern;
if ( null !== $pattern ) {
return $pattern;
}
$pattern = '/http.*\.(' . implode( '|', $this->supportedExtensions ) . ')$/i';
return $pattern;
}
}