Digital Sovereignty for everyone

Architectural notes

File structure (as of 1.1.4)

The former two god classes (LH_BP_Group_Taxonomies_Admin, LH_BP_Group_Taxonomies_Frontend) were split into eight focused, single-concern files. This wasn’t a mechanical file-per-method split — each cluster was kept together specifically where its methods share request-scoped instance state, and split apart everywhere else:

  • class-admin-bulk-tags.php (LH_BP_Group_Taxonomies_Admin_Bulk_Tags) — the edit-tags.php-emulation cluster (submenu registration, fake post-type registration, the whole add/edit/delete-tag action dispatcher). Kept together: these all read/write $admin_screens/$admin_pages instance state.
  • class-admin-list-tables.php (LH_BP_Group_Taxonomies_Admin_List_Tables) — Groups admin list table integration: taxonomy filter dropdowns, columns, term edit/delete link targets. No shared state with anything else.
  • class-admin-term-columns.php (LH_BP_Group_Taxonomies_Admin_Term_Columns) — term list table column customization (Posts count → Groups count). No shared state.
  • class-admin-group-metabox.php (LH_BP_Group_Taxonomies_Admin_Group_Metabox) — the single-group admin edit screen’s tag metabox. Delegates rendering/saving to LH_BP_Group_Taxonomies_Tag_Editor.
  • class-frontend.php (LH_BP_Group_Taxonomies_Frontend, slimmed) — directory SQL filtering (parse_select()/parse_total()/parse_groups_query()), BP theme-compat handling, and single-tag display. Kept together deliberately: one hook resolves “which tag is this directory view for” into $this->term/$this->taxonomy/$this->tax_query, and several later, unrelated-looking hook callbacks (theme-compat, count filters, tag-info display) depend on that having already run. Splitting this further would need a shared state object between classes rather than a mechanical extraction, so it stayed as one class.
  • class-frontend-tag-editor.php (LH_BP_Group_Taxonomies_Tag_Editor) — renders and saves the tag-selection checkboxes on group creation/edit. All-static, no shared state — called from both the front-end flow and Admin_Group_Metabox.
  • class-frontend-group-lifecycle.php (LH_BP_Group_Taxonomies_Group_Lifecycle) — visibility-change term-count fixup, cleanup on group deletion, single-group template hierarchy entry. No shared state with anything else.
  • class-taxonomy.php (LH_BP_Group_Taxonomies_Taxonomy) — unchanged, the data layer described below.

Groups directory filtering

Implemented via parse_select() / parse_total() in LH_BP_Group_Taxonomies_Frontend, hooked on BuddyPress’s own bp_groups_get_paged_groups_sql / bp_groups_get_total_groups_sql filters. parse_groups_query() (hooked on bp_before_has_groups_parse_args) collects every matching taxonomy present — either a directory URL segment or a $_GET param — into a WP_Tax_Query-shaped multi-clause array (AND relation across taxonomies). parse_select()/parse_total() then build a WP_Tax_Query from that array and inject its join and where SQL directly into BuddyPress’s group query (WP_Tax_Query::get_sql( 'g', 'id' )) — the same technique BuddyPress’s own native group_type filtering uses internally. Because $wpdb‘s term-table properties resolve to whichever site is current, this join correctly scopes to the current site’s own term tables even on a network-activated install where BuddyPress’s bp_groups table is centralised on the main site.

The first taxonomy/term matched is also kept on $this->taxonomy / $this->term for single-tag display contexts that only show one tag name — when multiple taxonomies are active at once, only the first is named in that display copy, though all are applied to the actual filtering.

An earlier PHP-side implementation (restrict_by_taxonomy(), using get_objects_in_term() + array_intersect() against $_GET) was removed in 1.0.1 in favour of the SQL-join approach above. Verified live on Princes Park Touch (site ID 2) that it correctly resolves to the site’s own term tables (e.g. lhero_2_term_relationships), not shared/network tables.

Reusable tax_query API

LH_BP_Group_Taxonomies_Taxonomy::get_group_ids_by_tax_query( array $tax_query ) returns matching group IDs for an arbitrary WP_Tax_Query-shaped argument — a single flat clause, or multiple clauses combined with a top-level relation key, exactly as WordPress core’s native tax_query argument works elsewhere (e.g. WP_Query). It runs standalone against BuddyPress’s own groups table via $wpdb, so it’s callable from any PHP code, not just the groups-directory-page context parse_select()/parse_total() are tied to.

// Multiple clauses, AND
$group_ids = LH_BP_Group_Taxonomies_Taxonomy::get_group_ids_by_tax_query( array(
    'relation' => 'AND',
    array( 'taxonomy' => 'lh_group_tags', 'terms' => 12, 'field' => 'term_id' ),
    array( 'taxonomy' => 'lh_comps_team_season', 'terms' => 'season-1', 'field' => 'slug' ),
) );

As of 1.1.0, lh-competitions‘s return_common_group_ids_by_term_id() and return_common_group_ids_by_term_slug() use this method internally instead of independently calling get_objects_in_term().

Forward-compatibility note: this array shape deliberately mirrors a generic tax_query argument BuddyPress core is adding to BP_Groups_Group::get() (landed on trunk June 2026, not yet in a stable release — confirmed absent from the BuddyPress 14.4.0 build installed on this network as of the 1.1.0 changelog entry). Once this network upgrades to a BuddyPress release that includes it, callers can switch to groups_get_groups( array( 'tax_query' => $tax_query ) ) directly, and this method (along with parse_select()/parse_total()) can likely be retired in favour of BuddyPress’s native support.

MCP abilities (removed in 2.0.0)

Up to 1.2.2 this plugin registered three read-only abilities: list-group-taxonomies, list-terms and get-groups-by-taxonomy. Their only consumer was LH Competitions’ team taxonomies, and because those taxonomies are registered by a site-activated plugin, the abilities could not be reached from another site’s connector. In 2.0.0 they moved to LH Competitions 1.101.0 as list-team-taxonomies, list-team-terms and get-teams, with the same output. A future companion plugin that needs group-taxonomy abilities should register them itself, using get_group_ids_by_tax_query() above.

Requirements

  • WordPress 6.9+ (declared via the plugin’s Requires at least header)
  • PHP 8.1+
  • BuddyPress 12.0+ with the Groups component active

If you like this plugin please consider making a donation to further development

Install LHero.org

lhero.org

Open it straight from your home screen, full screen and quicker to load.

  1. Tap the Share button . If you cannot see it, tap ••• first.
  2. Scroll down and tap Add to Home Screen.
  3. Tap Add.
  1. Tap the browser menu ⋮.
  2. Tap Install app or Add to Home screen.
  1. In the menu bar, choose File, then Add to Dock.

Use your browser's menu to install this site or add it to your home screen.