This file (included in functions.php) adds a Post Listing block using ACF. Key points of customization:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Post Listing | |
* | |
* @package CultivateBlocks | |
* @author Bill Erickson | |
* @since 1.0.0 | |
* @license GPL-2.0+ | |
**/ | |
class BE_Post_Listing { | |
/** | |
* Refers to a single instance of this class | |
* | |
* @var null | |
*/ | |
private static $instance = null; | |
/** | |
* Layouts | |
* | |
* @var array | |
*/ | |
private $layouts = []; | |
/** | |
* Taxonomies | |
* | |
* @var array | |
*/ | |
private $taxonomies = []; | |
/** | |
* Creates or returns an instance of this class. | |
* | |
* @since 0.1.8 | |
* @return object BE_Post_Listing, a single instance of this class. | |
*/ | |
public static function instance() { | |
if ( null == self::$instance ) { | |
self::$instance = new self; | |
} | |
return self::$instance; | |
} | |
/** | |
* Construct | |
* | |
* @since 0.1.0 | |
*/ | |
function __construct() { | |
$this->setup(); | |
// Create block | |
add_action('acf/init', array( $this, 'register_block' ) ); | |
} | |
/** | |
* Setup Layouts and Taxonomies | |
* | |
*/ | |
function setup() { | |
$this->layouts = [ | |
'alpha' => [ | |
'label' => '3 Column', | |
'posts_per_page' => 3, | |
'partial' => 'primary', | |
], | |
'beta' => [ | |
'label' => '4 Column', | |
'posts_per_page' => 4, | |
'partial' => 'tertiary', | |
], | |
'gamma' => [ | |
'label' => '2x2 Grid', | |
'posts_per_page' => 4, | |
'partial' => 'secondary', | |
], | |
'delta' => [ | |
'label' => 'Feature', | |
'posts_per_page' => 4, | |
'partial' => 'secondary', | |
'partial_override' => [ | |
0 => 'feature', | |
] | |
], | |
]; | |
$this->taxonomies = [ | |
[ | |
'tax' => 'category', | |
'field' => 'category', | |
'label' => 'Category', | |
], | |
[ | |
'tax' => 'post_tag', | |
'field' => 'post_tag', | |
'label' => 'Tag', | |
] | |
]; | |
} | |
/** | |
* Register post listing block | |
* | |
*/ | |
function register_block() { | |
acf_register_block_type( array( | |
'name' => 'post-listing', | |
'title' => __( 'Post Listing', 'cultivate_textdomains' ), | |
'render_callback' => array( $this, 'post_listing_block' ), | |
'category' => 'cultivatewp', | |
'icon' => be_icon( [ 'icon' => 'cultivatewp', 'group' => 'color', 'size' => 24 ] ), | |
'mode' => 'auto', | |
'supports' => [ 'anchor' => false, 'align' => false ] | |
)); | |
$layout_choices = []; | |
foreach( $this->layouts as $layout => $atts ) { | |
$layout_choices[ $layout ] = $atts['label']; | |
} | |
$fields = array( | |
array( | |
'key' => 'field_5e6a893b53d10', | |
'label' => 'Title', | |
'name' => 'title', | |
'type' => 'text', | |
'instructions' => '', | |
'required' => 0, | |
'conditional_logic' => 0, | |
'wrapper' => array( | |
'width' => '', | |
'class' => '', | |
'id' => '', | |
), | |
'default_value' => '', | |
'placeholder' => '', | |
'prepend' => '', | |
'append' => '', | |
'maxlength' => '', | |
), | |
array( | |
'key' => 'field_5e6a894753d11', | |
'label' => 'Layout', | |
'name' => 'layout', | |
'type' => 'select', | |
'instructions' => '', | |
'required' => 0, | |
'conditional_logic' => 0, | |
'wrapper' => array( | |
'width' => '', | |
'class' => '', | |
'id' => '', | |
), | |
'choices' => $layout_choices, | |
'default_value' => array( | |
), | |
'allow_null' => 0, | |
'multiple' => 0, | |
'ui' => 0, | |
'return_format' => 'value', | |
'ajax' => 0, | |
'placeholder' => '', | |
), | |
array( | |
'key' => 'field_5e6a895053d12', | |
'label' => 'Order', | |
'name' => 'orderby', | |
'type' => 'select', | |
'instructions' => '', | |
'required' => 0, | |
'conditional_logic' => 0, | |
'wrapper' => array( | |
'width' => '', | |
'class' => '', | |
'id' => '', | |
), | |
'choices' => array( | |
'recent' => 'Recent', | |
'popular' => 'Popular', | |
'manual' => 'Manual', | |
), | |
'default_value' => array( | |
), | |
'allow_null' => 0, | |
'multiple' => 0, | |
'ui' => 0, | |
'return_format' => 'value', | |
'ajax' => 0, | |
'placeholder' => '', | |
), | |
array( | |
'key' => 'field_5e6a897453d13', | |
'label' => 'Posts', | |
'name' => 'post__in', | |
'type' => 'post_object', | |
'instructions' => '', | |
'required' => 0, | |
'conditional_logic' => array( | |
array( | |
array( | |
'field' => 'field_5e6a895053d12', | |
'operator' => '==', | |
'value' => 'manual', | |
), | |
), | |
), | |
'wrapper' => array( | |
'width' => '', | |
'class' => '', | |
'id' => '', | |
), | |
'post_type' => array( | |
0 => 'post', | |
), | |
'taxonomy' => '', | |
'allow_null' => 1, | |
'multiple' => 1, | |
'return_format' => 'id', | |
'ui' => 1, | |
), | |
array( | |
'key' => 'field_8e6a893b53d10', | |
'label' => 'Read More', | |
'name' => 'read_more', | |
'type' => 'text', | |
'instructions' => '', | |
'required' => 0, | |
'conditional_logic' => 0, | |
'wrapper' => array( | |
'width' => '', | |
'class' => '', | |
'id' => '', | |
), | |
'default_value' => '', | |
'placeholder' => '', | |
'prepend' => '', | |
'append' => '', | |
'maxlength' => '', | |
), | |
); | |
foreach( $this->taxonomies as $i => $taxonomy ) { | |
$fields[] = [ | |
'key' => 'field_5e6a8aa253d2' . $i, | |
'label' => 'Limit to ' . $taxonomy['label'], | |
'name' => $taxonomy['field'], | |
'type' => 'taxonomy', | |
'instructions' => '', | |
'required' => 0, | |
'conditional_logic' => 0, | |
'taxonomy' => $taxonomy['tax'], | |
'field_type' => 'multi_select', | |
'all_null' => 1, | |
'add_term' => 0, | |
'save_terms' => 0, | |
'load_terms' => 0, | |
'return_format' => 'id', | |
'multiple' => 1, | |
]; | |
} | |
acf_add_local_field_group(array( | |
'key' => 'group_5e6a89326b7cb', | |
'title' => 'Post Listing Block', | |
'fields' => $fields, | |
'location' => array( | |
array( | |
array( | |
'param' => 'block', | |
'operator' => '==', | |
'value' => 'acf/post-listing', | |
), | |
), | |
), | |
'menu_order' => 0, | |
'position' => 'normal', | |
'style' => 'default', | |
'label_placement' => 'top', | |
'instruction_placement' => 'label', | |
'hide_on_screen' => '', | |
'active' => true, | |
'description' => '', | |
)); | |
} | |
/** | |
* Post Listing Block | |
* | |
*/ | |
function post_listing_block( $block, $content = '', $is_preview = false, $post_id = 0 ) { | |
$settings = [ | |
'title' => get_field( 'title' ), | |
'layout' => get_field( 'layout' ), | |
'orderby' => get_field( 'orderby' ), | |
'post__in' => get_field( 'post__in' ), | |
'title' => get_field( 'title' ), | |
'read_more' => get_field( 'read_more' ) | |
]; | |
foreach( $this->taxonomies as $taxonomy ) { | |
$settings[ $taxonomy['field'] ] = get_field( $taxonomy['field'] ); | |
} | |
if( !empty( $block['className'] ) ) | |
$settings['className'] = $block['className']; | |
if( !empty( $block['anchor'] ) ) | |
$settings['anchor'] = $block['anchor']; | |
$this->display( $settings ); | |
} | |
/** | |
* Display | |
* | |
*/ | |
function display( $settings = [] ) { | |
$classes = ['block-post-listing']; | |
if( !empty( $settings['className'] ) ) | |
$classes = array_merge( $classes, explode( ' ', $settings['className'] ) ); | |
if( !empty( $settings['layout'] ) ) | |
$classes[] = 'layout-' . $settings['layout']; | |
$anchor = ''; | |
if( !empty( $settings['anchor'] ) ) | |
$anchor = ' id="' . sanitize_title( $settings['anchor'] ) . '"'; | |
$loop = new WP_Query( $this->query_args( $settings ) ); | |
if( ! $loop->have_posts() ) | |
return; | |
echo '<section class="' . join( ' ', $classes ) . '"' . $anchor . '>'; | |
if( !empty( $settings['title'] ) ) | |
echo '<header><h2>' . esc_html( $settings['title'] ) . '</h2></header>'; | |
echo '<div class="block-post-listing__inner">'; | |
while( $loop->have_posts() ): $loop->the_post(); | |
$partial = $this->partial( $settings['layout'], $loop->current_post ); | |
get_template_part( 'partials/post-summary/' . $partial ); | |
endwhile; | |
wp_reset_postdata(); | |
echo '</div>'; | |
$this->display_footer( $settings ); | |
echo '</section>'; | |
} | |
/** | |
* Display Footer | |
* | |
*/ | |
function display_footer( $settings = [] ) { | |
if( empty( $settings['read_more'] ) ) | |
return; | |
$has_tax = $link = false; | |
foreach( $this->taxonomies as $taxonomy ) { | |
if( !empty( $settings[ $taxonomy['field'] ] ) ) { | |
$has_tax = true; | |
$terms = $settings[ $taxonomy['field'] ]; | |
if( ! is_array( $terms ) ) | |
$terms = array( $terms ); | |
if( 1 < count( $terms ) ) | |
return false; | |
$term = get_term_by( 'id', $terms[0], $taxonomy['tax'] ); | |
if( empty( $term ) || is_wp_error( $term ) || !empty( $more_link ) ) | |
return false; | |
$link = get_term_link( $term, $taxonomy['tax'] ); | |
} | |
} | |
if( ! $has_tax && get_option( 'page_for_posts' ) && ( empty( $settings['post_type' ] ) || 'post' === $settings['post_type'] ) ) | |
$link = get_permalink( get_option( 'page_for_posts' ) ); | |
if( ! $has_tax && !empty( $settings['post_type'] ) && 'post' !== $settings['post_type'] ) | |
$link = get_post_type_archive_link( $settings['post_type'] ); | |
if( !empty( $link ) ) | |
echo '<footer><a href="' . esc_url( $link ) . '">' . esc_html( $settings['read_more'] ) . '</a></footer>'; | |
} | |
/** | |
* Query Arguments | |
* | |
*/ | |
function query_args( $settings ) { | |
$args = [ | |
'posts_per_page' => 4, | |
'post_status' => 'publish', | |
]; | |
if( !empty( $settings['post__not_in'] ) ) | |
$args['post__not_in'] = $settings['post__not_in']; | |
if( !empty( $settings['layout'] ) && array_key_exists( $settings['layout'], $this->layouts ) ) | |
$args['posts_per_page'] = $this->layouts[ $settings['layout'] ]['posts_per_page']; | |
if( !empty( $settings['orderby'] ) && 'popular' === $settings['orderby'] ) { | |
// Order by comment count | |
$args['orderby'] = 'comment_count'; | |
/* | |
// Order by share count | |
$args['orderby'] = 'meta_value_num'; | |
$args['meta_key'] = 'shared_counts_total'; | |
*/ | |
/* | |
// Limit by post date | |
$args['date_query'] = array( | |
array( | |
'after' => '-3 months', | |
) | |
); | |
*/ | |
} | |
foreach( $this->taxonomies as $taxonomy ) { | |
if( !empty( $settings[ $taxonomy['field'] ] ) ) { | |
$terms = $settings[ $taxonomy['field'] ]; | |
if( ! is_array( $terms ) ) | |
$terms = array( $terms ); | |
$tax_args = [ | |
'taxonomy' => $taxonomy['tax'], | |
'field' => 'term_id', | |
'terms' => $terms, | |
'include_children' => true, | |
]; | |
if( 1 < count( $tax_args['terms'] ) ) { | |
$tax_args['operator'] = 'AND'; | |
$tax_args['include_children'] = false; | |
} | |
$args['tax_query'][] = $tax_args; | |
} | |
} | |
if( !empty( $settings['orderby'] ) && 'manual' === $settings['orderby'] ) { | |
if( !empty( $args['tax_query'] ) ) | |
unset( $args['tax_query'] ); | |
if( empty( $settings['post__in'] ) ) | |
$post_ids = [ 1 ]; // no post with ID = 1, will return no results | |
elseif( ! is_array( $settings['post__in'] ) ) | |
$post_ids = [ intval( $settings['post__in'] ) ]; | |
else | |
$post_ids = array_map( 'intval', $settings['post__in'] ); | |
$args['post__in'] = $post_ids; | |
$args['orderby'] = 'post__in'; | |
} | |
return $args; | |
} | |
/** | |
* Partial | |
* | |
*/ | |
function partial( $layout = false, $current_post = 0 ) { | |
$partial = false; | |
if( ! $layout ) | |
return $partial; | |
if( empty( $this->layouts[ $layout ] ) ) | |
return $partial; | |
$layout = $this->layouts[ $layout ]; | |
// Post specific partial | |
if( !empty( $layout['partial_override'] ) && !empty( $layout['partial_override'][ $current_post ] ) ) | |
$partial = $layout['partial_override'][ $current_post ]; | |
// Layout specific partial | |
if( empty( $partial ) ) | |
$partial = $layout['partial']; | |
return $partial; | |
} | |
} | |
function be_post_listing() { | |
return BE_Post_Listing::instance(); | |
} | |
be_post_listing(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment