0

I am working on a theme and want to hide the first blog post and instead output it at a custom widget position. For that I created a variable in the functions.php called $postCounter.

I accessed the variable in the header.php at the top with global $postCounter

Then in the index.php:

<?php while ( have_posts() ) : the_post(); $postCounter++; ?>
    <?php if ($postCounter > 1) : ?>
        Loop here
    <?php endif; ?>
<?php endwhile; ?>

That works great but how can I output the first blog post in a custom widget area? For better understanding: I want the first post to have full width at the top of the page, and the rest (starting from the second post) to be in the content area with a sidebar.

Unfortunately the Wordpress Widget "Latest Posts" (I guess thats the name in English) only outputs a link to the Post/s.

Does somebody have an idea?

1
  • Sorry! I used a plugin in the end to output a complete post Jun 11, 2015 at 23:32

1 Answer 1

0

Here is a cleaner method which does not skip the first post in the loop

As this is the main query on the home page, we can do the following:

  • Use pre_get_posts to alter the main query on the homepage so as to set an offset of one so that the newest post is ignored.

  • Recalculate the amount of posts found so that pagination works correctly in calculating the amount of pages to show.

  • Offset each page by one because we have excluded one post from page 1

Here is the code which goes into your functions.php: (NOTE: This code needs at least PHP 5.3 as it uses anonymous functions/closures. If you are using older PHP versions, upgrade your PHP version, versions PHP 5.3 and lower is dead)

add_action( 'pre_get_posts', function ( $q ) {

    if( !is_admin() && $q->is_main_query() && $q->is_home() ) {

        $offset = 1;
        $ppp = get_option( 'posts_per_page' );

        if ( !$q->is_paged() ) {

            $q->set( 'offset', $offset );

        } else {

            $offset = $offset + ( ( $q->query_vars['paged']-1 ) * $ppp );
            $q->set( 'offset', $offset );

        }

    }
    return $q;

});

//Recalculate found_posts for the home page
add_filter( 'found_posts', function ( $found_posts, $q ) {
    $offset = 1;

    if( $q->is_home() && $q->is_main_query() ) {
        $found_posts = $found_posts - $offset;
    }
    return $found_posts;

}, 10, 2 );

This will now take care to eliminate the newest post from the homepage loop. Now for the widget

I have quickly modified one of my widgets for this purpose to display the latest/newest post. You will just need to modify it to suite your exact needs, and also apply your own markup and styling

I'm not going to go into the details here as the Widget API is quite extensive. You will need to go and study this in your own time

Here is the widget: (NOTE: This widget needs at least PHP 5.4)

/**
 * Newest_Post_Widget widget class
 *
 * Displays the newest post
 *
 * @since 1.0.0
*/
class Newest_Post_Widget extends WP_Widget {

    public function __construct() {
        parent::__construct(
            'widget_newest_posts', 
            _x( 'Newest Post Widget', 'Tagged Posts Widget' ), 
            [ 'description' => __( 'Displays the newest post.' ), 
            ]
        );
        $this->alt_option_name = 'widget_newest_posts';

        add_action( 'save_post', [$this, 'flush_widget_cache'] );
        add_action( 'deleted_post', [$this, 'flush_widget_cache'] );
        add_action( 'switch_theme', [$this, 'flush_widget_cache'] );
    }

    public function widget( $args, $instance ) {
        $cache = [];
        if ( ! $this->is_preview() ) {
            $cache = wp_cache_get( 'widget_new_posts', 'widget' );
        }

        if ( ! is_array( $cache ) ) {
            $cache = [];
        }

        if ( ! isset( $args['widget_id'] ) ) {
            $args['widget_id'] = $this->id;
        }

        if ( isset( $cache[ $args['widget_id'] ] ) ) {
            echo $cache[ $args['widget_id'] ];
            return;
        }

        ob_start();

        $title          = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Newest Post' );
        /** This filter is documented in wp-includes/default-widgets.php */
        $title          = apply_filters( 'widget_title', $title, $instance, $this->id_base );

        /**
         * Filter the arguments for the Newest Post widget.
         *
         * @since 1.0.0
         *
         * @see WP_Query::get_posts()
         *
         * @param array $args An array of arguments used to retrieve the newest post
         */
        $query_args = [
            'posts_per_page'    => 1,
        ];
        $q = new WP_Query( apply_filters( 'newest_post_args', $query_args ) );

        if( $q->have_posts() ) {

            echo $args['before_widget'];
            if ( $title ) {
                echo $args['before_title'] . $title . $args['after_title'];
            }               

            while( $q->have_posts() ) {
                $q->the_post(); ?>

                <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 

                    <header class="entry-header">
                        <?php the_title( '<h1 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h1>' ); ?>
                    </header><!-- .entry-header -->

                    <?php 
                    if ( has_post_thumbnail() ) { ?>

                        <div class="post-thumbnail">

                            <?php the_post_thumbnail(); ?>

                        </div><!--/.post-thumbnail-->

                    <?php   
                    }
                    ?>

                        <div class="entry-content">
                            <?php the_content(); ?>
                        </div><!-- .entry-content -->


                </article><!-- #post-## -->

                <?php
            }


            wp_reset_postdata();
        }
            echo $args['after_widget']; 

        if ( ! $this->is_preview() ) {
            $cache[ $args['widget_id'] ] = ob_get_flush();
            wp_cache_set( 'widget_new_posts', $cache, 'widget' );
        } else {
            ob_end_flush();
        }
    }

    public function update( $new_instance, $old_instance ) {
        $instance                   = $old_instance;
        $instance['title']          = strip_tags( $new_instance['title'] );
        $this->flush_widget_cache();

        $alloptions = wp_cache_get( 'alloptions', 'options' );
        if ( isset($alloptions['widget_newest_posts']) )
            delete_option('widget_newest_posts');

        return $instance;
    }

    public function flush_widget_cache() {
        wp_cache_delete('widget_new_posts', 'widget');
    }

    public function form( $instance ) {

        $title      = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
        ?>

        <p>
            <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo $title; ?>" />
        </p>


    <?php
    }

}

add_action( 'widgets_init', function () {
    register_widget( 'Newest_Post_Widget' );
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.