Skip to content

Feature request: hookable ref-page resolver for image fields (RPB / non-textarea use cases) #12

Description

@inreti-sb

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions