<p>That's actually a very interesting set of data, thanks - I might use it myself! Here's how to get at the nested matrix block fields you're after:</p>
<pre class="lang-twig prettyprint-override"><code>{% set fields = craft.app.fields.allFields() %}

{% macro getOptions(f) %}
    {% set opts = [] %}

    {% for opt in f.options %}
        {% if opt.value is defined %}
            {% set opts = opt.value ? 
                opts|merge([ opt.value ]) : opts %}
        {% else %}
            {% set opts = opt.optgroup is defined ? 
                opts|merge([ &quot;optgroup:#{opt.optgroup}&quot; ]) : opts %}
        {% endif %}
    {% endfor %}

    {{ opts|join(', ') }}
{% endmacro %}

&lt;table border=&quot;1&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th align=&quot;right&quot;&gt;Count&lt;/th&gt;
            &lt;th&gt;Name&lt;/th&gt;
            &lt;th&gt;Handle&lt;/th&gt;
            &lt;th&gt;Type&lt;/th&gt;
            &lt;th&gt;Block fields&lt;/th&gt;
            &lt;th&gt;Options&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        {% for f in fields %}
            {% set type = f.className|replace('/^.*\\\\/', '') %}
            &lt;tr&gt;
                &lt;td align=&quot;right&quot;&gt;{{ loop.index0 }}&lt;/td&gt;
                &lt;td&gt;{{ f.name }}&lt;/td&gt;
                &lt;td&gt;{{ f.handle }}&lt;/td&gt;
                &lt;td&gt;{{ type }}&lt;/td&gt;
                &lt;td&gt;
                    {% if type == 'Matrix' %}
                        &lt;table border=&quot;1&quot;&gt;
                            &lt;thead&gt;
                                &lt;tr&gt;
                                    &lt;th align=&quot;right&quot;&gt;Count&lt;/th&gt;
                                    &lt;th&gt;Name&lt;/th&gt;
                                    &lt;th&gt;Handle&lt;/th&gt;
                                    &lt;th&gt;Type&lt;/th&gt;
                                    &lt;th&gt;Options&lt;/th&gt;
                                &lt;/tr&gt;
                            &lt;/thead&gt;
                            &lt;tbody&gt;
                                {% for blockField in f.blockTypeFields %}
                                    {% set type = blockField.className|replace('/^.*\\\\/', '') %}
                                    &lt;tr&gt;
                                        &lt;td align=&quot;right&quot;&gt;{{ loop.index0 }}&lt;/td&gt;
                                        &lt;td&gt;{{ blockField.name }}&lt;/td&gt;
                                        &lt;td&gt;{{ blockField.handle }}&lt;/td&gt;
                                        &lt;td&gt;{{ type }}&lt;/td&gt;
                                        &lt;td&gt;{{ blockField.hasProperty('options') ? _self.getOptions(blockField) : '' }}&lt;/td&gt;
                                    &lt;/tr&gt;
                                {% endfor %}
                            &lt;/tbody&gt;
                        &lt;/table&gt;
                    {% endif %}
                &lt;/td&gt;
                &lt;td&gt;{{ f.hasProperty('options') ? _self.getOptions(f) : '' }}&lt;/td&gt;
            &lt;/tr&gt;
        {% endfor %}
    &lt;/tbody&gt;
&lt;/table&gt;
</code></pre>
<p>I'm not sure about performance here, but assuming it's for a occasional internal use-case it probably doesn't matter if it's not great.</p>

CC BY-SA 4.0
2024-05-03T11:49:33.087Z
Oh thanks James. You’re a star. When I was exploring earlier and `dump`ed `f` for 'Matrix' fields, it reported `blockTypeFields` as `null`, so I assumed some other method was needed. But after your insight, when I `dump(f.blockTypeFields)` I get the data you have revealed to me. So it's not `null` at all! Thanks :)
Jonathan Schofield
CC BY-SA 4.0
2024-05-03T13:56:55.340Z
Using your insight James, I've worked the above into a Gist: https://gist.github.com/watershed/3746fb96d87a5a7c5e0ce9db48300928. Which gathers all the `field` and `blockField` data into a hash (so it can be output as something other than a table if desired), and then writes a table with striping that visually groups `blockField` rows with their parent `Matrix` rows.
Jonathan Schofield
CC BY-SA 4.0
2024-05-03T10:31:03.480Z
2024-05-03T10:31:03.480Z
James Smith
<p>I want to produce a templated table of all fields, including Matrix block fields which belong to their parent Matrix field.</p>
<p>I've been scratching around the <a href="https://docs.craftcms.com/api/v4/" rel="nofollow noreferrer">Craft 4 class reference</a> and getting nowhere. I realise that the class reference is written for customising and extending Craft, not for templating, but it is a frustration that it is mostly a process of trial and error as to which methods are exposed via which template ‘calls’, if at all.</p>
<p>Here below is my template code which prints out each field’s name, handle, type and options, but I cannot for the life of me figure out how to get the block fields which belong to my reported Matrix fields.</p>
<p>I’ve tried various syntaxes related to <a href="https://docs.craftcms.com/api/v4/craft-services-matrix.html#property-allblocktypes" rel="nofollow noreferrer"><code>allBlockTypes</code></a>, <a href="https://docs.craftcms.com/api/v4/craft-fields-matrix.html#property-blocktypefields" rel="nofollow noreferrer"><code>blockTypeFields</code></a> and <a href="https://docs.craftcms.com/api/v4/craft-fields-matrix.html#property-blocktypes" rel="nofollow noreferrer"><code>blockTypes</code></a> but no joy.</p>
<p>I’m not sure if any of these are supposed to stem from <code>craft.app.fields</code> or something else, or not actually exposed to templating methods at all?</p>
<pre><code>{% set fields = craft.app.fields.allFields() %}

{% macro getOptions(f) %}
    {% set opts = [] %}

    {% for opt in f.options %}
        {% if opt.value is defined %}
            {% set opts = opt.value ? 
                opts|merge([ opt.value ]) : opts %}
        {% else %}
            {% set opts = opt.optgroup is defined ? 
                opts|merge([ &quot;optgroup:#{opt.optgroup}&quot; ]) : opts %}
        {% endif %}
    {% endfor %}

    {{ opts|join(', ') }}
{% endmacro %}

&lt;table&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th align=&quot;right&quot;&gt;Count&lt;/th&gt;
            &lt;th&gt;Name&lt;/th&gt;
            &lt;th&gt;Handle&lt;/th&gt;
            &lt;th&gt;Type&lt;/th&gt;
            &lt;th&gt;Block fields&lt;/th&gt;
            &lt;th&gt;Options&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
    {% for f in fields %}
        {% set type = f.className|replace('/^.*\\\\/', '') %}
        &lt;tr&gt;
            &lt;td align=&quot;right&quot;&gt;{{ loop.index0 }}&lt;/td&gt;
            &lt;td&gt;{{ f.name }}&lt;/td&gt;
            &lt;td&gt;{{ f.handle }}&lt;/td&gt;
            &lt;td&gt;{{ type }}&lt;/td&gt;
            &lt;td&gt;
                {% if type == 'Matrix' %}
                {# 
                    - Do something here based on something like 
                        craft.app.fields.allBlockTypes()
                    - except that doesn't work :/
                #}
                {% endif %}
            &lt;/td&gt;
            &lt;td&gt;{{ f.hasProperty('options') ? _self.getOptions(f) : '' }}&lt;/td&gt;
        &lt;/tr&gt;
    {% endfor %}
    &lt;/tbody&gt;
&lt;/table&gt;
</code></pre>
<p>PS: my thanks to James Smith for the <a href="https://craftcms.stackexchange.com/a/35639/3507">use of <code>className</code> above</a>.</p>

<matrix><block-types>
How to get all Matrix block fields in a templated table of all fields
# How to get all Matrix block fields in a templated table of all fields

(Asked by: username_0 on 2024-05-03)

I want to produce a templated table of all fields, including Matrix block fields which belong to their parent Matrix field.
I've been scratching around the Craft 4 class reference and getting nowhere. I realise that the class reference is written for customising and extending Craft, not for templating, but it is a frustration that it is mostly a process of trial and error as to which methods are exposed via which template ‘calls’, if at all.
Here below is my template code which prints out each field’s name, handle, type and options, but I cannot for the life of me figure out how to get the block fields which belong to my reported Matrix fields.
I’ve tried various syntaxes related to allBlockTypes, blockTypeFields and blockTypes but no joy.
I’m not sure if any of these are supposed to stem from craft.app.fields or something else, or not actually exposed to templating methods at all?
{% set fields = craft.app.fields.allFields() %}

{% macro getOptions(f) %}
    {% set opts = [] %}

    {% for opt in f.options %}
        {% if opt.value is defined %}
            {% set opts = opt.value ? 
                opts|merge([ opt.value ]) : opts %}
        {% else %}
            {% set opts = opt.optgroup is defined ? 
                opts|merge([ "optgroup:#{opt.optgroup}" ]) : opts %}
        {% endif %}
    {% endfor %}

    {{ opts|join(', ') }}
{% endmacro %}


    
        
            Count
            Name
            Handle
            Type
            Block fields
            Options
        
    
    
    {% for f in fields %}
        {% set type = f.className|replace('/^.*\\\\/', '') %}
        
            {{ loop.index0 }}
            {{ f.name }}
            {{ f.handle }}
            {{ type }}
            
                {% if type == 'Matrix' %}
                {# 
                    - Do something here based on something like 
                        craft.app.fields.allBlockTypes()
                    - except that doesn't work :/
                #}
                {% endif %}
            
            {{ f.hasProperty('options') ? _self.getOptions(f) : '' }}
        
    {% endfor %}
    


PS: my thanks to James Smith for the use of className above.

**Tags:** matrix, block-types

---

## 1 answers

### Answer by username_1 on 2024-05-03. Score: 2

That's actually a very interesting set of data, thanks - I might use it myself! Here's how to get at the nested matrix block fields you're after:
{% set fields = craft.app.fields.allFields() %}

{% macro getOptions(f) %}
    {% set opts = [] %}

    {% for opt in f.options %}
        {% if opt.value is defined %}
            {% set opts = opt.value ? 
                opts|merge([ opt.value ]) : opts %}
        {% else %}
            {% set opts = opt.optgroup is defined ? 
                opts|merge([ "optgroup:#{opt.optgroup}" ]) : opts %}
        {% endif %}
    {% endfor %}

    {{ opts|join(', ') }}
{% endmacro %}


    
        
            Count
            Name
            Handle
            Type
            Block fields
            Options
        
    
    
        {% for f in fields %}
            {% set type = f.className|replace('/^.*\\\\/', '') %}
            
                {{ loop.index0 }}
                {{ f.name }}
                {{ f.handle }}
                {{ type }}
                
                    {% if type == 'Matrix' %}
                        
                            
                                
                                    Count
                                    Name
                                    Handle
                                    Type
                                    Options
                                
                            
                            
                                {% for blockField in f.blockTypeFields %}
                                    {% set type = blockField.className|replace('/^.*\\\\/', '') %}
                                    
                                        {{ loop.index0 }}
                                        {{ blockField.name }}
                                        {{ blockField.handle }}
                                        {{ type }}
                                        {{ blockField.hasProperty('options') ? _self.getOptions(blockField) : '' }}
                                    
                                {% endfor %}
                            
                        
                    {% endif %}
                
                {{ f.hasProperty('options') ? _self.getOptions(f) : '' }}
            
        {% endfor %}
    


I'm not sure about performance here, but assuming it's for a occasional internal use-case it probably doesn't matter if it's not great.

> **Comments:**
> **username_0**: Oh thanks James. You’re a star. When I was exploring earlier and `dump`ed `f` for 'Matrix' fields, it reported `blockTypeFields` as `null`, so I assumed some other method was needed. But after your insight, when I `dump(f.blockTypeFields)` I get the data you have revealed to me. So it's not `null` at all! Thanks :)  
> **username_0**: Using your insight James, I've worked the above into a Gist: https://gist.github.com/watershed/3746fb96d87a5a7c5e0ce9db48300928. Which gathers all the `field` and `blockField` data into a hash (so it can be output as something other than a table if desired), and then writes a table with striping that visually groups `blockField` rows with their parent `Matrix` rows.  

---

