Problem
Image Library's "Used in" tracking currently only covers images embedded in textarea/CKEditor fields (via Insert from Library). Images stored in FieldtypeImage fields — whether on regular content pages or on RockPageBuilder block child pages — are not indexed and show up as "unused" even when actively in use.
On a site with ~4700 images almost exclusively managed via image fields (gallery pages, news articles, RPB blocks), the "Used in" column is effectively empty.
RPB makes this especially difficult
RockPageBuilder stores block content on child pages with auto-generated templates named rockpagebuilderblock-*. Each block page carries its images in image fields (e.g. rpb_gallery_images, rpb_hero_image). These block pages have no public URL — the relevant page for editors is the parent content page that contains the block.
So for RPB, tracking image fields alone is not enough: the ref_page_id must be resolved from the block page up to the first non-block ancestor to produce a useful "Used in" reference.
Proposed solution
Two-step approach:
1. Index images in FieldtypeImage fields
Extend scanUsage() (or add a parallel scan) to also index images stored in image fields, not just textarea embeds. Default behaviour: ref_page_id = page_id (the page that owns the image field is the usage reference).
This already helps all sites using image fields without CKEditor embeds.
2. Hookable ref-page resolver
Expose a hookable method — e.g. resolveRefPageId(Page $imagePage): int — that returns the ref_page_id for a given image-owning page. The default implementation returns $imagePage->id. Third-party code (RPB integrations, custom modules) can hook into it to remap block pages to their content page:
// In site/ready.php or a dedicated RPB integration module:
$wire->addHookAfter('ProcessImageLibrary::resolveRefPageId', function(HookEvent $event) {
$page = $event->arguments(0);
if (strncmp((string) $page->template->name, 'rockpagebuilderblock-', 21) !== 0) return;
$ref = $page->parent;
while ($ref->id && strncmp((string) $ref->template->name, 'rockpagebuilderblock-', 21) === 0) {
$ref = $ref->parent;
}
if ($ref->id) $event->return = $ref->id;
});
This keeps the module free of RPB-specific knowledge while making it extensible for the growing RPB community.
Current workaround
We implemented a workaround via hooks in site/ready.php that:
- uses SQL bulk-inserts (
INSERT IGNORE) into process_imagelibrary_usage directly
- hooks
Pages::saved for incremental updates
- hooks
ProcessImageLibrary::autoMaintenance (After) to re-insert rows after pruneOrphanedUsageRows() removes them (since our ref_page_id values are not in usageCandidatePageIds())
The maintenance re-insertion workaround in particular feels fragile — it would be much cleaner if image-field rows survived pruning natively or if usageCandidatePageIds() was extended/hookable.
Environment
- ProcessWire 3.0.255, PHP 8.4
- Image Library 1.1.1
- RockPageBuilder (current)
Problem
Image Library's "Used in" tracking currently only covers images embedded in textarea/CKEditor fields (via Insert from Library). Images stored in FieldtypeImage fields — whether on regular content pages or on RockPageBuilder block child pages — are not indexed and show up as "unused" even when actively in use.
On a site with ~4700 images almost exclusively managed via image fields (gallery pages, news articles, RPB blocks), the "Used in" column is effectively empty.
RPB makes this especially difficult
RockPageBuilder stores block content on child pages with auto-generated templates named
rockpagebuilderblock-*. Each block page carries its images in image fields (e.g.rpb_gallery_images,rpb_hero_image). These block pages have no public URL — the relevant page for editors is the parent content page that contains the block.So for RPB, tracking image fields alone is not enough: the
ref_page_idmust be resolved from the block page up to the first non-block ancestor to produce a useful "Used in" reference.Proposed solution
Two-step approach:
1. Index images in FieldtypeImage fields
Extend
scanUsage()(or add a parallel scan) to also index images stored in image fields, not just textarea embeds. Default behaviour:ref_page_id = page_id(the page that owns the image field is the usage reference).This already helps all sites using image fields without CKEditor embeds.
2. Hookable ref-page resolver
Expose a hookable method — e.g.
resolveRefPageId(Page $imagePage): int— that returns theref_page_idfor a given image-owning page. The default implementation returns$imagePage->id. Third-party code (RPB integrations, custom modules) can hook into it to remap block pages to their content page:This keeps the module free of RPB-specific knowledge while making it extensible for the growing RPB community.
Current workaround
We implemented a workaround via hooks in
site/ready.phpthat:INSERT IGNORE) intoprocess_imagelibrary_usagedirectlyPages::savedfor incremental updatesProcessImageLibrary::autoMaintenance(After) to re-insert rows afterpruneOrphanedUsageRows()removes them (since ourref_page_idvalues are not inusageCandidatePageIds())The maintenance re-insertion workaround in particular feels fragile — it would be much cleaner if image-field rows survived pruning natively or if
usageCandidatePageIds()was extended/hookable.Environment