4

I have a fairly large site with the main content on most pages driven by a Matrix field. That Matrix field has 15 or so different Blocks - we are now doing a tidy up on the site and going to try and reduce the number of blocks available - is there any way to tell if a block isn't being used?

mmc501
  • 1,779
  • 13
  • 34

1 Answers1

10

Nothing native, but it can be done with an SQL query – something like this should work (note that all the queries assume that your dbPrefix setting is set to 'craft_'):

SELECT bt.id, bt.handle, f.handle as field 
FROM craft_matrixblocktypes bt 
INNER JOIN craft_fields f ON bt.fieldId = f.id 
LEFT JOIN craft_matrixblocks b ON bt.id = b.typeId 
WHERE b.id IS NULL 

The above query would output a table with the id and handle for all block types that aren't used, in addition to the handle for the Matrix field they belong to, i.e.

id  | handle             | field
------------------------------------------
13  | someMatrixBlock    | someMatrixField
4   | anotherMatrixBlock | someMatrixField

To actually execute the SQL query, you can use a free tool like Sequel Pro or phpMyAdmin – or write a custom plugin that uses the QueryBuilder.

Edit

Upon request in the comments below, here's a query that will list all block types that are in use (i.e. there are blocks for each particular block type). The number of blocks for each type is listed in a count column:

SELECT COUNT(bt.id) as count, bt.id, bt.handle, f.handle as field 
FROM craft_matrixblocktypes bt 
INNER JOIN craft_fields f ON bt.fieldId = f.id 
LEFT JOIN craft_matrixblocks b ON bt.id = b.typeId 
WHERE b.id IS NOT NULL 
GROUP BY bt.id    

...and here's a query that will output a table with all blocks, sorted by block type, with the ID and URI for the entry which "owns" each particular block. The following query should work for Craft 2:

SELECT b.id as blockId, bt.handle as blockType, bt.id as blockTypeId, e.id as entryId, i18n.uri as entryUri, f.handle as field
FROM craft_matrixblocks b
INNER JOIN craft_entries e on e.id = b.ownerId
INNER JOIN craft_fields f on f.id = b.fieldId
INNER JOIN craft_matrixblocktypes bt on bt.id = b.typeId
LEFT JOIN craft_elements_i18n i18n on i18n.elementId = e.id
ORDER BY bt.id

For Craft 3 (and 4), you'll need to replace the craft_elements_i18n table with craft_elements_sites:

SELECT b.id as blockId, bt.handle as blockType, bt.id as blockTypeId, e.id as entryId, sites.uri as entryUri, f.handle as field
FROM craft_matrixblocks b
INNER JOIN craft_entries e on e.id = b.ownerId
INNER JOIN craft_fields f on f.id = b.fieldId
INNER JOIN craft_matrixblocktypes bt on bt.id = b.typeId
LEFT JOIN craft_elements_sites sites on sites.elementId = e.id
ORDER BY bt.id

If you want to exclude drafts, revisions and soft-deleted entries, include this in the query:

INNER JOIN craft_elements els on els.id = b.ownerId 
WHERE els.dateDeleted IS NULL AND els.draftId IS NULL AND els.revisionId IS NULL AND els.archived = 0

Edit: For Craft 4, you'll want to replace all instances of b.ownerId with b.primaryOwnerId.

If you want to limit that last query to only list the blocks for a particular block type, you can replace the ORDER BY statement with this:

WHERE bt.id = 2

Where 2 is the ID for the block type you want to list.

Mats Mikkel Rummelhoff
  • 22,361
  • 3
  • 38
  • 69
  • Excellent - really useful - in a similar manner then is it possible to find the number of times a block from a particular field does appear and say what page it is on – mmc501 Dec 22 '16 at 10:35
  • The number of times a block type have been used (i.e. the number of blocks with that particular block type) should be easy enough, but if you want to output the ID/handle/URL for any elements with relevant blocks you're going to have to pull multiple rows for each block type (one per element), so I don't see those two operations being very useful together. – Mats Mikkel Rummelhoff Dec 22 '16 at 10:56
  • Thanks - the number of times of block type would be used would be very useful as we could see then what blocks we could do away with. If there is a few then some way to find easily what entries the block is used in - even if it needed to be a separate query as there are a large number of entries on the site so could be hard to find manually – mmc501 Dec 22 '16 at 10:58
  • @mmc501 Edited my answer and added a couple queries that might prove useful. – Mats Mikkel Rummelhoff Dec 22 '16 at 11:31
  • 1
    First class - easy to tidy up now - much appreciated! – mmc501 Dec 22 '16 at 12:49
  • 1
    @mmc501The queries you provided are SUPER helpful. Just wanted to say thank you! You helped me considerably with this answer. – dpayne Jun 07 '17 at 15:17
  • @dpayne Awesome that it proved helpful :) – Mats Mikkel Rummelhoff Jun 07 '17 at 15:22