If you load subpages of your WordPress site via AJAX you lose your Open Graph tags when you share those posts via Facebook or Twitter. Any social media site will pull the OG data from the main URL and ignores any hash URL.
If you share http://mysite.com/#my-post Facebook will just use the base URL http://mysite.com/ to pull the metadata.
Test your current metadata
Use the following URLs to test your OG metadata and your twitter cards:
https://developers.facebook.com/tools/debug/og/object/
https://cards-dev.twitter.com/validator
Use hashbang instead of hash URLs
Change your AJAX links from http://mysite.com/#my-post to http://mysite.com/#!my-post
A hash URL is just a client instruction so you can’t react on this via PHP. If you use hashbang URLs instead the crawlers from Facebook and Twitter convert your request to /index.php?_escaped_fragment_=my-post so you can find the value in your $_SERVER global.
Redirect _escaped_fragment_ in .htaccess
We create a rewrite condition in our .htaccess to convert URLs with _escaped_fragment_ parameter to static URLs.
All my hashbang urls are used on the page /news/ so I add this to the rewrite rule:
RewriteCond %{QUERY_STRING} _escaped_fragment_=(.*)$ RewriteRule ^news/$ /%1/? [R=301,L]
- Original link: http://mysite.com/#!my-post
- Facebook crawler: http://mysite.com/?_escaped_fragment_=my-post
- Htaccess redirect: http://mysite.com/my-post/
Redirect real users back to the ajax page
Just in case a real user visits the crawler URL we redirect him back to the ajax version of the page. Add the following code to the top of the single.php ( or single-posttype.php for custom post types ):
if( ( empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest' ) && FALSE === stripos( $_SERVER['HTTP_USER_AGENT'], 'facebookexternalhit') && FALSE === stripos( $_SERVER['HTTP_USER_AGENT'], 'twitterbot') && FALSE === stripos( $_SERVER['HTTP_USER_AGENT'], 'bingbot') && FALSE === stripos( $_SERVER['HTTP_USER_AGENT'], 'googlebot') && FALSE === stripos( $_SERVER['HTTP_USER_AGENT'], 'bingbot') && FALSE === stripos( $_SERVER['HTTP_USER_AGENT'], 'yahoo') ) { wp_redirect( get_permalink( XXX ).'#!'.str_replace(home_url(), '', get_permalink($post->ID)), 302 ); exit; }
If the request is not an ajax request and the browser is not a bot redirect to the overview page and append the hashbang url.