$value ) {
$out[ $name ] = $value;
}
foreach ( $defaults as $name => $default ) {
if ( array_key_exists( $name, $out ) ) {
if ( $out[ $name ] === '' ) {
$out[ $name ] = $default;
}
} else {
$out[ $name ] = $default;
}
}
return $out;
}
}
if ( ! function_exists( 'stackable_blog_posts_block_default_attributes_v2' ) ) {
function stackable_blog_posts_block_default_attributes_v2( $attributes ) {
$defaults = array(
'postType' => 'post',
'numberOfItems' => 6,
'orderBy' => 'date',
'order' => 'desc',
'taxonomyType' => 'category',
'taxonomy' => '',
'taxonomyFilterType' => '__in',
'postOffset' => 0,
'postExclude' => '',
'postInclude' => '',
'design' => 'basic',
'shadow' => 3,
'imageSize' => 'large',
'titleTag' => 'h3',
'metaSeparator' => 'dot',
'excerptLength' => 55,
'readmoreText' => '',
'showAuthor' => true,
'showDate' => true,
'showComments' => true,
'showImage' => true,
'showCategory' => true,
'showTitle' => true,
'showMeta' => true,
'showExcerpt' => true,
'showReadmore' => true,
'columns' => 2,
);
return stackable_attributes_default_v2( $attributes, $defaults );
}
}
if ( ! function_exists( 'stackable_blog_posts_post_query_v2' ) ) {
function stackable_blog_posts_post_query_v2( $attributes ) {
$passed_attributes = array(
'post_type' => $attributes['postType'],
'post_status' => 'publish',
'order' => $attributes['order'],
'orderby' => $attributes['orderBy'],
'numberposts' => $attributes['numberOfItems'],
'suppress_filters' => false,
);
if ( ! empty( $attributes['taxonomy'] ) && ! empty( $attributes['taxonomyType'] ) ) {
// Categories.
if ( $attributes['taxonomyType'] === 'category' ) {
$passed_attributes[ 'category' . $attributes['taxonomyFilterType'] ] = explode( ',', $attributes['taxonomy'] );
// Tags.
} else if ( $attributes['taxonomyType'] === 'post_tag' ) {
$passed_attributes[ 'tag' . $attributes['taxonomyFilterType'] ] = explode( ',', $attributes['taxonomy'] );
// Custom taxonomies.
} else {
$passed_attributes['tax_query'] = array(
array(
'taxonomy' => $attributes['taxonomyType'],
'field' => 'term_id',
'terms' => explode( ',', $attributes['taxonomy'] ),
'operator' => $attributes['taxonomyFilterType'] === '__in' ? 'IN' : 'NOT IN',
),
);
}
}
return apply_filters( 'stackable/blog-post/v2/post_query',
$passed_attributes,
$attributes
);
}
}
/**
* Renders the `ugb/blog-posts` block on server.
*
* @since 1.7
*
* @param array $attributes The block attributes.
*
* @return string Returns the post content with latest posts added.
*/
if ( ! function_exists( 'stackable_render_blog_posts_block_v2' ) ) {
function stackable_render_blog_posts_block_v2( $attributes, $content ) {
// Migrate attributes if this is an old block.
if ( stackable_block_blog_posts_is_deprecated_v2( $attributes, $content ) ) {
$attributes = apply_filters( 'stackable_block_migrate_attributes_v2', $attributes, 'blog-posts' );
}
$attributes = stackable_blog_posts_block_default_attributes_v2( $attributes );
$post_query = stackable_blog_posts_post_query_v2( $attributes );
$recent_posts = wp_get_recent_posts( $post_query );
// Manually slice the array based on the number of posts per page.
if ( is_array( $recent_posts ) && count( $recent_posts ) > (int) $post_query['numberposts'] ) {
$recent_posts = array_slice( $recent_posts, 0, (int) $post_query['numberposts'] );
}
$posts_markup = '';
$show = stackable_blog_posts_util_show_options_v2( $attributes );
$props = array( 'attributes' => array() );
/**
* Classes.
*/
// Item classes.
$item_classes = array( 'ugb-blog-posts__item' );
if ( ! $show['imageShadow'] && (int) $attributes['shadow'] !== 0 ) {
$item_classes[] = 'ugb--shadow-' . $attributes['shadow'];
}
// Add background gradient class.
if ( $show['showBackgroundInItem'] &&
( $attributes['columnBackgroundColorType'] === 'gradient' ||
$attributes['columnBackgroundMediaUrl' ] ||
$attributes['columnTabletBackgroundMediaUrl' ] ||
$attributes['columnMobileBackgroundMediaUrl' ] ) ) {
$item_classes[] = 'ugb--has-background-overlay';
}
$item_classes = implode( ' ', $item_classes );
$content_classes = array( 'ugb-blog-posts__content' );
// Add background gradient class.
if ( $show['showBackgroundInContent'] &&
( $attributes['columnBackgroundColorType'] === 'gradient' ||
$attributes['columnBackgroundMediaUrl' ] ||
$attributes['columnTabletBackgroundMediaUrl' ] ||
$attributes['columnMobileBackgroundMediaUrl' ] ) ) {
$content_classes[] = 'ugb--has-background-overlay';
}
$content_classes = implode( ' ', $content_classes );
// Image classes.
$featured_image_classes = array( 'ugb-blog-posts__featured-image' );
if ( $show['imageShadow'] && (int) $attributes['shadow'] !== 0 ) {
$featured_image_classes[] = 'ugb--shadow-' . $attributes['shadow'];
}
$featured_image_classes = implode( ' ', $featured_image_classes );
/**
* END Classes.
*/
// Meta separators.
$meta_separators = array(
'dot' => '·',
'space' => ' ',
'comma' => ',',
'dash' => '—',
'pipe' => '|',
);
foreach ( $recent_posts as $i => $post ) {
$post_id = $post['ID'];
// Featured image.
$featured_image = '';
$featured_image_background = '';
$featured_image_id = get_post_thumbnail_id( $post_id );
if ( ! empty( $featured_image_id ) ) {
$featured_image_urls = stackable_featured_image_urls_from_url_v2( $featured_image_id );
$featured_image_src = $featured_image_urls[ $attributes['imageSize'] ];
if ( ! empty( $featured_image_src ) ) {
$image_alt = get_post_meta( $featured_image_id, '_wp_attachment_image_alt', true );
$thumbnail = get_the_post_thumbnail(
$post_id,
$attributes['imageSize'],
array(
'alt' => esc_attr( ! empty( $image_alt ) ? $image_alt : '' ),
'width' => esc_attr( $featured_image_src[1] ),
'height' => esc_attr( $featured_image_src[2] ),
)
);
// Get the image tag in the thumbnail markup.
preg_match( "/
]*>/", $thumbnail, $match );
// Remove the built in style attribute in the image.
if ( is_array( $match ) && count( $match ) > 0 ) {
// Only remove the style tag inside the image tag.
$new_img = preg_replace( '/style=\"[^\"]*\"\s?/', "", $match[ 0 ] );
$thumbnail = preg_replace( "/
]*>/", $new_img, $thumbnail );
}
$featured_image = sprintf(
'%s',
esc_attr( $featured_image_classes ),
esc_url( get_permalink( $post_id ) ),
$thumbnail
);
$featured_image_background = sprintf(
'
',
'ugb-blog-posts__featured-image-background',
esc_url( $featured_image_src[0] )
);
}
}
// Title.
$title = get_the_title( $post_id );
if ( ! $title ) {
$title = __( '(Untitled)', STACKABLE_I18N );
}
$title = sprintf(
'<%s class="%s">%s%s>',
$attributes['titleTag'],
'ugb-blog-posts__title',
esc_url( get_permalink( $post_id ) ),
$title,
$attributes['titleTag']
);
// Category.
$category = sprintf(
'%s
',
get_the_category_list( esc_html__( ', ', STACKABLE_I18N ), '', $post_id )
);
// Separator.
$separator = sprintf(
'%s',
$meta_separators[ $attributes['metaSeparator'] ]
);
// Author.
$author = sprintf(
'%s',
esc_html( get_the_author_meta( 'display_name', $post['post_author'] ) )
);
// Date.
$date = sprintf(
'',
esc_attr( get_the_date( 'c', $post_id ) ),
esc_html( get_the_date( '', $post_id ) )
);
// Comments.
$num = get_comments_number( $post_id );
$num = sprintf( _n( '%d comment', '%d comments', $num, STACKABLE_I18N ), $num );
$comments = sprintf(
'%s',
$num
);
// Excerpt.
$excerpt = stackable_get_excerpt_v2( $post_id, $post );
// Trim the excerpt.
if ( ! empty( $excerpt ) ) {
$excerpt = explode( ' ', $excerpt );
$trim_to_length = (int) $attributes['excerptLength'] ? (int) $attributes['excerptLength'] : 55;
if ( count( $excerpt ) > $trim_to_length ) {
$excerpt = implode( ' ', array_slice( $excerpt, 0, $trim_to_length ) ) . '...';
} else {
$excerpt = implode( ' ', $excerpt );
}
$excerpt = sprintf(
'%s
',
wp_kses_post( $excerpt )
);
}
// Read more link.
$readmore_text = __( 'Continue reading', STACKABLE_I18N );
if ( ! empty( $attributes['readmoreText'] ) ) {
$readmore_text = $attributes['readmoreText'];
}
$readmore = sprintf(
'%s
',
esc_url( get_permalink( $post_id ) ),
esc_html( $readmore_text )
);
// Meta.
$showAuthor = $attributes['showAuthor'];
$showDate = $attributes['showDate'];
$showComments = $attributes['showComments'];
$meta = '';
if ( $showAuthor || $showDate || $showComments ) {
$meta = sprintf(
'',
$showAuthor && $author ? $author : '',
$showAuthor && $author && ( ( $showDate && $date ) || ( $showComments && $comments ) ) ? $separator : '',
$showDate && $date ? $date : '',
( ( $showAuthor && $author ) || ( $showDate && $date ) ) && $showComments && $comments ? $separator : '',
$showComments && $comments ? $comments : ''
);
}
$output = apply_filters( 'stackable/blog-posts/v2/edit.output', null, $attributes, array(
'itemClasses' => $item_classes,
'contentClasses' => $content_classes,
'featuredImageBackground' => $featured_image_background,
'featuredImage' => $featured_image,
'category' => $category,
'title' => $title,
'author' => $author,
'separator' => $separator,
'date' => $date,
'comments' => $comments,
'excerpt' => $excerpt,
'readmore' => $readmore,
'meta' => $meta,
), $i );
if ( ! empty( $output ) ) {
$posts_markup .= $output;
} else {
$posts_markup .= sprintf(
'%s%s%s%s%s%s%s%s
',
$item_classes,
$attributes['showImage'] && $show['imageAsBackground'] ? $featured_image_background : '',
$attributes['showImage'] && ! $show['imageAsBackground'] && $show['imageOutsideContainer'] ? $featured_image : '',
$content_classes,
$attributes['showImage'] && ! $show['imageAsBackground'] && ! $show['imageOutsideContainer'] ? $featured_image : '',
$attributes['showCategory'] ? $category : '',
$attributes['showTitle'] ? $title : '',
$attributes['showMeta'] ? $meta : '',
$attributes['showExcerpt'] ? $excerpt : '',
$attributes['showReadmore'] ? $readmore : ''
);
}
}
do_action( 'stackable/blog-posts/v2/render', $attributes, $content );
return apply_filters( 'stackable/blog-posts/v2/edit.output.markup', $posts_markup, $attributes, $content );
}
}
if ( ! function_exists( 'stackable_register_blog_posts_block_v2' ) ) {
/**
* Add our render attributes.
*/
function stackable_register_blog_posts_block_v2( $options, $block_name ) {
if ( $block_name !== 'ugb/blog-posts' ) {
return $options;
}
$options['attributes'] = stackable_blog_posts_attributes_v2();
$options['render_callback'] = 'stackable_render_blog_posts_block_v2';
return $options;
}
add_filter( 'stackable.v2.register-blocks.options', 'stackable_register_blog_posts_block_v2', 10, 2 );
}
if ( ! function_exists( 'stackable_blog_posts_rest_fields_v2' ) ) {
/**
* Add more data in the REST API that we'll use in the blog post.
*
* @since 1.7
*/
function stackable_blog_posts_rest_fields_v2() {
if ( ! has_stackable_v2_frontend_compatibility() && ! has_stackable_v2_editor_compatibility() ) {
return;
}
$post_types = get_post_types( array( 'public' => true ), 'objects' );
foreach ( $post_types as $post_type => $data ) {
if ( $post_type === 'attachment' ) {
continue;
}
// Featured image urls.
register_rest_field( $post_type, 'featured_image_urls_v2',
array(
'get_callback' => 'stackable_featured_image_urls_v2',
'update_callback' => null,
'schema' => array(
'description' => __( 'Different sized featured images', STACKABLE_I18N ),
'type' => 'array',
),
)
);
// Excerpt.
register_rest_field( $post_type, 'post_excerpt_stackable_v2',
array(
'get_callback' => 'stackable_post_excerpt_v2',
'update_callback' => null,
'schema' => array(
'description' => __( 'Post excerpt for Stackable', STACKABLE_I18N ),
'type' => 'string',
),
)
);
// Category links.
register_rest_field( $post_type, 'category_list_v2',
array(
'get_callback' => 'stackable_category_list_v2',
'update_callback' => null,
'schema' => array(
'description' => __( 'Category list links', STACKABLE_I18N ),
'type' => 'string',
),
)
);
// Author name.
register_rest_field( $post_type, 'author_info_v2',
array(
'get_callback' => 'stackable_author_info_v2',
'update_callback' => null,
'schema' => array(
'description' => __( 'Author information', STACKABLE_I18N ),
'type' => 'array',
),
)
);
// Number of comments.
register_rest_field( $post_type, 'comments_num_v2',
array(
'get_callback' => 'stackable_commments_number_v2',
'update_callback' => null,
'schema' => array(
'description' => __( 'Number of comments', STACKABLE_I18N ),
'type' => 'number',
),
)
);
}
}
add_action( 'rest_api_init', 'stackable_blog_posts_rest_fields_v2' );
}
if ( ! function_exists( 'stackable_featured_image_urls_v2' ) ) {
/**
* Get the different featured image sizes that the blog will use.
* Used in the custom REST API endpoint.
*
* @since 1.7
*/
function stackable_featured_image_urls_v2( $object, $field_name, $request ) {
return stackable_featured_image_urls_from_url_v2( ! empty( $object['featured_media'] ) ? $object['featured_media'] : '' );
}
}
if ( ! function_exists( 'stackable_featured_image_urls_from_url_v2' ) ) {
/**
* Get the different featured image sizes that the blog will use.
*
* @since 2.0
*/
function stackable_featured_image_urls_from_url_v2( $attachment_id ) {
$image = wp_get_attachment_image_src( $attachment_id, 'full', false );
$sizes = get_intermediate_image_sizes();
$imageSizes = array(
'full' => is_array( $image ) ? $image : '',
);
foreach ( $sizes as $size ) {
$imageSizes[ $size ] = is_array( $image ) ? wp_get_attachment_image_src( $attachment_id, $size, false ) : '';
}
return $imageSizes;
}
}
if ( ! function_exists( 'stackable_author_info_v2' ) ) {
/**
* Get the author name and link.
*
* @since 1.7
*/
function stackable_author_info_v2( $object ) {
// Some CPTs may not support authors.
if ( ! array_key_exists( 'author', $object ) ) {
return array(
'name' => '',
'url' => '',
);
}
return array(
'name' => get_the_author_meta( 'display_name', $object['author'] ),
'url' => get_author_posts_url( $object['author'] ),
);
}
}
if ( ! function_exists( 'stackable_commments_number_v2' ) ) {
/**
* Get the number of comments.
*
* @since 1.7
*/
function stackable_commments_number_v2( $object ) {
$num = get_comments_number( $object['id'] );
return sprintf( _n( '%d comment', '%d comments', $num, STACKABLE_I18N ), $num );
}
}
if ( ! function_exists( 'stackable_category_list_v2' ) ) {
/**
* Get the category links.
*
* @since 1.7
*/
function stackable_category_list_v2( $object ) {
return get_the_category_list( esc_html__( ', ', STACKABLE_I18N ), '', $object['id'] );
}
}
if ( ! function_exists( 'stackable_post_excerpt_v2' ) ) {
/**
* Get the post excerpt.
*
* @since 1.7
*/
function stackable_post_excerpt_v2( $object ) {
return stackable_get_excerpt_v2( $object['id'] );
}
}
if ( ! function_exists( 'stackable_get_excerpt_v2' ) ) {
/**
* Get the excerpt.
*
* @since 1.7
*/
function stackable_get_excerpt_v2( $post_id, $post = null ) {
// Remove jetpack sharing button.
add_filter( 'sharing_show', '__return_false' );
// If there's an excerpt provided, use it.
$excerpt = get_post_field( 'post_excerpt', $post_id, 'display' );
// We need to check before running the filters since some plugins override it.
if ( ! empty( $excerpt ) ) {
$excerpt = apply_filters( 'the_excerpt', $excerpt );
}
if ( empty( $excerpt ) ) {
$max_excerpt = 100; // WP default is 55.
// If there's post content given to us, trim it and use that.
if ( ! empty( $post['post_content'] ) ) {
$excerpt = apply_filters( 'the_excerpt', wp_trim_words( $post['post_content'], $max_excerpt ) );
} else {
// If there's no post content given to us, then get the content.
$post_content = get_post_field( 'post_content', $post_id );
if ( ! empty( $post_content ) ) {
// Remove the jetpack sharing button filter.
$post_content = apply_filters( 'the_content', $post_content );
$excerpt = apply_filters( 'the_excerpt', wp_trim_words( $post_content, $max_excerpt ) );
}
}
}
// Remove the jetpack sharing button filter.
remove_filter( 'sharing_show', '__return_false' );
return empty( $excerpt ) ? "" : $excerpt;
}
}
if ( ! function_exists( 'stackable_render_block_blog_posts_v2' ) ) {
/**
* Combine our JS & PHP block outputs.
*
* @since 2.0
*/
function stackable_render_block_blog_posts_v2( $block_content, $block ) {
if ( $block['blockName'] !== 'ugb/blog-posts' ) {
return $block_content;
}
if ( empty( $block['innerHTML'] ) ) {
return $block_content;
}
/**
* Our expected SAVE output (generated by save.js) is:
*
*
*
* We need to place the contents inside ".ugb-block-content"
*/
// The innerHTML contains the HTML created by the save JS method.
// Fix the tags or else they will print out escaped.
$new_content = preg_replace( '/</', '<', $block['innerHTML'] );
// Split the content into parts, so that we can place the contents in the correct position.
// This is better than doing a straight preg_replace since the content may contain '$1' that would affect
// the replacement https://github.com/gambitph/Stackable/issues/505
$parts = preg_split( '/(ugb-block-content[\'"]\s*>)/', $new_content, -1, PREG_SPLIT_DELIM_CAPTURE );
if ( count( $parts ) < 3 ) {
return $block_content;
}
return $parts[0] . $parts[1] . $block_content . $parts[2];
}
add_filter( 'render_block', 'stackable_render_block_blog_posts_v2', 10, 2 );
}
if ( ! function_exists( 'stackable_rest_get_terms_v2' ) ) {
/**
* REST Callback. Gets all the terms registered for all post types (including category and tags).
*
* @see https://stackoverflow.com/questions/42462187/wordpress-rest-api-v2-how-to-list-taxonomy-terms
*
* @since 2.0
*/
function stackable_rest_get_terms_v2() {
$args = array(
'public' => true,
);
$taxonomies = get_taxonomies( $args, 'objects' );
$return = array();
$post_types = get_post_types( array( 'public' => true ), 'objects' );
foreach ( $post_types as $post_type => $data ) {
// Don't include attachments.
if ( $post_type === 'attachment' ) {
continue;
}
$return[ $post_type ] = array(
'label' => $data->label,
'taxonomies' => array(),
);
}
foreach ( $taxonomies as $taxonomy_slug => $taxonomy ) {
foreach ( $taxonomy->object_type as $post_type ) {
// Don't include post formats.
if ( $post_type === 'post' && $taxonomy_slug === 'post_format' ) {
continue;
}
$return[ $post_type ]['taxonomies'][ $taxonomy_slug ] = array(
'label' => $taxonomy->label,
'terms' => get_terms( $taxonomy->name ),
);
}
}
return new WP_REST_Response( $return, 200 );
}
}
if ( ! function_exists( 'stackable_get_terms_endpoint_v2' ) ) {
/**
* Define our custom REST API endpoint for getting all the terms/taxonomies.
*
* @since 2.0
*/
function stackable_get_terms_endpoint_v2() {
if ( ! has_stackable_v2_frontend_compatibility() && ! has_stackable_v2_editor_compatibility() ) {
return;
}
register_rest_route( 'stackable/v2', '/terms', array(
'methods' => 'GET',
'callback' => 'stackable_rest_get_terms_v2',
'permission_callback' => function () {
return current_user_can( 'edit_posts' );
},
) );
}
add_action( 'rest_api_init', 'stackable_get_terms_endpoint_v2' );
}
if ( ! function_exists( 'stackable_add_custom_orderby_params_v2' ) ) {
/**
* The callback to add `rand` as an option for orderby param in REST API.
* Hook to `rest_{$this->post_type}_collection_params` filter.
*
* @param array $query_params Accepted parameters.
* @return array
*
* @see https://felipeelia.dev/wordpress-rest-api-enable-random-order-of-posts-list/
* @see https://www.timrosswebdevelopment.com/wordpress-rest-api-post-order/
*/
function stackable_add_custom_orderby_params_v2( $query_params ) {
if ( ! in_array( 'rand', $query_params['orderby']['enum'] ) ) {
$query_params['orderby']['enum'][] = 'rand';
}
if ( ! in_array( 'menu_order', $query_params['orderby']['enum'] ) ) {
$query_params['orderby']['enum'][] = 'menu_order';
}
return $query_params;
}
}
if ( ! function_exists( 'stackable_add_custom_orderby_v2' ) ) {
/**
* Add `rand` as an option for orderby param in REST API.
* Hook to `rest_{$this->post_type}_collection_params` filter.
*
* @param array $query_params Accepted parameters.
* @return array
*
* @see https://felipeelia.dev/wordpress-rest-api-enable-random-order-of-posts-list/
* @see https://www.timrosswebdevelopment.com/wordpress-rest-api-post-order/
*/
function stackable_add_custom_orderby_v2() {
if ( ! has_stackable_v2_frontend_compatibility() && ! has_stackable_v2_editor_compatibility() ) {
return;
}
$post_types = get_post_types( array( 'public' => true ) );
foreach ( $post_types as $post_type ) {
add_filter( 'rest_' . $post_type . '_collection_params', 'stackable_add_custom_orderby_params_v2' );
}
}
add_action( 'rest_api_init', 'stackable_add_custom_orderby_v2' );
}