Feature request: accordion as faq section => structured data

Hi there,

is it somehow possible to add a checkbox to the accrodion element if this is a faq block? so it does generate structured data itself?
that would be awesome. or is there a other way to make this possible? native?

thanks in advance for your help.

1 Like

I have a FAQ accordion template that generates a schema here using Twig. It would be nice for it to be a toggle button, but it’s a more serious rewrite to support that. This has been asked a couple of times so I figured I would create something for everybody in the meantime. Have a great day.

https://theme.co/app/uploads/share/faq-section.tco

2 Likes

Hi @charlie!

Your TWIG FAQ solution is amazing!

I tried modifying it so that the dynamic looper uses ACF relation fields instead of the the List group parameter.

Your dynamic content is {{dc:p:faq}}, whereas mine is {{dc:acf:post_field field="service_faq_relations"}}.

Your question is {{ looper.item.question }}, whereas mine is {{dc:acf:post_field field="faq_question"}}.

Your answer is {{ looper.item.answer }}, whereas mine is {{dc:acf:post_field field="faq_answer"}}.

(I tried {{acf.post_field field="faq_question"}}, but that didn’t work, so I left the dc and the columns as they are.)

This is your original TWIG:

Your Original TWIG
{# Setup questions array #}

{% set questions = [] %}

{% for item in p.faq %}

{% set questions = questions|push({
  "@type": "Question",
  "name": item.question,
  "acceptedAnswer": {
    "@type": "Answer",
    "text": item.answer | striptags
  }
}) %}

{% endfor %}

{# Setup and output Schema #}
{% set schema = {
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": questions
} %}

{# Debug {{ schema | json_encode }} #}

<script type="application/ld+json">
{{ schema | json_encode | raw }}
</script>

This is my updated TWIG, which reflects different dynamic content references and parameters:

My Updated TWIG
{# Setup questions array #}

{% set questions = [] %}

{% for item in looper.array %}

  {% set questions = questions|push({
    "@type": "Question",
    "name": item.faq_question,
    "acceptedAnswer": {
      "@type": "Answer",
      "text": item.faq_answer | striptags
    }
  }) %}

{% endfor %}

{# Setup and output Schema #}
{% set schema = {
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": questions
} %}

{# Debug #}
{# {{ schema | json_encode }} #}

<script type="application/ld+json">
  {{ schema | json_encode | raw }}
</script>

I am not getting any immediate errors, but the front end is not rendering the schema. This is all I get:

<script type="application/ld+json">
  {"@context":"https:\/\/schema.org","@type":"FAQPage","mainEntity":[]}
</script>

Followed by a few empty <div> elements.

If this isn’t something that would take too much of your time, it would be amazing if you could provide a working TWIG snippet that generates an FAQ Schema from ACF dynamic content. I believe many of us are generating FAQs this way.

Thank you!

2 Likes

So it’s probably this part that is throwing it off. I don’t think there is a dynamic content data point to get all items in a looper. It would be a nice feature though. Since your using an ACF field for this your probably going to use acf.post_field({"field":" service_faq_relations"}) instead of looper.array. I’m not sure how that data is stored from there, but it might just be faq_answer or if your storing as posts you might need to use acf.post_field again.

{% for item in looper.array %}

We are releasing a feature to Accordions that auto sets this up as well in Pro 6.6.2 or 6.6.3. Having researched this more too, the striptags is unnecessary as Google allows certain HTML here and ignores invalid HTML tags.

2 Likes

Thank you Charlie, that helped!

I got an output with null, but after some thinkering with Claude 3.7. Sonet, I got this working code:

{# Setup questions array #}
{% set questions = [] %}

{# Get the FAQ relationships from ACF, rename as needed #}
{% set faq_relations = acf.post_field({"field": "service_faq_relations"}) %}

{# Check if we have FAQ relations #}
{% if faq_relations %}
  {% for relation in faq_relations %}
    {# Try different approaches to access the fields #}
    
    {# Option 1: If relation is the post ID and fields are stored on that post. Rename fields as needed #}
    {% set faq_question = relation.faq_question ?? acf.post_field({"field": "faq_question", "post_id": relation}) %}
    {% set faq_answer = relation.faq_answer ?? acf.post_field({"field": "faq_answer", "post_id": relation}) %}
    
    {# Option 2: If fields are directly accessible in the relation object #}
    {% if faq_question == null %}
      {% set faq_question = relation.faq_question ?? null %}
      {% set faq_answer = relation.faq_answer ?? null %}
    {% endif %}
    
    {# Add to questions array if we have data #}
    {% if faq_question and faq_answer %}
      {% set questions = questions|push({
        "@type": "Question",
        "name": faq_question,
        "acceptedAnswer": {
          "@type": "Answer",
          "text": faq_answer
        }
      }) %}
    {% endif %}
  {% endfor %}
{% endif %}

{# Setup and output Schema #}
{% set schema = {
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": questions
} %}

{# Debug output to see what data we're getting #}
{# 
<div style="display: none;">
  Service FAQ Relations: {{ faq_relations | json_encode }}
</div>
#}

<script type="application/ld+json">
  {{ schema | json_encode | raw }}
</script>

Thanks again, looking forward to the native solution!