Skip to content

Instantly share code, notes, and snippets.

@srikat
Forked from GaryJones/readme.md
Last active April 3, 2022 16:29
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save srikat/8e7ecf30329462f91e8d15d9ff448aef to your computer and use it in GitHub Desktop.
Save srikat/8e7ecf30329462f91e8d15d9ff448aef to your computer and use it in GitHub Desktop.
Custom Featured Posts Widget plugin: Skeleton for amending the output of the Genesis Featured Posts widget. https://sridharkatakam.com/custom-featured-post-widget-plugin/
<?php
/**
* Plugin Name
*
* @package Custom_Featured_Post_Widget
* @author Gary Jones
* @license GPL-2.0+
* @link http://gamajo.com/
* @copyright 2013 Gary Jones, Gamajo Tech
*/
/**
* Custom Featured Post widget class.
*
* @package Custom_Featured_Post_Widget
* @author Gary Jones
*/
class Custom_Featured_Post extends Genesis_Featured_Post {
/**
* Echo the widget content.
*
* @since 1.0.0
*
* @global WP_Query $wp_query Query object.
* @global array $_genesis_displayed_ids Array of displayed post IDs.
* @global int $more
*
* @param array $args Display arguments including `before_title`, `after_title`,
* `before_widget`, and `after_widget`.
* @param array $instance The settings for the particular instance of the widget.
*/
public function widget( $args, $instance ) {
global $wp_query, $_genesis_displayed_ids;
// Merge with defaults.
$instance = wp_parse_args( (array) $instance, $this->defaults );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['before_widget'];
if ( ! empty( $instance['title'] ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ) . $args['after_title'];
}
$query_args = [
'post_type' => 'post',
'cat' => $instance['posts_cat'],
'showposts' => $instance['posts_num'],
'offset' => $instance['posts_offset'],
'orderby' => $instance['orderby'],
'order' => $instance['order'],
'ignore_sticky_posts' => $instance['exclude_sticky'],
];
// Exclude displayed IDs from this loop?
if ( $instance['exclude_displayed'] ) {
$query_args['post__not_in'] = (array) $_genesis_displayed_ids;
}
$wp_query = new WP_Query( $query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Reset later.
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
$_genesis_displayed_ids[] = get_the_ID();
genesis_markup(
[
'open' => '<article %s>',
'context' => 'entry',
'params' => [
'is_widget' => true,
],
]
);
$image = genesis_get_image(
[
'format' => 'html',
'size' => $instance['image_size'],
'context' => 'featured-post-widget',
'attr' => genesis_parse_attr( 'entry-image-widget', [] ),
]
);
if ( $image && $instance['show_image'] ) {
$role = empty( $instance['show_title'] ) ? '' : ' aria-hidden="true" tabindex="-1"';
printf(
'<a href="%s" class="%s"%s>%s</a>',
esc_url( get_permalink() ),
esc_attr( $instance['image_alignment'] ),
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping breaks output here
$role,
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaping breaks output here
wp_make_content_images_responsive( $image )
);
}
if ( ! empty( $instance['show_gravatar'] ) ) {
echo '<span class="' . esc_attr( $instance['gravatar_alignment'] ) . '">';
echo get_avatar( get_the_author_meta( 'ID' ), $instance['gravatar_size'] );
echo '</span>';
}
if ( $instance['show_title'] || $instance['show_byline'] ) {
$header = '';
if ( ! empty( $instance['show_title'] ) ) {
$title = get_the_title() ?: __( '(no title)', 'genesis' );
/**
* Filter the featured post widget title.
*
* @since 2.2.0
*
* @param string $title Featured post title.
* @param array $instance {
* Widget settings for this instance.
*
* @type string $title Widget title.
* @type int $posts_cat ID of the post category.
* @type int $posts_num Number of posts to show.
* @type int $posts_offset Number of posts to skip when
* retrieving.
* @type string $orderby Field to order posts by.
* @type string $order ASC for ascending order, DESC for
* descending order of posts.
* @type bool $exclude_displayed True if posts shown in main output
* should be excluded from this widget
* output.
* @type bool $show_image True if featured image should be
* shown, false otherwise.
* @type string $image_alignment Image alignment: `alignnone`,
* `alignleft`, `aligncenter` or `alignright`.
* @type string $image_size Name of the image size.
* @type bool $show_gravatar True if author avatar should be
* shown, false otherwise.
* @type string $gravatar_alignment Author avatar alignment: `alignnone`,
* `alignleft` or `aligncenter`.
* @type int $gravatar_size Dimension of the author avatar.
* @type bool $show_title True if featured page title should
* be shown, false otherwise.
* @type bool $show_byline True if post info should be shown,
* false otherwise.
* @type string $post_info Post info contents to show.
* @type bool $show_content True if featured page content
* should be shown, false otherwise.
* @type int $content_limit Amount of content to show, in
* characters.
* @type int $more_text Text to use for More link.
* @type int $extra_num Number of extra post titles to show.
* @type string $extra_title Heading for extra posts.
* @type bool $more_from_category True if showing category archive
* link, false otherwise.
* @type string $more_from_category_text Category archive link text.
* }
* @param array $args {
* Widget display arguments.
*
* @type string $before_widget Markup or content to display before the widget.
* @type string $before_title Markup or content to display before the widget title.
* @type string $after_title Markup or content to display after the widget title.
* @type string $after_widget Markup or content to display after the widget.
* }
*/
$title = apply_filters( 'genesis_featured_post_title', $title, $instance, $args );
$heading = genesis_a11y( 'headings' ) ? 'h4' : 'h2';
$header .= genesis_markup(
[
'open' => "<{$heading} %s>",
'close' => "</{$heading}>",
'context' => 'entry-title',
'content' => sprintf( '<a href="%s">%s</a>', get_permalink(), $title ),
'params' => [
'is_widget' => true,
'wrap' => $heading,
],
'echo' => false,
]
);
}
if ( ! empty( $instance['show_byline'] ) && ! empty( $instance['post_info'] ) ) {
$header .= genesis_markup(
[
'open' => '<p %s>',
'close' => '</p>',
'context' => 'entry-meta',
'content' => genesis_strip_p_tags( do_shortcode( $instance['post_info'] ) ),
'params' => [
'is_widget' => true,
],
'echo' => false,
]
);
}
genesis_markup(
[
'open' => '<header %s>',
'close' => '</header>',
'context' => 'entry-header',
'params' => [
'is_widget' => true,
],
'content' => $header,
]
);
}
if ( ! empty( $instance['show_content'] ) ) {
genesis_markup(
[
'open' => '<div %s>',
'context' => 'entry-content',
'params' => [
'is_widget' => true,
],
]
);
if ( 'excerpt' === $instance['show_content'] ) {
the_excerpt();
} elseif ( 'content-limit' === $instance['show_content'] ) {
the_content_limit( (int) $instance['content_limit'], genesis_a11y_more_link( esc_html( $instance['more_text'] ) ) );
} else {
global $more;
$orig_more = $more;
$more = 0; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Temporary change.
the_content( genesis_a11y_more_link( esc_html( $instance['more_text'] ) ) );
$more = $orig_more; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Global is being restored.
}
genesis_markup(
[
'close' => '</div>',
'context' => 'entry-content',
'params' => [
'is_widget' => true,
],
]
);
}
genesis_markup(
[
'close' => '</article>',
'context' => 'entry',
'params' => [
'is_widget' => true,
],
]
);
}
}
// Restore original query.
wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- Making sure the query is really reset.
// The EXTRA Posts (list).
if ( ! empty( $instance['extra_num'] ) ) {
if ( ! empty( $instance['extra_title'] ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['before_title'] . '<span class="more-posts-title">' . esc_html( $instance['extra_title'] ) . '</span>' . $args['after_title'];
}
$offset = (int) $instance['posts_num'] + (int) $instance['posts_offset'];
$query_args = [
'cat' => $instance['posts_cat'],
'showposts' => $instance['extra_num'],
'offset' => $offset,
];
$wp_query = new WP_Query( $query_args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Reset later.
$listitems = '';
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
$_genesis_displayed_ids[] = get_the_ID();
$listitems .= sprintf( '<li><a href="%s">%s</a></li>', esc_url( get_permalink() ), esc_html( get_the_title() ) );
}
if ( '' !== $listitems ) {
printf( '<ul class="more-posts">%s</ul>', $listitems ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped before.
}
}
// Restore original query.
wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- Making sure the query is really reset.
}
if ( ! empty( $instance['more_from_category'] ) && ! empty( $instance['posts_cat'] ) ) {
printf(
'<p class="more-from-category"><a href="%1$s" title="%2$s">%3$s</a></p>',
esc_url( get_category_link( $instance['posts_cat'] ) ),
esc_attr( get_cat_name( $instance['posts_cat'] ) ),
esc_html( $instance['more_from_category_text'] )
);
}
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['after_widget'];
}
}
<?php
/**
* Custom Featured Post Widget
*
* @package Custom_Featured_Post_Widget
* @author Gary Jones
* @license GPL-2.0+
* @link http://gamajo.com/
* @copyright 2013 Gary Jones, Gamajo Tech
*
* @wordpress-plugin
* Plugin Name: Custom Featured Post Widget
* Plugin URI: http://gamajo.com/...
* Description: Provides a canvas for modifying Genesis Featured Post Widget.
* Version: 1.0.3
* Author: Gary Jones
* Author URI: http://gamajo.com/
* Text Domain: custom-featured-post-widget
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Domain Path: /languages
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
register_activation_hook( __FILE__, 'custom_activation_check' );
/**
* Check if Genesis is the parent theme.
*/
function custom_activation_check() {
$theme_info = wp_get_theme();
$genesis_flavors = array(
'genesis',
'genesis-trunk',
);
if ( ! in_array( $theme_info->Template, $genesis_flavors, true ) ) {
deactivate_plugins( plugin_basename( __FILE__ ) ); // Deactivate ourself.
$message = sprintf(
/* translators: %s: URL to Genesis Framework. */
__( 'Sorry, you can\'t activate this plugin unless you have installed <a href="%s">Genesis</a>.', 'genesis-simple-hook-guide' ),
esc_url( 'https://my.studiopress.com/themes/genesis/' )
);
wp_die( $message );
}
}
add_action( 'widgets_init', 'custom_featured_post_widget', 15 );
/**
* Register widgets for use in a Genesis child theme.
*
* @since 1.0.0
*/
function custom_featured_post_widget() {
require plugin_dir_path( __FILE__ ) . 'class-custom-featured-post.php';
unregister_widget( 'Genesis_Featured_Post' );
register_widget( 'Custom_Featured_Post' );
}
/* Note: If the require is happening too late, then move into a new function, hooked to genesis_setup, 15 instead:
add_action( 'genesis_setup', 'custom_featured_post_load_class', 15 );
function custom_featured_post_load_class() {
require plugin_dir_path( __FILE__ ) . 'class-custom-featured-post.php';
}
*/
@srikat
Copy link
Author

srikat commented Sep 6, 2016

@WPDevHQ
Copy link

WPDevHQ commented Sep 6, 2016

Please use wp_reset_postdata(); instead of wp_reset_query(); in class-custom-featured-post.php @ line 229

@jhbanks
Copy link

jhbanks commented Sep 7, 2016

Please add the function to plugin to prevent plugin from being activated on sites where Genesis isn't installed (especially useful in situation where plugins can be mass activated across a multisite network.) Thank you!

@aminta
Copy link

aminta commented Nov 17, 2016

Great plugin, thanks!

@srikat
Copy link
Author

srikat commented Sep 20, 2017

@WPDevHQ I've created an issue in Genesis GH repo. Will update this based on the replies I get there.

@srikat
Copy link
Author

srikat commented Sep 21, 2017

@WPDevHQ Here's the response from Bill Erickson:

wp_reset_query() is correct because those widgets are overwriting the global $wp_query. wp_reset_query() resets this back to the correct global $wp_query, using $wp_the_query, then runs wp_reset_postdata().

If those widgets used a different variable for the query, like $loop = new WP_Query(), then we could use wp_reset_postdata() as the only global variable that needs resetting is $post.

@srikat
Copy link
Author

srikat commented Sep 21, 2017

@grcwordpress Done.

@mmgmoro
Copy link

mmgmoro commented Jan 17, 2018

I'm getting a blank site when I try to activate - does the plugin work with the most recent Genesis install?

@srikat
Copy link
Author

srikat commented Mar 22, 2018

@mmgmoro Yes, it works fine the current latest Genesis. No problem here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment