How allow users to save list of posts?

I am not asking you to write the all code or asking a plugin, I am asking a way to build this feature because I don’t have any plan in my mind to build this feature.

This is the requirement : There are many posts on the website. Logged Users (Front-end users) should have a feature to save list of posts.

Ex :

  • List 01 : My favorite Posts
  • List 02 : Blogging related posts
  • List 03 : Watch later Posts

I want user to allow to create these types of list. Then they can add any number of posts. And these list are private. I mean only created user can access the list.

This is something like we label emails on gmail.

What can I use to save list? I have no idea what can I use for it… At least is this possible with WordPress?

Solutions Collecting From Web of "How allow users to save list of posts?"

I’d suggest using using custom tables to keep things lean.

Have two tables: A table of lists and a table of posts and which lists they belong to.

The lists table (let’s call it wp_lists) would look like:

| id | user_id |      name      |
|  1 |       2 | My list        |
|  2 |       2 | My second list |

You could have more columns here if lists had more data to them, like a description or associated colour. If the table starts growing you might want to split it into a two tables, with a separate table for user-list relationships.

And the lists-posts table (let’s call it wp_post_list) would look like:

| post_id | list_id |
|       2 |       2 |
|       3 |       2 |
|       2 |       1 |

Maybe you’d want an ID column, but I’m not sure what you’d need it for, since the post_id/list_id combinations should all be unique, since posts can’t be in a list more than once.

So when someone creates a list you’d insert it into wp_lists. They could create as many as they like, or you could limit it in PHP by checking how many they’ve already got.

To get the lists that belong to the current user you’d just query wp_lists based on the user_id column.

When someone adds a post to a list you’d insert the post ID into wp_post_list alongside the list it belongs to. When you want to see all posts within a list you’d query based on the list_id column, then put the resulting IDs into a WP_Query or get_posts().

When browsing posts you’d want to show which of the user’s lists it already belongs too. In that case you’d query wp_post_list based on the post_id, but JOIN it to wp_lists and limit results to ones with lists that have the current user’s ID.

You can use a button on the front and save the ID of the currently displayed post in user’s meta. Here’s a simple way to do this:

Output a Button on Front

You need to create a button in your single.php ( or whatever page you want ) to allow the user to actually set the post as a favorite. The below template does this. The like-overlay class is used to create a loading effect while the request is being processed.

<div id="like-button" class="like btn btn-default" type="button">
    <span class="fa fa-heart"></span>
    <span class="like-overlay"><i class="fa fa-spin fa-circle-o-notch"></i></span>
<input type="hidden" value="<?php the_ID(); ?>" id="current-post-id"/>
<input type="hidden" value="<?php echo get_current_user_id(); ?>" id="current-user-id"/>

Add a Click event to the Button

When the user clicks the button, send an AJAX request to the server, and update the button based on the results. You might need to localize the script to pass the rest URL and other data.

$('#like-button').on('click',function (e) {
        type: 'GET',
        url: '',
        data: { post_id: $('#current-post-id').val(), user_id : $('#current-user-id').val() },
        beforeSend: function() {
            $('#like-button').addClass('active').prop('disabled', true);
        success: function(data){

            $('#like-button').removeClass('active').prop('disabled', false);

            if( data != null ){

                if( data == '400' ) {
                } else if( data == '200') {


Process the Ajax Request Using REST-API

Now create a rest route and process the data. If the received post ID doesn’t exists in the user meta, add it and return a successful code. If it does, remove it and let your script know about it.

add_action( 'rest_api_init', 'my_rest_routes');
function my_rest_routes() {
    // Path to ajax like function
            'methods' => 'GET',
            'callback' => 'ajax_favorite'

function ajax_favorite(){

    // If the ID is not set, return
    if(!isset($_GET['post_id']) || !isset($_GET['user_id'])){
        return $data['status'] = '500';

    // Store user and product's ID
    $post_id   = sanitize_text_field($_GET['post_id']);
    $user_id   = sanitize_text_field($_GET['user_id']);
    $user_meta = get_user_meta($user_id,'_favorite_posts',false);

    // Check if the post is favorited or not
    if( in_array( $post_id, $user_meta ) ){
        return $data['status'] = '400';
    } else {
        return $data['status'] = '200';


You can use this as a template to output any button that saves data from front-end to database. Don’t forget to sanitize the data, and use nonce too.

Now of course all you need is to get the _favorite_posts user meta whenever you want to display it.

When I am thinking about UI something like this is comming to my mind.

enter image description here

Something similar has YouTube under the video.

When user fills input and clicks enter or submit button to create list, you will send ajax request with list name and save it as a record in wp_usermeta table with meta_key _list_user_1 and meta_value as list title.

To add post to this list you have to save record in wp_postmeta table with _list_post_1 value in meta_key field and value of umeta_id from _list_user_1 row in field meta_value.


| umeta_id | user_id | meta_key     | meta_value |
| 100      | 1       | _list_user_1 | List 1     |


| meta_id | post_id | meta_key     | meta_value |
| 1       | 1       | _list_post_1 | 100        |

To get all lists for user:

FROM `wp_usermeta`
WHERE `user_id` = 1
  AND `meta_key` LIKE "_list_user_%";

To get all posts for List 1:

FROM `wp_posts`
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE wp_postmeta.`meta_key` LIKE "_list_post_%"
  AND wp_postmeta.`meta_value` = 100;