The Facebook bots are unable to crawl our AngularJS application because the JavaScript is not being properly

I have a unique setup where my website is built with AngularJS and Wordpress as a single page application. Depending on the routing of the page, I dynamically define meta tags in the controller. Here's a snippet of my HTML header:

<meta property="og:url" content="{{ngMeta['og:url']}}" />
<meta property="og:title" content="{{ngMeta['og:title']}}" />
<meta property="og:description" content="{{ngMeta['og:description']}}" />
<meta property="og:image" content="{{ngMeta['og:image']}}" />

While this setup works correctly, I encountered an issue when trying to share a page on Facebook. The crawler dispatched by Facebook doesn't seem to recognize the meta tags, resulting in incorrect display:

https://i.sstatic.net/VH8Mk.png

I suspect this is due to the fact that the crawler doesn't load the Javascript, hence failing to fetch the meta tags.

To address this, I'm considering implementing a server-side solution using Apache mod rewrite. This involves setting up different redirects for human visitors and social media crawlers (Facebook, Twitter, etc.).

In an article I came across, they suggest using mod rewrite with Apache to handle requests from social media crawlers and redirect them to server-side static pages with metadata processed by the server.

Currently, my website uses Wordpress with permalinks structured as:

https://<dns>/%category%/%postname%/
. Here's a snippet of my .htaccess file:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

To implement the suggested solution, I would need to add specific Rewrite rules for each category like so:

RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit/[0-9]|Twitterbot|Pinterest|Google.*snippet)
RewriteRule tracks/(\d*)$ https://<dns>/server/static-page.php?id=$1 [P]
RewriteRule articles/(\d*)$ https://<dns>/server/static-page.php?id=$1 [P]

These rules are intended to redirect crawlers to static pages. However, I'm uncertain how to handle the requests on these server-side static pages. Any suggestions or recommendations?

Answer №1

I devised a solution by redirecting all Facebook crawlers to a static server page in order to enhance the open graph meta tags.

WordPress automatically redirects to index.php, so it's necessary to block this redirection for Facebook (and any other social bots) in the .htaccess file as well.

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_USER_AGENT} !facebookexternalhit/1.1|Twitterbot|Pinterest|Google.*snippet
RewriteRule . /index.php [L]
</IfModule>

# END WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} facebookexternalhit/1.1|Twitterbot|Pinterest|Google.*snippet
RewriteRule tracks/(.*) http://<fqdn>o/static.php?id=$1 [R]
</IfModule>

You can adjust the RewriteRule to fit your permalinks (tracks represents a category in my WordPress) using the regex of your choice. My custom WordPress permalinks are structured like this: /%category%/%postname%/.

After configuring the rewrite in the Apache configuration, you need to create your static page. In my case, I'm utilizing WP API V2, and here is an example of my page:

<?php 

$SITE_ROOT = "http://<fqdn>";

$jsonData = getData($SITE_ROOT);
makePage($jsonData, $SITE_ROOT);

function getData($siteRoot) {
    $id = $_GET['id'];
    $rawData = file_get_contents($siteRoot.'/wp-json/wp/v2/posts?slug='.$id);
    return json_decode($rawData);
}

function makePage($data, $siteRoot) {
    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <meta property="og:type" content="articles" />
        <meta property="og:url" content="<?php echo $data[0]->link; ?>" />
        <meta property="og:title" content="<?php echo $data[0]->title->rendered; ?> | Going Solo" />
        <meta property="og:description" content="<?php echo $data[0]->excerpt->rendered; ?>" />
        <meta property="og:image" content="<?php echo $data[0]->better_featured_image->media_details->sizes->medium->source_url; ?>" />
        <meta property="og:image:width" content="500" />
        <meta property="og:image:height" content="500" />
    </head>
    <body>
        <img src="<?php echo $data[0]->better_featured_image->media_details->sizes->medium->source_url; ?>">    
        <h1><?php echo $data[0]->title->rendered; ?></h1>
        <p><?php echo $data[0]->excerpt->rendered; ?></p>

    </body>
    </html>
<?php
}
?>

The variable $id corresponds to the post's slug. By accessing your static page with the specified slug as a parameter, you will observe the server-side management of all open graph meta tags:

http://<fqdn>/static.php?id=<slug>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Fresh ajax requests are not clearing the current data displayed in the JSP table

My ajax function retrieves data from a servlet and displays it in the page successfully. However, each time a new ajax call is made, the form appends the new data to the existing results instead of replacing them. I need to reset the current values stored ...

What is the procedure for turning off hover color on an href element?

Working on a website that utilizes MUI components, I have incorporated href into the Tab elements within the navigation bar. <Tab label={element} id={index} sx={{display: {xs: 'none', md: 'inherit'}}} href={`#${navElements[element ...

Combine two arrays of objects and merge properties using the Ramda library

I have two arrays as shown below: ['TAG.u', 'TAG.c'] and the other one is: [{name:'some',key:'TAG.u'}, {name:'some new', key: 'TAG.b'}, {name:'some another' , key:'TAG.c'} ...

Is there a way to individually apply loading to only the button that has been clicked in vuejs?

One problem I am facing is that when I click a specific button in a table, all buttons end up in loading mode. The table loops and displays data from an API, with a button embedded in each row. Upon clicking the button, it should send the ID of the clicked ...

Beginner's guide to integrating the @jsplumb/browser-ui into your Vuejs/Nuxtjs project

I am working on the integration of @jsplumb/browser-ui community edition into my application. After receiving a recommendation from the team at jsplumb, I decided to utilize @jsplumb/browser-ui. However, I am facing difficulty in understanding how to begin ...

change visibility:hidden to visible in a css class using JavaScript

I've put together a list of Game of Thrones characters who might meet their demise (no spoilers included). However, I'm struggling with removing a CSS class as part of my task. Simply deleting the CSS is not the solution I am looking for. I' ...

The program keeps encountering the issue of returning undefined while attempting to calculate the sum of elements in an array

I'm having trouble with the code below, it seems to be returning undefined for the sum of the array. Any advice or assistance would be greatly appreciated. var myExpenses = []; var total; function appendExpenses() { ...

I will receive a 404 error if I try to access a URL without including the hashtag symbol

Is it feasible to display a record by directly inputting the user ID in the URL without using the # symbol? I am currently working on a website where I have a single view page named Login.html. I want to be able to access this page by entering the user&ap ...

Adding options to a dropdown list dynamically within a ASP.NET Datagrid using Jquery

While the function in my 'aspx' page is functioning properly, I am facing an issue with the 'dropdown' inside the GridControl. It appears to be getting duplicated from the original row and not updating with the values from the appended ...

Clicking a button in JavaScript can pass an ID by triggering an onClick

Here is the function that triggers when the button is clicked <button type="button" class="btn btn-info " onClick= "show('<?php echo $data ?>')" name="show" >Show</button> This is the show function defined in the .js file f ...

How can I display input only when a checkbox is selected? React with Next.js

I'm trying to figure out how to handle this task, but I'm a bit confused on the approach. I would like to display the promo code field only when the checkbox (I have a promo code) is checked. Additionally, it would be ideal to reveal this field ...

Using ReactJS to insert an array of objects into an object nested within another array object

After receiving a response from a REST call, I am working with an array of objects. response.data.steps Here is an example of how it looks: https://i.sstatic.net/h2QsL.png Now, my task is to add a new Object Array to each Child of this array. Can anyo ...

Automatically filling in related information in multiple input fields after choosing a value in a specific input field using JavaScript

My horizontal form is dynamically generated using JavaScript, with each input field having a jQuery autocomplete that retrieves data from a database using the $.get method. I'm looking to automatically populate the second input field with the corresp ...

Angular HTTP request URLs are dynamically appended to the current URL in Internet Explorer within a custom MVC route leading to

I've hit a roadblock with some custom routing I implemented. Our custom routes handle product perma-links, and Angular makes requests to the server for non-perma-link routes. Everything works smoothly in all browsers except for IE. In IE, the relativ ...

Angular is failing to retrieve data from FS.readFile using promises

My goal is to utilize an Angular service to decide whether to call fs.readFile or fs.writeFile based on the button pressed, in order to explore the interaction between node and angular promises. Although I have managed to read and write files, I am facing ...

Display the div only after all images have finished loading in response to the AJAX call

Prior to diving into this, I am determined to steer clear of utilizing Jquery for personal reasons that I won't delve into. So please refrain from suggesting it, as that is not the solution I seek. I am currently working on a web page that sends mult ...

Adjust the tally of search results and modify the selection depending on the frequency of the user's searches within an array of objects

Seeking assistance with adding a new function that allows users to navigate to the next searched result. Big thanks to @ggorlen for aiding in the recursive search. https://i.stack.imgur.com/OsZOh.png I have a recursive search method that marks the first ...

Tips for receiving feedback when uploading multiple images

I've been facing challenges with receiving a response when uploading multiple images using the API. Despite getting a valid response when uploading a single image, I'm not getting the expected response for multiple uploads. Below is my code: fil ...

Encountered an issue retrieving audio during recording with Recorder.js

I've come across a scenario where I'm utilizing the Recorder.js Demo for recording audio. Interestingly, it works perfectly on Linux but encounters an issue when used on Windows. A pop-up alert stating "Error getting audio" shows up. Here's ...

Parent state in AngularJS, identifying state transitions

Currently, I am utilizing ui-router in my project. Within the application, there is a state labeled user, which showcases a list of users. Additionally, there exists another state known as user.edit, presenting a form along with a submit button for user in ...