1

I don't know if I've complicated things a bit, so I'll explain things from the top. I have a set up with a custom post type (news), which is exposed via the REST API. The main endpoint (/wp-json/wp/v2/news) returns a list of news items, which needs to be sorted by popularity. I tried a few post view count plugins, but none of them seem to work via the REST API (they only work when the theme renders the post).

My plan is to create a "view count" ACF field and hook into the REST API init for a post (or only for my news type), and update the value for that ACF field. I should then be able to request a list of the items ordered by the view count.

I seem to have found solutions for some of the tasks involved, but I can't figure out the basic one: How can I hook into WP when a REST API request is made on a particular post type and how can I update the custom field at that point?

ACF isn't an integral part of this query - I'm fine with using a native custom field, but if my question about the hook is answered, the field type is irrelevant.

1

I looked around again with a more relaxed mind and figured out that the_posts is the action hook I was looking for. This is how I just did it:

add_action(
    'the_post',
    function ( $post ) {
        $count = (int) get_field('views');
        $count++;
        update_field('views', $count);
    }
);

Now I'll just figure out how to sort it by an ACF field...

Update: Nope, this will not work, because the_post runs 10 times in the main query /news/ for each of the 10 items, so even getting the index would increase the view counts. Back to the drawing board...

Update 2: My final idea is to still use the the_post hook as used above, but by adding a ?index=true parameter, which will only be specified with the /news/ endpoint, eg. /news?index=true. I'll then update the hook function to only count a view if there is no index query string parameter set. Finally, I will hook into the main WP_Query and sort the items by the count before they're sent out. If this doesn't work, I'm trashing this whole directory and building the app from scratch using Laravel.

Update 3: I think the last idea is probably not the cleanest or the correct way to do this. I ended up adding a custom endpoint only for counting views, accepting that this is a custom functionality requirement. I did it like this:

function aalaap_count_view( $data ) {
    $post = get_post( $data['id'] );

    if ( empty( $post ) ) {
        return new WP_Error( 'aalaap_post_not_found', 'Invalid post', array( 'status' => 404 ) );
    }

    // Now update the ACF field (or whatever you wish)
    $count = (int) get_field('views', $post->ID);
    $count++;
    update_field('views', $count, $post->ID);

    return new WP_REST_Response($count);
}

add_action( 'rest_api_init', function () {
    register_rest_route( 'aalaap/v1', '/countview/(?P<id>\d+)', array(
        'methods' => 'GET',
        'callback' => 'aalaap_count_view',
    ) );
} );

Thanks to @Mark-Kaplun for the suggestion in the other answer.

|improve this answer|||||
  • at least you also count real views that way.... still the thing to be careful with when handling DB writes on front end is that it will bring you site down when it gets more traffic. If it is your site, I would consider making it it more complex but with much better performance by storing the views in a file which is being processed every hour by a cron which updates the values in DB – Mark Kaplun Oct 6 '17 at 6:21
  • @mark-kaplun Right. This is just for a PoC. – aalaap Oct 6 '17 at 7:32
0

In general, if you need your own special treatment you should just implement your own end point. It will become more apparent the more usage the canonical end point will get. In your case, if you change the output of that end point, you will not be able to use it in other plugins that expect that it will return a list soreted by publish time.

|improve this answer|||||
  • It really isn't "special" treatment, in that it's just a view count and a standard sort feature, which is applicable to any post type. – aalaap Sep 28 '17 at 13:38
  • view count is special treatment, but I was referring more to showing the posts sorted. Anyway you should never write to the DB on "frontend" requests unless you want your site to die quickly when at last it will get some traffic, and obviously it will not work at all when you employ caching. – Mark Kaplun Sep 28 '17 at 17:39
  • It's RESTful to have a ?sort=criteria parameter, so I don't think a separate endoint (i.e. /news-popular) is good practice. The db write thing is certainly a concern. – aalaap Sep 29 '17 at 8:05
  • I find RESTful to be a meaningless buzz word (REST is actually a stupid concept that not many understand and therefor almost no one actually follows it). If you add ?sort=criteria you have effectively created a new end point. – Mark Kaplun Sep 29 '17 at 9:29
  • I think it's probably reasonable to create a custom endpoint to count views, which is what I eventually did. – aalaap Oct 6 '17 at 5:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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