Jump to content

Recommended Posts

Posted

Hi everyone,

I've been running this module in production a spirits catalog with 12,000+ products — for several months. Today I'm releasing it publicly.

GitHub: https://github.com/mxmsmnv/Collections

The problem

ProcessWire's page tree is brilliant for site structure. It's painful for data management. When you have thousands of pages as records — products, listings, vacancies, menu items — you hit the same walls on every project: no table view, no inline filters, no bulk actions, no export, no REST API, no role scoping per dataset.

Every PW developer has solved some version of this. Collections solves it once.

Screenshots

col1.thumb.png.6cd1705ea49faea6f3816393b7886c6c.png col1-dark.thumb.png.f09459ddb87d920eafdb641c696f07fa.png

col2.png.d89734d75d147e365c6794e36fdb9538.png col3.png.bed5a85b61a08b994df977e1e8103679.png

col7.png.8dd72336d58efb0d4c08a75fe95c3ba0.png col4.png.8dd0c316aa682c10f892b65ca08627c0.png

col5.png.ee20f73576a3ae2dfd42bd878ac7d6f9.png col6.png.d843289011c5892dce54faf5fa3f9ee4.png

What it does

Gives any ProcessWire template a configurable admin table — live search, dropdown filters, inline status toggles, bulk actions, CSV/JSON export, and a REST API — all configured through a UI, without writing code.

Admin UI:

  • Configurable columns per collection with custom labels
  • Live search with 300ms debounce across multiple fields including Page references
  • Dropdown filters for FieldtypePage and FieldtypeOptions fields
  • Inline publish/unpublish toggle via AJAX
  • Bulk actions: publish, unpublish, delete with CSRF protection
  • CSV and JSON export with active filters preserved
  • Role-based permissions matrix — scope each role per collection
  • "View in Collection" button injected into the page edit form

REST API:

  • Bearer token, query param, HTTP Basic, and PW session auth
  • API key management with expiration dates and per-key capability scopes
  • SHA-256 hashed keys, usage tracking, rate limiting (100 req/min)
  • WireCache support for GET responses

ProFields support: Table, Textareas, Multiplier, Repeater Matrix, Combo — including dot-notation for subfields (address.city, blocks.hero.title, prices.*.amount)

Field types: Text, Textarea, Integer, Float, Checkbox, URL, Email, Date, Image, File, FieldtypeFileB2, FieldtypePage, FieldtypeOptions, MapMarker, Color

Requirements: ProcessWire 3.0.244+, PHP 8.2+

 

There's a thread from 2013 asking for exactly this: Module Idea: Flat Listings — here it is, 12 years later.

Known issues are tracked on GitHub — the module is stable for production use, active development continues.

  • Like 21
  • Thanks 1
Posted

Brilliant implementation as usual. Ditto - I find when creating modules that tables are almost always the most important working view and the data model I have to fight and customise the most. I’d love to see this incorporated into the core and more modules too. 

  • Like 2
Posted
4 hours ago, Peter Knight said:

I’d love to see this incorporated into the core and more modules too. 

Since it partially solves what Lister Pro is about, we cannot expect something like this in the core.

Anyway, thank you @maximus for sharing this module, I will surely try it out. 

  • Like 2
Posted

Thanks for sharing this! It looks really helpful.

Does the Collections link in the top nav behave like a dropdown menu with all the collections listed when hovered?

Posted

Not yet — currently it renders as a single top-level link. A dropdown listing all collections on hover is a reasonable UX improvement and I'll add it to the roadmap. The main challenge is that collections lists can get long, so it'll need some thought around grouping or truncation.

  • Like 4
Posted

@maximus Thanks for all your modules, you're on a roll!  I've tested this module and opened an issue. It's probably a misunderstanding on my part, but when you get a chance, could you take a look at it? Thanks!

  • Like 1
Posted

Hi @jacmaes, thanks for the kind words and for taking the time to test!

Both issues you reported are fixed in v1.9.2 (released today). Quick summary:

  1. Unix timestamps for start_date / end_date — datetime fields are now auto-detected by field type and formatted automatically, no manual column type override needed.
  2. Filter dropdown doing nothing — two bugs were at play: the Apply button wasn't showing up on select change (DOM queried before ready), and the query string was encoding [ / ] as %5B%5D which PHP couldn't parse as an array. Both fixed.

Full details in the changelog. Let me know if anything else comes up!

  • Like 2
Posted

Wonderful, thanks @maximus! I can confirm that these two issues are fixed. I've added a follow-up to my Github issue as the sorting order by date does not seem to work.  

Posted

Thank you very much for your feedback and for your contribution to helping us refine the module! I'll try to make some adjustments in the coming days.

The module has been in development since February 2026, so stable operation was paramount.

If you have any issues or suggestions for improvement, I'm always happy to help!

  • Like 1
Posted

Hi @maximus, I've been trying it out this module too and really like it!  I have a couple of suggestions, if that's OK?
 

  1. Pages that don't have template view files (<templatename>.php) still show a view icon in the collection list, resulting in a 404 when clicked.  This could be solved by adding a $page->viewable() check to the $showViewLink boolean.
  2. When a template's "Can this template be used for new pages?" setting ("noParents") is set to -1 (only one page) or 1 (no new pages), the "Add [collectionItem]" button still shows.  Maybe a canAddNew() method of the Collection class to hide the button in those circumstances? [this worked for me, though there may be a more elegant way, or that suits your coding style]:
    /**
     * Whether the admin "Add" button should be shown for this collection.
     * Mirrors ProcessPageAdd's logic on Template::noParents:
     *   1  → template disallows new pages
     *  -1  → singleton; only allowed while no page using it exists yet
     */
    public function canAddNew(): bool
    {
        $template = wire('templates')->get($this->template);
        if (!$template || !$template->id) return false;

        $noParents = (int) $template->noParents;
        if ($noParents === 1) return false;
        if ($noParents === -1) {
            return $template->getNumPages() === 0;
        }
        return true;
    }

//and then in collection-list.php:

<?php if ($canCreate && $collection->canAddNew()):
	$addTemplate = $wire->templates->get($collection->template);
	$addUrl = $adminUrl . 'page/add/?template_id=' . $addTemplate->id;
?>

Anyway, thanks for the great module!

  • Like 1
Posted

Both issues are fixed in v1.9.3 just released!

@jacmaes - the sort direction bug is fixed. Root cause: the default sort direction parameter was always 'asc' (a non-empty string), so the fallback to the collection's configured direction was never reached. Now when no explicit sort is in the URL, both the sort field and direction come from the collection settings.

@iank - both your suggestions are implemented, and your code was pretty much used as-is, thanks for that!

  1. View icon is now hidden for pages where $page->viewable() returns false
  2. Added canAddNew() to the Collection class that checks noParents — hides the Add button when set to "no new pages" or when it's a singleton and a page already exists

And thanks to @elabx for the kind words!

  • Like 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...