iperson1337/opendxp-tag-management-bundle

Tag analytics for the OpenDXP admin: usage statistics per tag, find DataObjects by any/all of the selected tags, CSV/XLSX export

Maintainers

Package info

github.com/iperson1337/opendxp-tag-management-bundle

Type:opendxp-bundle

pkg:composer/iperson1337/opendxp-tag-management-bundle

Transparency log

Statistics

Installs: 18

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-23 10:31 UTC

This package is auto-updated.

Last update: 2026-08-23 15:31:28 UTC


README

Tag analytics for the OpenDXP classic admin: which tags exist, how many DataObjects carry each of them (with a per-class breakdown), which objects carry any / all of the selected tags — and a CSV / XLSX export of that list.

What it does:

  • "Tags" entry in the main navigation (left bar) for users holding the configured permission (tags_search — a core permission, nothing to install). Opens a Tags tab.
  • Tag grid (left): hierarchical name path (Parent / Child), number of objects, compact breakdown by class (Product 15 · Brand 7, full list in the tooltip). Search by name (case-insensitive), filter by object class (only tags used by that class, counts restricted to it), server-side sort by name or usage, paging.
  • Object grid (right): follows the tick marks in the tag grid automatically. Any tag / All tags switch, the selected tags as removable chips, total count, server-side sort on every column, paging, type / published icons, double-click (or the row button) opens the object. Selection survives paging, searching and re-filtering of the tag grid.
  • Export (button menu): CSV (UTF-8 BOM, ; delimiter — opens cleanly in Excel with Cyrillic locales) or XLSX (bold frozen header, auto-filter). Streams in batches up to export.max_rows; cells starting with =, +, -, @, TAB or CR are apostrophe-prefixed against spreadsheet formula injection.

Scope: DataObject assignments only (tags_assignment.ctype = 'object'); assets and documents are not counted. A tag's count is its own assignments — child tags are not rolled up.

Requirements

  • OpenDXP ^1.0 with the classic admin bundle (open-dxp/admin-bundle), PHP 8.3.
  • phpoffice/phpspreadsheet for the XLSX export (declared as a dependency).

Installation

composer require iperson1337/opendxp-tag-management-bundle

config/bundles.php:

Iperson1337\OpenDxpTagManagementBundle\OpenDxpTagManagementBundle::class => ['all' => true],

Then:

bin/console cache:clear
bin/console assets:install          # publishes public/ to /bundles/opendxptagmanagement/
bin/console fos:js-routing:dump     # routes are exposed for Routing.generate() in the admin JS

Routes (config/opendxp/routing.yaml) are picked up automatically by OpenDXP's bundle routing loader; no entry in the application's config/routes.yaml is needed. No installer, no database changes: the bundle only reads the core tags / tags_assignment / objects tables.

Grant the tags_search permission (Settings → Users) to every non-admin user who should see the tab — or point permission at any other permission key you already use.

Configuration

Every key has a default, so the bundle runs without any config/packages/*.yaml. Reference:

bin/console config:dump-reference iperson1337_opendxp_tag_management
bin/console debug:config iperson1337_opendxp_tag_management
iperson1337_opendxp_tag_management:
    permission: tags_search   # admin permission for the menu entry and every endpoint
    page_size: 50             # rows per page in both grids
    max_page_size: 500        # hard upper bound of the "limit" request parameter
    export:
        max_rows: 10000       # objects written into one CSV/XLSX
        batch_size: 500       # objects fetched per query while streaming an export

Admin API

All endpoints are GET, sit behind the admin firewall and the configured permission (403 otherwise), and answer {"success": true, ...}.

Route Purpose Parameters
/admin/tag-management/tags tags with usage statistics search, className, orderBy (name|usageCount), orderDirection, limit, offset
/admin/tag-management/objects objects carrying the tags tagIds (comma-separated, required), matchMode (all|any), className, orderBy (id|key|path|className|published|updatedAt), orderDirection, limit, offset
/admin/tag-management/export same filter, as a file as /objects plus format (csv|xlsx)

Unknown values fall back to the defaults instead of failing; limit is clamped to [1, max_page_size].

Adding an export format

Implement Service\Export\ExporterInterface (format name, content type, extension, write() into a stream). Services implementing the interface are tagged automatically (iperson1337.opendxp_tag_management.exporter) and picked up by ExporterRegistry; the new format appears in the admin export menu on the next page load (exportFormats in opendxp.settings.tagManagement).

Layout

config/
  opendxp/routing.yaml         attribute routes of src/Controller, exposed to FOSJsRouting
  services.yaml
public/
  css/tag-management.css       navigation / tab icon, chips, grid cell styles
  img/tag.svg
  js/opendxp/tagPanel.js       the "Tags" tab (both grids, export)
  js/opendxp/startup.js        settings accessor + main-navigation entry (permission-gated)
src/
  Controller/TagManagementController.php
  DependencyInjection/         Configuration (iperson1337_opendxp_tag_management) + Extension
  EventSubscriber/AdminSettingsSubscriber.php   → opendxp.settings.tagManagement
  Http/QueryParser.php         raw query string → bounded TagQuery / ObjectQuery
  Model/                       TagManagementConfig, TagQuery, ObjectQuery, MatchMode, ObjectOrder, TagOrder, SortDirection
  Repository/                  TagStatsRepository, TaggedObjectRepository (+ TaggedObjectFinderInterface) — DBAL, read-only
  Service/Export/              ExporterInterface, CsvExporter, XlsxExporter, ExporterRegistry, ExportRow, TaggedObjectExportSource
translations/                  admin.ru.yml, admin.en.yml (prefix plugin_pimcore_tag_management_)
tests/                         PHPUnit unit tests (mirrors src/; excluded from the dist archive)

Testing

Pure unit tests, no OpenDXP kernel or database needed:

composer install
vendor/bin/phpunit

License

MIT.