Skip to content

Instantly share code, notes, and snippets.

@billerickson
Created April 14, 2020 14:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save billerickson/2b00b4602a496cf1961c016c02d4ab12 to your computer and use it in GitHub Desktop.
Save billerickson/2b00b4602a496cf1961c016c02d4ab12 to your computer and use it in GitHub Desktop.
This file (included in functions.php) adds a Post Listing block using ACF. Key points of customization:
<?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