I'd like to present a "Most Viewed Posts" block on my site based on those URLs with the highest Google Analytics Pageviews count. Current loops display the title, featured image, the selection of an ACF field and the selections of a custom taxonomy. This would be no different. It should also be noted that I would need to be pulling from multiple CPTs.
I launched this site 1.5 years ago and immediately set up Google Analytics so there's lots of data there. I did not, however, set up a post counter inside my singular.php template.
I installed a plugin called Post Pageviews and set up a Google OAuth ID with the Analytics API. This is working and so I am able to retrieve a post count when I place the plugin's custom function ( <?php echo gapp_get_post_pageviews(); ?> ) on singular.php:
* https://github.com/wp-plugins/google-analytics-post-pageviews/blob/master/google-analytics-post-pageviews.php
* https://wordpress.org/plugins/google-analytics-post-pageviews/
Since this is working, it would be great to either a) hook in to this data or b) alter the plugin's code to achieve my goal with the loop. But I am also open to any alternative that allows me to get the posts from these multiple CPTs, sorted by highest pageview.
Fahad Murtaza answers:
You can simply use gapp_pre_get_posts(); It's built in the plugin. This should give you posts sorted already.
So in your wordpress query, sort by 'post_views' and you are done :) It has a filter which will sort by the right custom field for you.
So your code will look like this:
$args = array(
'orderby' => 'post_views',
'order' => 'DESC', // OR 'ASC'
);
$query = new WP_Query( $args );
These above arguments are supposed to be in addition with your other WP Query arguments. Please let me know if you need further help.
Problem solved :)
David Holtz comments:
Not a chance. This ain't my first rodeo and I'm not sure why anyone would ever agree to that.
Fahad Murtaza comments:
OK
Fahad Murtaza comments:
I have found the easiest solution for you. The plugin provides build in filter to do that and modifies your existing QP Query using 'orderby' param.
If you are curious about how it works, please look at the code for
function gapp_pre_get_posts($query) {
...
It's on line # 678 on the plugin file. I have updated my answer to reflect that.
David Holtz comments:
Using 'orderby' => 'post_views'
in a loop is just giving me my most recent posts.
David Holtz comments:
I'd love for it to be this simple and it makes sense. Any reason the 'orderby' value of 'post_views' would be ignored / only show recent posts?
Fahad Murtaza comments:
Something weird is happening. I don't have a live site right now to test number of views. But google now supports local testing. Will get back to you. May be Reigel's solution is better since it's non intrusive to plugin's actual code.
Please alsop notice that the plugin from wordpress.org and the github code is completely different. Possibly a different version.
David Holtz comments:
Just noticed that as well. I am using the one downloaded from wordpress.org, not the one from github. It wasn't clear to me that your method involved changing the plugin's code (if that's what you mean by intrusive).
Fahad Murtaza comments:
No, I was also using the plugin downloaded from wordpress.org. My code didn't change anything except for the main loop. But an actual solution might change the plugin since the filter tries to use the meta key while actual data is saved as transients. I think it wasn't implemented completely and the author left in in the middle of implementation.
So here is my solution, add a meta key to post. And then save it as a meta value along with the existing transient values. This would be one way to do it.
What Reigel Gallarde has suggested below might also be a good way since he is using usort. Not sure how performant it would be though. And you might have one more issue. It will only sort the resulting posts, not all of them, so not a completely solution either.
Fahad Murtaza comments:
Apologies for my typos.
Fahad Murtaza comments:
So here is the thing. You don't really need to use the same plugin if this needs customization anyway. Just tap into the google data directly and use this plugin
https://wordpress.org/plugins/ga-popular-posts/
David Holtz comments:
Something I'd like to point out. Line 680:
if ($query->is_main_query() && ($orderby = $query->get('orderby')))
If I change that to
if ($orderby = $query->get('orderby')))
I do see results that are not the most recent. In fact, the first post in the list is absolutely our most viewed post, but the following posts are not.
David Holtz comments:
Can you identify the range that 'post_views" is querying?
Fahad Murtaza comments:
I'll have a look again.
After testing on my own site, I can tell better. I'll suggest checking transient values to make sure if it's sorting correctly. You can install any transient plugin to do that. Your post id with transient name should give a perspective into that.
Reigel Gallarde answers:
you can add the page views in a meta field... maybe via cron so it would update like once a day... or once a week...
then you could sort the post via this meta field..
Reigel Gallarde comments:
gapp_get_post_pageviews function accepts page/post ID...
so you could loop through all the posts and update its meta field by passing the ID on gapp_get_post_pageviews to get the total views...
David Holtz comments:
Scheduling cron tasks is a little out of my wheelhouse, but I like where you're going with this... Could you walk me through? This plugin allows me set the cache time (an hour, a day, a week, etc..). Not sure if that helps or matters with what you're suggesting.
David Holtz comments:
I was responding to your first comment, but now seeing your second, which I also like the sound of. Could you provide a code example?
Reigel Gallarde comments:
I'm going away on the idea of cron and meta field... because I see on it's source code that the function is using transient which good as cache...
so I'm thinking you could just go with your query and use usort to sort the query result...
I have pasted the code here (for readability ) https://pastebin.com/raw/Aj2Eku6z
you just have to call <?php posts_gapp_get_post_pageviews(); ?> somewhere in your php page..
and edit it to display as you wanted...
Reigel Gallarde comments:
ahh forgot to change 'post_status' => 'any', to 'post_status' => 'post',
was using it for a test.. you can change that to 'post' or any of your post type...
Reigel Gallarde comments:
what I have is something like this on my functions.php
add_action('posts_gapp_get_post_pageviews', 'posts_gapp_get_post_pageviews');
function posts_gapp_get_post_pageviews(){
}
function posts_gapp_get_post_pageviews_sort( $a, $b ){
}
then somewhere on other php page, I called
<?php do_action( 'posts_gapp_get_post_pageviews' ); ?>
Reigel Gallarde comments:
lol... 'post_status' => 'any' is correct... sorry for misleading... was doing something else while answering your question... my apologies...
Reigel Gallarde comments:
have you tried my idea with usort?
David Holtz comments:
I'm not really certain what to do with your solution, I'm afraid.
Reigel Gallarde comments:
ok... on the block where you want to present a "Most Viewed Posts" insert this
<?php do_action( 'posts_gapp_get_post_pageviews' ); ?>
then your functions.php insert the code from here... https://pastebin.com/raw/nnCxCHgt
I put it on pastebin for readability...
Reigel Gallarde comments:
another thing I would like to point out...
$articles = get_posts(
array(
'numberposts' => -1,
'post_status' => 'publish',
)
);
numberposts is set to -1, meaning all posts...
you can change post_status to publish so it will only get the posts that can be viewed publicly... there's no sense getting those posts not published...
David Holtz comments:
I added my 'post_type' array, but I am not seeing any results or errors.
David Holtz comments:
You are using do_action, but you only provided functions. There's no 'action' to "do".
Reigel Gallarde comments:
add_action('posts_gapp_get_post_pageviews', 'posts_gapp_get_post_pageviews');
there's the action in above the two functions...
David Holtz comments:
Got it. Added it. I set the 'numberposts' to 5, but it's just displaying the current article in the loop 5 times.
Reigel Gallarde comments:
hhhmmm... not really sure why... you can comment out or remove usort($articles, 'posts_gapp_get_post_pageviews_sort');
to test if the sort is the problem...
by removing that line, you can see the original query result.
Reigel Gallarde comments:
I got stuck while creating credentials needed for google-analytics-post-pageviews plugin... I went trying to create a sample page but failed...
So I really can't test `gapp_get_post_pageviews`...
I made a test on usort using the post ID to compare, and the sort works well...
function posts_gapp_get_post_pageviews_sort( $a, $b ){
$a_page_views = $a->ID;
$b_page_views = $b->ID;
if ( $a_page_views == $b_page_views ) {
return 0;
}
return ($a_page_views > $b_page_views) ? -1 : 1;
}
it was able to put the the post that has the highest ID number on top..
Reigel Gallarde comments:
I tried replicating function gapp_get_post_pageviews as this to test.
function gapp_get_post_pageviews( $id ) {
$data = array(
'861' => 10000,
'807' => 500,
'742' => 3000
);
return array_key_exists($id, $data)?$data[$id]:0;
}
This gives me expected result.
I'm still trying to make a demo but godaddy has started migrating my website to a new server.. I currently have problems uploading files to my ftp..
If you can provide a test site, that would be great.
by the way, this line is checking for main query.. so custom query like get_posts will not kick in the codes inside the if.
if ($query->is_main_query() && ($orderby = $query->get('orderby')))
David Holtz comments:
Test site is not possible.
Reigel Gallarde comments:
Ok, I went deeper on investigating this. Because I too am curious...
Ok, still talking about the functions from this link: https://pastebin.com/raw/nnCxCHgt
look for `setup_postdata( $post );`
Upon searching, apparently, this may sometimes not work. And to fixed it, according here: https://codex.wordpress.org/Function_Reference/setup_postdata
You need to change it to setup_postdata( $GLOBALS['post'] =& $post );
I made a sample https://reigelgallarde.me/reigel/
Arnav Joy answers:
Which code you added when you getting same result again ?
David Holtz comments:
With Fahad's answers, I got close by editing the plugin to remove a reference to 'the_main_query()'. I was able to see my most viewed post first, but the following posts, while high in pageviews, most certainly are not the highest or consistent with my analytics.
With Reigel's answers, I didn't get as far. This is what produced the current post over and over:
In functions:
https://pastebin.com/raw/Aj2Eku6z - but I changed it to show my CTPs.
On the template:
add_action('posts_gapp_get_post_pageviews', 'posts_gapp_get_post_pageviews');