Tag Archives: plugin

Posts on Page WordPress Widget Plugin

I was disappointed to find that there wasn’t a “Posts on Page” widget plugin for WordPress. I wanted something that would:

  1. Display a list of all the posts on a page
  2. The title is optional
  3. Also, add “Recent Posts”
  4. Again the recent posts title could be optional
  5. The number of recent posts could be fixed or variable based on the number of posts on the page (I use 5 fixed)
  6. The recent posts could be selected by category, by tag, or by both – so you can effectively add “featured” posts
  7. Display all as a <ul> list (or not)

So I learned how to create a WordPress plugin that creates a widget, there’s a tutorial here: https://horkan.com/2023/08/08/creating-a-wordpress-widget-plugin-tutorial

And then built my own. It should be over there on the right, doing its job.

You can download the widget from here: http://horkan.com/wp-content/uploads/2023/08/posts-on-page-widget.zip

The code is below. I’ll add it to GitHub later.

<?php
/**
 * Plugin Name: Posts on Page Widget
 * Plugin URI: https://horkan.com/posts-on-page-wordpress-widget-plugin 
 * Description: A widget that displays a list of all posts displayed on the current page.
 * Version: 1.0
 * Author: Wayne Horkan
 * Author URI: https://horkan.com
 * License: MIT
 */

 // Register and load the widget
function posts_on_page_widget_load() {
    register_widget( 'Posts_On_Page_Widget' );
}
add_action( 'widgets_init', 'posts_on_page_widget_load' );

class Posts_On_Page_Widget extends WP_Widget {
    public function __construct() {
        $widget_options = array( 
            'classname' => 'posts_on_page_widget',
            'description' => 'This is a plugin developed by Wayne Horkan that displays a list of all posts displayed on the current page.',
        );
        parent::__construct( 'posts_on_page_widget', 'Posts on Page Widget', $widget_options );
    }

    public function widget( $args, $instance ) {

        if(isset($instance['title'])) {
            
            $title = apply_filters( 'widget_title', $instance[ 'title' ] );
            echo $args['before_widget'] . $args['before_title'] . $title . $args['after_title'];
        }

        global $posts;

        if (empty($posts)) {
            $posts = get_posts();
        }

        $total_posts_to_show = count($posts);
        $displayed_posts     = 0;

        if ($instance['use_list']) {
            echo '<ul>';
            foreach ($posts as $post) {
                if($displayed_posts < $total_posts_to_show) {
                    echo '<li><a href="' . get_permalink($post) . '">' . $post->post_title . '</a></li>';
                    $displayed_posts++;
                }
            }
            echo '</ul>';
        } else {
            foreach ($posts as $post) {
                if($displayed_posts < $total_posts_to_show) {
                    echo '<a href="' . get_permalink($post) . '">' . $post->post_title . '</a><br/>';
                    $displayed_posts++;
                }
            }
        }

        if ($instance['fixed_variable_recent']) {

            $total_posts_to_show = isset($instance['total_posts']) ? $instance['total_posts'] : 0; # count($posts);

            if ($total_posts_to_show != 0) {

                $total_posts_to_show = $total_posts_to_show + $displayed_posts; 

            }


        } else {

            $total_posts_to_show = isset($instance['total_posts']) ? $instance['total_posts'] : 0; # count($posts);

            if($displayed_posts < $total_posts_to_show) {

                $total_posts_to_show = $total_posts_to_show - $displayed_posts;

            } else {

                $total_posts_to_show = 0; 
            }

        }

        if($instance['show_recent'] && $displayed_posts < $total_posts_to_show) {
            $recent_posts_args = array(
                'numberposts' => $total_posts_to_show - $displayed_posts,
                'offset' => 0,
                'category' => 0,
                'orderby' => 'post_date',
                'order' => 'DESC',
                'include' => '',
                'exclude' => '',
                'post_status' => 'publish',
                'suppress_filters' => true,
            );

            if(isset($instance['recent_category']) && isset($instance['recent_tag'])) {
                $recent_posts_args['category_name'] = $instance['recent_category'];
                $recent_posts_args['tag'] = $instance['recent_tag'];
            } elseif(isset($instance['recent_category'])) {
                $recent_posts_args['category_name'] = $instance['recent_category'];
            } elseif(isset($instance['recent_tag'])) {
                $recent_posts_args['tag'] = $instance['recent_tag'];
            }

            $recent_posts = wp_get_recent_posts( $recent_posts_args, ARRAY_A );

            echo '<br/>';
            echo '<br/>';
            echo '<br/>';

            if(isset($instance['recent_title'])) {
                $recent_title = $instance['recent_title'];
                echo $args['before_title'] . $recent_title . $args['after_title'];
            } 

            if($instance['use_list']) {
                echo '<ul>';
                foreach ($recent_posts as $post) {
                    echo '<li><a href="' . get_permalink($post['ID']) . '">' . $post['post_title'] . '</a></li>';
                }
                echo '</ul>';
            } else {
                foreach ($recent_posts as $post) {
                    echo '<a href="' . get_permalink($post['ID']) . '">' . $post['post_title'] . '</a><br/>';
                }
            }
        }

        echo $args['after_widget'];
    }

    // Form method
    public function form( $instance ) {
        $title = ! empty( $instance['title'] ) ? $instance['title'] : 'Posts on Page';
        $use_list = ! empty( $instance['use_list'] ) ? $instance['use_list'] : true;
        $recent_title = ! empty( $instance['recent_title'] ) ? $instance['recent_title'] : 'Recent Posts';
        $show_recent = ! empty( $instance['show_recent'] ) ? $instance['show_recent'] : true;
        $recent_category = ! empty( $instance['recent_category'] ) ? $instance['recent_category'] : '';
        $recent_tag = ! empty( $instance['recent_tag'] ) ? $instance['recent_tag'] : '';
        $total_posts = ! empty( $instance['total_posts'] ) ? $instance['total_posts'] : '5';
        $fixed_variable_recent = ! empty( $instance['fixed_variable_recent'] ) ? $instance['fixed_variable_recent'] : true;

        ?>
    
        <p>
            <label for="<?php echo $this->get_field_id( 'title' ); ?>">Title (Optional):</label>
            <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $title ); ?>" placeholder="Enter title (optional)" />
        </p>
        <p>
            <input type="checkbox" id="<?php echo $this->get_field_id( 'use_list' ); ?>" name="<?php echo $this->get_field_name( 'use_list' ); ?>" <?php checked($use_list, true); ?> />
            <label for="<?php echo $this->get_field_id( 'use_list' ); ?>">Use List Format</label>
        </p>
        <p>
            <input type="checkbox" id="<?php echo $this->get_field_id( 'show_recent' ); ?>" name="<?php echo $this->get_field_name( 'show_recent' ); ?>" <?php checked($show_recent, true); ?> />
            <label for="<?php echo $this->get_field_id( 'show_recent' ); ?>">Show Recent Posts</label>
        </p>
        <p>
            <label for="<?php echo $this->get_field_id( 'recent_title' ); ?>">Recent Title (Optional):</label>
            <input type="text" id="<?php echo $this->get_field_id( 'recent_title' ); ?>" name="<?php echo $this->get_field_name( 'recent_title' ); ?>" value="<?php echo esc_attr( $recent_title ); ?>" placeholder="Enter recent title (optional)" />
        </p>
        <p>
            <label for="<?php echo $this->get_field_id( 'total_posts' ); ?>">Total Posts to Show:</label>
            <input type="number" id="<?php echo $this->get_field_id( 'total_posts' ); ?>" name="<?php echo $this->get_field_name( 'total_posts' ); ?>" value="<?php echo esc_attr( $total_posts ); ?>" />
        </p>
        <p>
            <input type="checkbox" id="<?php echo $this->get_field_id( 'fixed_variable_recent' ); ?>" name="<?php echo $this->get_field_name( 'fixed_variable_recent' ); ?>" <?php checked($fixed_variable_recent, true); ?> />
            <label for="<?php echo $this->get_field_id( 'fixed_variable_recent' ); ?>">Fixed or Variable</label>            
        </p>        
        <p>
            <label for="<?php echo $this->get_field_id( 'recent_category' ); ?>">Recent Posts Category:</label>
            <input type="text" id="<?php echo $this->get_field_id( 'recent_category' ); ?>" name="<?php echo $this->get_field_name( 'recent_category' ); ?>" value="<?php echo esc_attr( $recent_category ); ?>" />
        </p>
        <p>
            <label for="<?php echo $this->get_field_id( 'recent_tag' ); ?>">Recent Posts Tag:</label>
            <input type="text" id="<?php echo $this->get_field_id( 'recent_tag' ); ?>" name="<?php echo $this->get_field_name( 'recent_tag' ); ?>" value="<?php echo esc_attr( $recent_tag ); ?>" />
        </p>
        <?php
    }

    public function update( $new_instance, $old_instance ) {
        $instance = $old_instance;
        $instance['title'] = strip_tags( $new_instance['title'] );
        $instance['use_list'] = filter_var($new_instance['use_list'], FILTER_VALIDATE_BOOLEAN);
        $instance['show_recent'] = filter_var($new_instance['show_recent'], FILTER_VALIDATE_BOOLEAN);
        $instance['recent_title'] = strip_tags( $new_instance['recent_title'] );
        $instance['recent_category'] = strip_tags( $new_instance['recent_category'] );
        $instance['recent_tag'] = strip_tags( $new_instance['recent_tag'] );
        $instance['total_posts'] = strip_tags( $new_instance['total_posts'] );
        $instance['fixed_variable_recent'] = filter_var($new_instance['fixed_variable_recent'], FILTER_VALIDATE_BOOLEAN);
        return $instance;
    }
}

?>

Adding an AJAX Preview to a WordPress Widget Plugin Tutorial

If you would like to add a preview mechanism to your WordPress plugin, you can use WordPress’ Ajax capabilities. This way, you can make changes in the admin area and preview them on the front end without having to save or reload the page.

In this context, I’ll add an AJAX preview to our plugin which will preview the list of posts in a modal window.

The previous post is: https://horkan.com/2023/08/08/creating-a-wordpress-widget-plugin-tutorial

Modify your plugin’s main PHP file (my_posts_widget.php) as follows:

<?php
/**
 * Plugin Name: My Posts Widget
 * Description: A widget that displays a list of all the posts displayed on the current page.
 * Version: 1.0
 * Author: Your Name
 */

// Register and load the widget
function my_posts_widget_load() {
    register_widget( 'my_posts_widget' );
}
add_action( 'widgets_init', 'my_posts_widget_load' );

// Creating the widget 
class my_posts_widget extends WP_Widget {

    function __construct() {
        parent::__construct(
            'my_posts_widget',
            __('My Posts Widget', 'my_posts_widget_domain'),
            array( 'description' => __( 'A widget that displays a list of all the posts displayed on the current page.', 'my_posts_widget_domain' ), ) 
        );
    }

    // Creating widget front-end
    public function widget( $args, $instance ) {
        global $posts;

        $title = apply_filters( 'widget_title', $instance['title'] );
        
        echo $args['before_widget'];
        if ( ! empty( $title ) )
            echo $args['before_title'] . $title . $args['after_title'];
        
        // this is where we output the posts
        echo '<ul>';
        foreach ($posts as $post) {
            echo '<li><a href="' . get_permalink($post) . '">' . $post->post_title . '</a></li>';
        }
        echo '</ul>';
        echo $args['after_widget'];
    }

    // Widget Backend 
    public function form( $instance ) {
        if ( isset( $instance[ 'title' ] ) ) {
            $title = $instance[ 'title' ];
        }
        else {
            $title = __( 'New title', 'my_posts_widget_domain' );
        }
        // Widget admin form
        ?>
        <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 esc_attr( $title ); ?>" />
        </p>
        <?php 

// Add a Preview button
        ?>
        <p>
            <button id="my-posts-widget-preview-btn" class="button">Preview</button>
            <div id="my-posts-widget-preview"></div>
        </p>
        <?php
    }

    // Updating widget replacing old instances with new
    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        return $instance;
    }
}

add_action( 'admin_footer', 'my_posts_widget_preview_script' );
function my_posts_widget_preview_script() {
    ?>
    <script type="text/javascript" >
    jQuery(document).ready(function($) {
        $('#my-posts-widget-preview-btn').on('click', function(e) {
            e.preventDefault();

            $.ajax({
                url: ajaxurl, // default WP ajax url
                data: {
                    'action': 'my_posts_widget_preview',
                },
                success:function(response) {
                    // Add response in Modal window
                    $('#my-posts-widget-preview').html(response);
                    // You can use any modal plugin or write your own code to display this response in modal
                },
                error: function(error){
                    console.log(error);
                }
            });  

        });
    });
    </script>
    <?php
}

add_action( 'wp_ajax_my_posts_widget_preview', 'my_posts_widget_preview' );
function my_posts_widget_preview() {
    global $posts;

    // Start capturing output
    ob_start();
    
    echo '<ul>';
    foreach ($posts as $post) {
        echo '<li><a href="' . get_permalink($post) . '">' . $post->post_title . '</a></li>';
    }
    echo '</ul>';
    
    // Get current buffer contents and delete current output buffer
    $output = ob_get_clean();

    echo $output;
    
    wp_die(); // All ajax handlers should die when finished
}

The above modification does the following:

  • Adds a Preview button in the widget form that, when clicked, makes an AJAX call to the server.
  • The AJAX call invokes a server-side PHP function (my_posts_widget_preview()) that generates a list of posts and sends it back as the AJAX response.
  • The AJAX response is then inserted into a div for preview.

Please note that for this code to work, AJAX should be properly set up in your WordPress and the admin user should have the right permissions to view the posts.

Remember, this is a very basic preview mechanism and may not reflect exactly how the widget will look on the frontend of your site. Depending on your theme and the styles it applies to widgets, the actual appearance may be different.

You might want to add more advanced features, like a live preview that updates automatically when you change the widget’s settings, or a more accurate representation of the frontend styles. This will require more complex code and a good understanding of both PHP and JavaScript.

Creating a WordPress Widget Plugin Tutorial

I wanted a widget that displays a list of all the posts displayed on the current page, but I couldn’t find a WordPress widget plugin that would do what I wanted. Ergo sum I’ll build it myself. Here’s a super short tutorial on how to create a WordPress widget plugin.

To accomplish this, we’ll create a plugin that registers a widget. This widget will grab the global $posts object from WordPress (which contains the posts that are being displayed on the current page), and list their titles in a widget.

Here’s my template code:

<?php
/**
 * Plugin Name: My Posts Widget
 * Description: A widget that displays a list of all the posts displayed on the current page.
 * Version: 1.0
 * Author: Your Name
 */

// Register and load the widget
function my_posts_widget_load() {
    register_widget( 'my_posts_widget' );
}
add_action( 'widgets_init', 'my_posts_widget_load' );

// Creating the widget 
class my_posts_widget extends WP_Widget {

    function __construct() {
        parent::__construct(
            'my_posts_widget',
            __('My Posts Widget', 'my_posts_widget_domain'),
            array( 'description' => __( 'A widget that displays a list of all the posts displayed on the current page.', 'my_posts_widget_domain' ), ) 
        );
    }

    // Creating widget front-end
    public function widget( $args, $instance ) {
        global $posts;

        $title = apply_filters( 'widget_title', $instance['title'] );
        
        echo $args['before_widget'];
        if ( ! empty( $title ) )
            echo $args['before_title'] . $title . $args['after_title'];
        
        // this is where we output the posts
        echo '<ul>';
        foreach ($posts as $post) {
            echo '<li><a href="' . get_permalink($post) . '">' . $post->post_title . '</a></li>';
        }
        echo '</ul>';
        echo $args['after_widget'];
    }

    // Widget Backend 
    public function form( $instance ) {
        if ( isset( $instance[ 'title' ] ) ) {
            $title = $instance[ 'title' ];
        }
        else {
            $title = __( 'New title', 'my_posts_widget_domain' );
        }
        // Widget admin form
        ?>
        <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 esc_attr( $title ); ?>" />
        </p>
        <?php 
    }

    // Updating widget replacing old instances with new
    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        return $instance;
    }
}

Here’s what’s happening in the code:

  1. We’re creating a new widget with the name “My Posts Widget”. This will appear in the list of available widgets in the WordPress admin dashboard.
  2. The widget has a title which is editable from the widget settings.
  3. In the widget method, we’re accessing the global $posts variable, which WordPress sets with all the posts being displayed on the current page.
  4. We’re then iterating through each of the posts and adding a link to the post in an unordered list.

To install this plugin, you need to:

  1. Create a my-posts-widget directory. The majority of plugins follow the same pattern re: use of “-” to separate words.
  2. Copy the code above and put it in my_posts_widget.php file inside my-posts-widget directory.
  3. Compress the my-posts-widget directory to my-posts-widget.zip.
  4. Go to your WordPress admin dashboard, then go to “Plugins > Add New > Upload Plugin”.
  5. Choose the my-posts-widget.zip file and click “Install Now”.
  6. After installation, activate the plugin by clicking “Activate”.

After you’ve done this, you’ll see a new widget available in your list of widgets called “My Posts Widget”. You can add it to any widget area in your theme like you would with any other widget.

Please note that this plugin will display all posts that are being displayed on the current page, regardless of where they’re displayed. That includes posts in main query, posts in sidebars, posts in footer etc. If you need more precise control, you’ll need to modify the code to suit your needs.