Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-05-03T11:49:33.087Z
Answers.Text: 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 :)
Answers.UserDisplayName: Jonathan Schofield
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-05-03T13:56:55.340Z
Answers.Text: 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.
Answers.UserDisplayName: Jonathan Schofield
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-05-03T10:31:03.480Z
Answers.LastActivityDate: 2024-05-03T10:31:03.480Z
Answers.UserDisplayName: James Smith
Body: <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>
  
Tags: <matrix><block-types>
Title: How to get all Matrix block fields in a templated table of all fields
ThreadText: # 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](https://docs.craftcms.com/api/v4/) 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`](https://docs.craftcms.com/api/v4/craft-services-matrix.html#property-allblocktypes), [`blockTypeFields`](https://docs.craftcms.com/api/v4/craft-fields-matrix.html#property-blocktypefields) and [`blockTypes`](https://docs.craftcms.com/api/v4/craft-fields-matrix.html#property-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 %}
  
  <table>
      <thead>
          <tr>
              <th align="right">Count</th>
              <th>Name</th>
              <th>Handle</th>
              <th>Type</th>
              <th>Block fields</th>
              <th>Options</th>
          </tr>
      </thead>
      <tbody>
      {% for f in fields %}
          {% set type = f.className|replace('/^.*\\\\/', '') %}
          <tr>
              <td align="right">{{ loop.index0 }}</td>
              <td>{{ f.name }}</td>
              <td>{{ f.handle }}</td>
              <td>{{ type }}</td>
              <td>
                  {% if type == 'Matrix' %}
                  {# 
                      - Do something here based on something like 
                          craft.app.fields.allBlockTypes()
                      - except that doesn't work :/
                  #}
                  {% endif %}
              </td>
              <td>{{ f.hasProperty('options') ? _self.getOptions(f) : '' }}</td>
          </tr>
      {% endfor %}
      </tbody>
  </table>
  
  ```
  
  PS: my thanks to username_1 for the [use of `className` above](https://craftcms.stackexchange.com/a/35639/3507).
  
  **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:
  
  ```twig
  {% 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 %}
  
  <table border="1">
      <thead>
          <tr>
              <th align="right">Count</th>
              <th>Name</th>
              <th>Handle</th>
              <th>Type</th>
              <th>Block fields</th>
              <th>Options</th>
          </tr>
      </thead>
      <tbody>
          {% for f in fields %}
              {% set type = f.className|replace('/^.*\\\\/', '') %}
              <tr>
                  <td align="right">{{ loop.index0 }}</td>
                  <td>{{ f.name }}</td>
                  <td>{{ f.handle }}</td>
                  <td>{{ type }}</td>
                  <td>
                      {% if type == 'Matrix' %}
                          <table border="1">
                              <thead>
                                  <tr>
                                      <th align="right">Count</th>
                                      <th>Name</th>
                                      <th>Handle</th>
                                      <th>Type</th>
                                      <th>Options</th>
                                  </tr>
                              </thead>
                              <tbody>
                                  {% for blockField in f.blockTypeFields %}
                                      {% set type = blockField.className|replace('/^.*\\\\/', '') %}
                                      <tr>
                                          <td align="right">{{ loop.index0 }}</td>
                                          <td>{{ blockField.name }}</td>
                                          <td>{{ blockField.handle }}</td>
                                          <td>{{ type }}</td>
                                          <td>{{ blockField.hasProperty('options') ? _self.getOptions(blockField) : '' }}</td>
                                      </tr>
                                  {% endfor %}
                              </tbody>
                          </table>
                      {% endif %}
                  </td>
                  <td>{{ f.hasProperty('options') ? _self.getOptions(f) : '' }}</td>
              </tr>
          {% endfor %}
      </tbody>
  </table>
  
  ```
  
  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 username_1. 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 username_1, 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.  
  
  ---
  
  