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%1$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;
}
}