🧩 Template Surgery: Injecting JSON-LD into XenForo 2.3

Roiarthur

Active member
🧩 Template Surgery: Injecting JSON-LD into XenForo 2.3

👋 Introduction

XenForo is a beast, but its default SEO is a bit "generic". It throws "DiscussionForumPosting" at Google while you are writing technical masterpieces. If you just paste your script blindly into the footer, Google will laugh. We are going to use the XF template engine to inject this dynamically into the <head>, and only on your tutorials. No paid plugins, just clean code.



🎯 Target Audience

XenForo Admins who aren't afraid to touch the "Appearance" button and want quality Rich Snippets.



🧰 Tools or Prerequisites

• AdminCP Access (admin.php)

• The Forum ID (Node ID) where you post your tutorials (e.g., the "Windows" forum is ID 12)

• "Development Mode" enabled (optional but recommended to avoid breaking prod)



🗺️ Overview

Step #1
> Easy > Locate the thread_view template

Step #2 > Intermediate > Conditional Code Injection



🛠️ Step-by-Step Tutorial

🔹 Step #1 > Targeting the Right Organ

1️⃣ Action : Go to Appearance > Templates and search for thread_view.

2️⃣ Utility : This is the template that handles the display of a single topic. It is the only place where variables like "Thread Title" or "Author" actually exist.

3️⃣ Explanation : Do not touch PAGE_CONTAINER for this. If you put it there, you'll have to write complex SQL queries to fetch thread info. In thread_view, everything is served on a silver platter.



✔️ Execution Procedure:

Explanation
: Open the template and position yourself at the very top, after the macros.

Code:
AdminCP > Appearance > Templates > thread_view



🔹 Step #2 > The Transplant (Dynamic Injection)

1️⃣ Action : Insert the JSON-LD code using the <xf:head> tag and dynamic variables.

2️⃣ Utility : If you leave "Tutorial Title" hardcoded, all your topics will have the same title for Google. We replace that with {$thread.title}.

3️⃣ Explanation : We add an <xf:if> condition so that this code ONLY loads in your tutorial forum (replace "X" with your node ID). We use |escape('json') to prevent quotes in a title from breaking the entire script.



✔️ Execution Procedure:

Explanation
: Copy this block to the very top of the thread_view template. Replace '10' with your tutorial forum ID.

Code:
<xf:if is="$thread.node_id == 10">
    <xf:head option="ld_json_techarticle">
        <script type="application/ld+json">
        {
          "@context": "https://schema.org",
          "@type": "TechArticle",
          "headline": "{$thread.title|escape('json')}",
          "image": "{$xf.options.boardUrl}/styles/default/xenforo/xenforo-logo.png",
          "author": {
            "@type": "Person",
            "name": "{$thread.User.username|escape('json')}"
          },
          "publisher": {
            "@type": "Organization",
            "name": "{$xf.options.boardTitle|escape('json')}",
            "logo": {
               "@type": "ImageObject",
               "url": "{$xf.options.boardUrl}/styles/default/xenforo/xenforo-logo.png"
            }
          },
          "datePublished": "{{ date($thread.post_date, 'c') }}",
          "dateModified": "{{ date($thread.last_post_date, 'c') }}",
          "description": "{$thread.FirstPost.message|snippet(160)|escape('json')}"
        }
        </script>
    </xf:head>
</xf:if>



⚠️ Troubleshooting (Failsafe):

If error
: White page or Template syntax error.

Fix : Check that you have closed the <xf:if> tag. Check that you haven't forgotten a comma in the JSON.

Code:
Validate your JSON on https://validator.schema.org/ after modification



🆚 Differences Between Versions

On XenForo 1.x, it was a jungle. On 2.3, the use of <xf:head> is clean: it automatically moves the script to the final HTML header, even if you write it in the middle of the body in the template. It's magic.



🎁 Bonus Tip

For the image, if you use an addon that allows "Featured Images" for threads, you can replace the logo URL with the addon variable (often {$thread.CoverImage}). Otherwise, Google will settle for the site logo, which is better than nothing.



🚫 What NOT to do

Do not put this code in PAGE_CONTAINER without a strict condition. Otherwise, your "Privacy Policy" or "Member List" pages will declare themselves as "TechArticle", and Google will penalize you for misleading data.



🧠 Pro Tip

If you have multiple tutorial forums (e.g., Windows, Linux, Mac), use an array in the condition: <xf:if is="in_array($thread.node_id, [10, 12, 15])">. Saves you from duplicating code.



📚 For Further Reading

XenForo Template Documentation

Schema.org Validation Tool

Google TechArticle Docs

Search with Google



📝 Bottom Line

Never copy a static JSON-LD script into a dynamic CMS. Use the {$thread} variables and the <xf:head> tag in the thread_view template. It's the only "clean" way to tell Google: "Hey, look, this is a real technical tutorial, not just forum chatter". Now, save and clear the cache.
 
Back
Top Bottom