Paginated posts, also known as multi-page posts, can be an indispensable tool when publishing long posts. Our Core i7 860 overclocking article, for example, is 10 packed pages of stats and images.
WordPress handles this task with ease, by offering the nextpage tag in the post’s visual editor or directly with the wp_link_pages() function.
Using this feature in recent versions of WordPress, however, results in only the first page being indexed by Google and other search engines. Subsequent pages are unsearchable. In this article, I will show you how to fix this problem easily so that all your pages get indexed.
Causes of the Problem
Update May 27,2012: The newest version now properly shows the Canonical URL on paginated posts, so we no longer need to modify it.
Update March 1,2016: The newest version now properly shows the Title on paginated posts. Only the description remains to alter.
The major issue is the recent addition of canonical URLs in WordPress and their support by Google. No matter which page you are on, the canonical URL is always set to the first page. This causes Google to always refer back to the first page when it tries to crawl subsequent pages.
You will have to contend with the title and description. These two items are, by default, the same for all pages in the post.
How to Fix the Indexing Problem
This fix assumes you are using the All-In-One SEO Pack plugin. If you are in the minority who do not use it, then you just need to find the spots where your canonical URL, title, and description are finalized. These changes were made under WordPress 2.9 – WordPress 3.3.1 and the SEO plugin 1.6.13.4 (as of June 1, 2012).
These 2 alterations we must make are all located in the same file under the All-In-One SEO plugin. The file is aioseoclass.php
. Here is the outline of the changes we will make:
- Check current URL to see if it is paginated
- If so, set current page number in a variable
- Add page number to page title tag
- Add page number to meta description
Desciption
Near line 2114. This puts “Page x of series” before the description to make it unique.
/* BEFORE: $meta_string .= sprintf("<meta name=\"description\" content=\"%s\" />", $description); */ $exploded = explode("/",$_SERVER['REQUEST_URI']); if( is_numeric( $exploded[sizeof($exploded)-2] ) ){ $description = "Page ".$exploded[sizeof($exploded)-2]." of series - ".$description; } |
Canonical URL
Near line 383. This matches the canonical url with the current paginated URL.
NO LONGER USED OR NEEDED
/* goes after: $url = apply_filters('aioseop_canonical_url',$url);
$exploded = explode("/",$_SERVER['REQUEST_URI']);
if( is_numeric( $exploded[sizeof($exploded)-2] ) ){
$url = $url.$exploded[sizeof($exploded)-2]."/";
} */ |
Page title
Line 722. This changes the title
tag.
NO LONGER USED OR NEEDED /* BEFORE: $title_format = $aioseop_options['aiosp_post_title_format']; */ $exploded = explode("/",$_SERVER['REQUEST_URI']); if( is_numeric( $exploded[sizeof($exploded)-2] ) ){ $title = $title." (Page ".$exploded[sizeof($exploded)-2].")"; } |
After placing these 2 code snippets into the plugin’s php file, simply give Google a day or two and your additional pages will begin to show up in search results. You can look at the page source output to verify this has worked.
If this tip helped you, or if you want to contribute, leave a comment!
Terrific article. I’ve been wondering why my paginated posts were not being indexed for some terms and now I know: Canonical URLs. Better yet, you’ve provided great step by step instructions on how to remedy this issue.
Thanks!
Appreciate the comment! I struggled originally to find any information at all about the topic, as it was something you couldn’t search for with 2 or 3 simple keywords.
Hopefully, this will be helpful and easily searchable for others who experience our problem.
Hi SS,
Well, I seem to have an issue. Probably an incorrect implementation on my part.
Where does
$exploded = explode("/",$_SERVER['REQUEST_URI']);
go exactly in aioseop.class.php? It goes outside theclass All_In_One_SEO_Pack
?My issue is that
$exploded[sizeof($exploded)-2]
is not returning anything, and hence failing theis_numeric
if statement.Any thouhgts?
Each of the 3 code snippets use the
$exploded
variable, so it has to be available to 3 different functions.I originally suggested putting it up top, but that didn’t work, so put the
$exploded
declaration in front of each snippet (article updated to show this).I just followed all those steps. Now (as you said) I gotta wait to see if Google got it.
Anyway, the article was very well explained. Thank you!
Hello. I did everything as written, but in the page code canonical links are not changed.
Here is the code: http://e-dotu.ru/uploads/2011/06/aioseop.class.txt
Haven’t got to look at your code yet, but my first idea would be some sort of other plugin overriding your canonical urls or secondly- they have updated the AIOSEO plugin to where this code doesn’t work as written.
You could do some tests in the code to output the variables if you have a dev version of your page, or output their values as comments in HTML if you have to work on your live site.
I disabled all plugins except AIOSEOP, but the problem persists.
No changes. As if i didnt edit the code.
Yep, you were right! The class is not recognizing the
$exploded
variable at the top of the script.The easy fix is remove it from the top and put it in front of each of the 3 snippets. I am updating the article to show this.
This is something I’ve been looking for like crazy and couldn’t find any solution.
My main problem for me are duplicate title and description tags which show up as errors in the Google Webmaster Tools.
Is there a way to implement your solution into the plugin WP SEO, which I currently use, or better yet, is there a way to make a standalone plugin out of this?
Thanks,
Eddie
The concept of my solution can be implemented with any plugin. I was going to check your plugin out and see if I could provide some quick advice, but it’s a pay plugin that doesn’t have its php classes available with the download.
Just look at what my code does and make the change in your plugin where the title, description, and canonical url are. It’s actually really simple and you *might* be able to drop it right in and just change the variable name (like $description) to whatever your plugin uses. You just have to go find the spots where it sets those items.
Thanks Evan for the reply.
No, I mean that other one from Yoast which is free: http://wordpress.org/extend/plugins/wordpress-seo/
I really not code savvy, unfortunately, so a little bit of help is much appreciated.
Thanks again,
Eddie
I took a short stroll through that code and looks to me like the functions you want to update are in frontend/class-frontend.php.
I see functions title(), metadesc(), and canonical(). Look at my snippet above for canonical and you’ll see a line that’s the similar to their line 404 (in their version 0.4.2). Just pop my code in line the next line and change the variable name from $url to $canonical.
I’ll let you figure out the other 2.
Thank you so much!
I think I figured it out (for a non-coder this is like rocket-science):
for description: line 501
for canonical URL: line 404 (as you’ve written)
for page title: line 97
Is that correct? Don’t want to mess up something…
Thanks again for your help and your time, I really appreciate it.
Eddie
Great tip, thanks a lot.
But i’m still having trouble with index pagination (example: http://www.yourblog.com/page1 and http://www.yourblog.com/page2 with the same meta description.
Is it a misconfiguration of All in One?
Hi Daniel, you have to alter the code snippet if your URL actually ends with /page2, /page3, etc.
“page2” is not numeric, which is what that code snippet looks for. Remove the word leaving only the number.
$exploded = explode("/",$_SERVER['REQUEST_URI']);
$checkurl = str_replace("page","",$exploded[sizeof($exploded)-2]);
if( is_numeric( $checkurl ) ){
$description = "Page ".$checkurl." of series - ".$description;
}
Hi
Thanks for this information, it was really useful!
However, I had to make some changes to the canonical URL rewrite code to get it to work with my site.
My site has several pages (not posts) that are split into multiple pages. The structure is as follows:
http://site-url/section/page-name/page-number
Since the page number is the last portion of the URL, I changed your code to the following:
$exploded = explode(“/”,$_SERVER[‘REQUEST_URI’]);
if( is_numeric( $exploded[sizeof($exploded)-1] ) ){
$url = $url.$exploded[sizeof($exploded)-1].”/”;
}
So now it checks the last array entry instead of the second-last one. This works great for me.
Just thought I should share it with you. Thanks again!
Regards
Vijay Padiyar
Thanks Vijay. I also corrected the sample URL you entered since my spam system stripped it out.
Concerning your code change, I was under the impression that WordPress always put a trailing slash on the end of a URL. Your sample URL did not have a slash at the end, which accounts for that change. Might be a plugin or configuration difference.
Yes in my case WordPress does not add a trailing slash by default. I am not sure if it is due to any plugin, as this has been the case from when I first started out with my WordPress site. Of course, I can get it to add the slash by adding it to the pretty permalinks.
Hi
I´m using the yoast seo plugin and i’m suffering the same problems like “eddie” (post from the 6th and 7th august). Is there a slight chance that you can alter your code special for the yost seo plugin, or otherwise can you give some more specific advise how and where to alter the specific code.
I hope that will you answer my request positive.
Regards
tom
Hi Tom, just follow the advice I gave Eddie. You don’t even have to write any code, just put my code in there and change my variable names to match the ones used in the yoast version.
The line numbers he mentions look to be right. The place for the title might work better at line 216 rather than 97, but either one might work.
At last! Something clear I can uendsrtand. Thanks!
Hi, first of all thanks for such an important article. It seems you are the only one that is speaking about this problem.
I’m using 1.6.13.4 and I strictly followed you guide.
Everything works apart from the title rewriting. I get exactly the same title as the first page of the post.
Post title is configured as %post_title% in the plugins settings.
As Vijay Padiyar my site has several pages (not posts) that are split into multiple pages
Do you have any idea what is happening?
P.S.
What about a plugin made by you to fix this 😉
Thanks for the compliments. I wish I had enough time in the day to build plugins, too.
I just downloaded version
1.6.13.4
and it’s way different than1.6.13.2
. It looks like you want to check out line 513 ofaioseop.class.php
. It looks like that is where the final title is set and where you want to put my snippet that changes it.It works perfectly! Thanks!
Hello,
I am really glad I found this post. I am having an issue with AIOSEO Version 1.6.13.8
On just my category pages it is duplicating the main category meta description for pages two and higher. I am using paging for categories. The title and canonical link are correct and show the page number but the meta description does not, and Google is telling me for the meta descriptions I have duplicate content. Can you please help me fix this issue with only category pages?
Google Webmaster Tools is showing
/blog/category/Main-Cat1/
/blog/category/Main-Cat1/page/2/ (Duplicate)
/blog/category/Main-Cat1/page/3/ (Duplicate)
I have pages on my homepage and everything is fine, the issue is only with cat pages. I really appreciate any help, or any advice you can give me, and thanks so much for taking the time to post this info.
I checked it now with All-In-One SEO Pack version 1.6.13.8
Your solution working nice, except category view.
Example:
in page http://site/category/category_name/page/2/
In my page source:
<link rel=”canonical” href=”http://site/category/category_name/page/2/2/”>
So it has false addition “2/” at end of URI.
It means we need to avoid your plugin modification category view, I changed this string:
if( is_numeric( $exploded[sizeof($exploded)-2] ) ){
To:
if( is_single() && is_numeric( $exploded[sizeof($exploded)-2] ) ){
Function is_single() used to check if we are rendering article view or not.
I don’t know if my solution is best, still need to check it.
Regards
Interesting. I am using AIOSEO 1.6.13.8 also, and I don’t remember having a problem like that.
For example, if you go to http://solidlystated.com/hardware/page/2/ you will see the source HTML:
<link rel=”canonical” href=”http://solidlystated.com/hardware/page/2/” />
However, I did at some point change my own code to say
is_numeric($exploded[sizeof($exploded)-2]) && !is_archive() && !eregi(“/page/”,$_SERVER[‘REQUEST_URI’])
First let me say thank you so much for this solution. It is very helpful. I was wondering if there was any way to make the description say Page X of Y where Y was the total number of pages in the article.
So I guess you are asking me how you would find Y? Of course you can.
For example, the plugin I use for pagination separates pages by the tag
<!--nextpage-->
. In the code, before I echo out the description, I could a WP function to get the post content and count how many times I see the nextpage tag.SolidlyStated, let me just say: Thank you!
My long lasting search ends here. I think you can’t imagine how many threads on the wordpress seo support pages are filled with “canonical” & “paginated” and there is absolutly no satisfying solution. You have it. Thanks.
If you one day want to add some bonus (I think there are others out there seeking for a solution, too):
A smart solution to give every paginated postpage a really indivdual title (maybe with use of custom fields?) would be a real killer. Maybe for xmas 🙂
Regards
Oli
Hi,
I’m coming back to share my experience after implementing the solution above: At first everything looked fine to me. Correct canonicals on paginated posts, individual titles and I was so happy that I just forgot to look at the first page of the paginated posts where i ran into problems.
My URI-structure is: domain/postname/Unique-ID/(postpage)
wich causes the function to take the unique-ID on singlepage posts and write it to the variable though it’s not a pagenumber.
My question is: Could the function check if the numeric part is a unique-ID or a pagenumber (e.g. if only one numeric part = Unique iD, if two parts, take the last one as pagenumber for canonical. If there’s only one numerical part – leave everything as ist is )??
Any ideas/help highly appreciated
Thanks
Oli
SolidlyStated, thanks for this very helpful post. This is out of the topic but I am just wondering if it is possible to format/style wp_link_pages() links like the one that appears here http://solidlystated.com/hardware/page/2/
Thanks
Aris
wp_link_pages() just fetches the existing link, it doesn’t create it. I think you are asking about permalink structure which you have full control over.
When paginated pages are excluded from Google s index, then this would drop all signals from those pages. This would include the content which contains internal links to deeper level pages (product URLs, news articles, etc.).