0, 'ids' => null, 'items' => 0, 'placement' => $display->opt( 'placement' ), 'template' => '', 'layout' => '', 'heading' => null, 'preview' => false, ) ); $post_id = absint( $args['post_id'] ); if ( ! $post_id && null === $args['ids'] ) { $post_id = (int) get_the_ID(); } $config = $display->config; foreach ( array( 'template', 'layout' ) as $key ) { if ( ! empty( $args[ $key ] ) ) { $config[ $key ] = sanitize_key( $args[ $key ] ); } } foreach ( array( 'cols_d', 'cols_t', 'cols_m' ) as $key ) { if ( ! empty( $args[ $key ] ) ) { $config[ $key ] = max( 1, (int) $args[ $key ] ); } } if ( ! empty( $args['items'] ) ) { $config['items'] = max( 1, (int) $args['items'] ); } if ( null !== $args['heading'] ) { $config['heading'] = sanitize_text_field( $args['heading'] ); } $display = clone $display; $display->config = $config; $ids = ( null !== $args['ids'] ) ? srpp_int_list( $args['ids'] ) : SRPP_Engine::get_ids( $display, $post_id, array( 'items' => $config['items'] ) ); $ids = array_slice( $ids, 0, (int) $config['items'] ); if ( empty( $ids ) ) { return ''; } $items = array(); foreach ( $ids as $id ) { $data = $this->item_data( $id, $display ); if ( $data ) { $items[] = $data; } } if ( empty( $items ) ) { return ''; } $template = SRPP_Templates::get( $config['template'] ); SRPP_Assets::mark_used( $config['layout'], $template['id'] ); self::$sequence++; $context = array( 'uid' => 'srpp-' . $display->id . '-' . self::$sequence, 'display' => $display, 'config' => $config, 'items' => $items, 'template' => $template, 'post_id' => $post_id, 'placement' => sanitize_key( $args['placement'] ), 'preview' => (bool) $args['preview'], ); ob_start(); $this->open_wrapper( $context ); include SRPP_Templates::path( $template['id'] ); $this->close_wrapper(); $html = ob_get_clean(); /** * Filter a rendered related-content block. * * @param string $html Markup. * @param SRPP_Display $display Display. * @param array $context Render context. */ return apply_filters( 'srpp_render', $html, $display, $context ); } /** * Open the block wrapper, heading included. * * @param array $context Render context. */ protected function open_wrapper( $context ) { $config = $context['config']; $classes = array( 'srpp', 'srpp-layout-' . sanitize_html_class( $config['layout'] ), 'srpp-' . sanitize_html_class( $context['template']['id'] ), 'srpp-ratio-' . sanitize_html_class( $config['image_ratio'] ), 'srpp-shadow-' . sanitize_html_class( $config['style']['shadow'] ), ); if ( $context['preview'] ) { $classes[] = 'srpp-is-preview'; } printf( '
', esc_attr( implode( ' ', $classes ) ), esc_attr( $context['uid'] ), esc_attr( $this->style_vars( $config ) ), absint( $context['display']->id ), absint( $context['post_id'] ), esc_attr( $context['template']['id'] ), esc_attr( $context['placement'] ) ); $heading = trim( (string) $config['heading'] ); if ( '' !== $heading ) { $tag = $config['heading_tag']; printf( '<%1$s class="srpp-heading srpp-align-%2$s">%3$s', esc_html( $tag ), esc_attr( $config['heading_align'] ), esc_html( $heading ) ); } } /** * Close the wrapper. */ protected function close_wrapper() { echo '
'; } /** * Build the inline custom property list. * * @param array $config Config. * @return string */ protected function style_vars( $config ) { $style = wp_parse_args( (array) $config['style'], srpp_default_style() ); $vars = array( '--srpp-cols-d' => (int) $config['cols_d'], '--srpp-cols-t' => (int) $config['cols_t'], '--srpp-cols-m' => (int) $config['cols_m'], '--srpp-gap' => (int) $config['gap'] . 'px', '--srpp-accent' => $style['accent'], '--srpp-card-bg' => $style['card_bg'], '--srpp-title' => $style['title_color'], '--srpp-text' => $style['text_color'], '--srpp-meta' => $style['meta_color'], '--srpp-border' => $style['border'], '--srpp-radius' => (int) $style['radius'] . 'px', '--srpp-img-radius' => (int) $style['img_radius'] . 'px', '--srpp-title-size' => (int) $style['title_size'] . 'px', '--srpp-text-size' => (int) $style['text_size'] . 'px', '--srpp-pad' => (int) $style['padding'] . 'px', ); $out = ''; foreach ( $vars as $key => $value ) { if ( '' === $value || null === $value ) { continue; } $out .= $key . ':' . $value . ';'; } return $out; } /** * Assemble everything a template may need for one item. * * @param int $id Post ID. * @param SRPP_Display $display Display. * @return array|false */ public function item_data( $id, $display ) { $post = get_post( $id ); if ( ! $post ) { return false; } $config = $display->config; $is_product = srpp_is_woo_active() && 'product' === $post->post_type; $product = $is_product ? wc_get_product( $id ) : null; $data = array( 'id' => (int) $id, 'post' => $post, 'is_product' => $is_product, 'product' => $product, 'title' => get_the_title( $id ), 'url' => get_permalink( $id ), 'target' => $config['link_target'], 'date' => get_the_date( '', $id ), 'datetime' => get_the_date( 'c', $id ), 'author' => get_the_author_meta( 'display_name', $post->post_author ), 'author_url' => get_author_posts_url( $post->post_author ), 'readtime' => srpp_reading_time( $id ), 'term' => '', 'term_url' => '', 'excerpt' => '', 'image' => '', 'image_url' => '', 'price' => '', 'rating' => '', 'cart' => '', 'on_sale' => false, ); // Primary term. $taxonomies = $is_product ? array( 'product_cat' ) : array( 'category' ); $taxonomies = array_merge( $taxonomies, (array) $config['relate_by'] ); foreach ( array_unique( $taxonomies ) as $taxonomy ) { if ( ! taxonomy_exists( $taxonomy ) ) { continue; } $terms = get_the_terms( $id, $taxonomy ); if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) { $term = array_shift( $terms ); $data['term'] = $term->name; $link = get_term_link( $term ); $data['term_url'] = is_wp_error( $link ) ? '' : $link; break; } } // Excerpt. $length = (int) $config['excerpt_length']; if ( $length > 0 ) { $raw = has_excerpt( $id ) ? $post->post_excerpt : $post->post_content; $raw = strip_shortcodes( wp_strip_all_tags( $raw ) ); $data['excerpt'] = wp_trim_words( $raw, $length, '…' ); } // Image. $size = apply_filters( 'srpp_image_size', 'medium_large', $display, $id ); if ( has_post_thumbnail( $id ) ) { $attr = array( 'class' => 'srpp-img' ); if ( srpp_get_option( 'lazy_images', 1 ) ) { $attr['loading'] = 'lazy'; } $data['image'] = get_the_post_thumbnail( $id, $size, $attr ); $data['image_url'] = get_the_post_thumbnail_url( $id, $size ); } else { $fallback = apply_filters( 'srpp_placeholder_image', '', $display, $id ); if ( $fallback ) { $data['image'] = ''; $data['image_url'] = $fallback; } } // WooCommerce fields. if ( $product ) { $data['price'] = $product->get_price_html(); $data['on_sale'] = $product->is_on_sale(); if ( $product->get_rating_count() ) { $data['rating'] = wc_get_rating_html( $product->get_average_rating(), $product->get_rating_count() ); } $data['cart'] = sprintf( '%4$s', esc_url( $product->add_to_cart_url() ), esc_attr( implode( ' ', array_filter( array( $product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '', $product->supports( 'ajax_add_to_cart' ) && $product->is_purchasable() && $product->is_in_stock() ? 'ajax_add_to_cart' : '' ) ) ) ), (int) $id, esc_html( $product->add_to_cart_text() ) ); } /** * Filter one item's render data. * * @param array $data Item data. * @param int $id Post ID. * @param SRPP_Display $display Display. */ return apply_filters( 'srpp_item_data', $data, $id, $display ); } /** * Link attributes shared by every template. * * @param array $item Item data. * @param array $context Render context. * @param array $extra Extra classes. * @return string */ public static function link_atts( $item, $context, $extra = array() ) { $classes = array_merge( array( 'srpp-link' ), (array) $extra ); $atts = sprintf( 'href="%s" class="%s" data-srpp-target="%d"', esc_url( $item['url'] ), esc_attr( implode( ' ', array_map( 'sanitize_html_class', $classes ) ) ), absint( $item['id'] ) ); if ( '_blank' === $item['target'] ) { $atts .= ' target="_blank" rel="noopener noreferrer"'; } unset( $context ); return $atts; } }