Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions data-machine-events.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ function datamachine_get_event_timing( int $post_id ): string {
\WP_CLI::add_command( 'data-machine-events check clean-duplicates', \DataMachineEvents\Cli\Check\CleanDuplicatesCommand::class );
\WP_CLI::add_command( 'data-machine-events check merged-bills', \DataMachineEvents\Cli\Check\CheckMergedBillsCommand::class );
\WP_CLI::add_command( 'data-machine-events check merge-duplicate-venues', \DataMachineEvents\Cli\Check\CheckMergeDuplicateVenuesCommand::class );
\WP_CLI::add_command( 'data-machine-events check missing-venue-addresses', \DataMachineEvents\Cli\Check\CheckMissingVenueAddressesCommand::class );
\WP_CLI::add_command( 'data-machine-events check orphan-venues', \DataMachineEvents\Cli\Check\CheckOrphanVenuesCommand::class );
\WP_CLI::add_command( 'data-machine-events check quality', \DataMachineEvents\Cli\Check\CheckQualityCommand::class );
\WP_CLI::add_command( 'data-machine-events check all', \DataMachineEvents\Cli\Check\CheckAllCommand::class );
}
Expand Down Expand Up @@ -410,6 +412,11 @@ function ( array $templates ): array {
new \DataMachineEvents\Abilities\GeocodingAbilities();
}

if ( file_exists( DATA_MACHINE_EVENTS_PLUGIN_DIR . 'inc/Abilities/VenueStatsAbilities.php' ) ) {
require_once DATA_MACHINE_EVENTS_PLUGIN_DIR . 'inc/Abilities/VenueStatsAbilities.php';
new \DataMachineEvents\Abilities\VenueStatsAbilities();
}

if ( file_exists( DATA_MACHINE_EVENTS_PLUGIN_DIR . 'inc/Abilities/FilterAbilities.php' ) ) {
require_once DATA_MACHINE_EVENTS_PLUGIN_DIR . 'inc/Abilities/FilterAbilities.php';
new \DataMachineEvents\Abilities\FilterAbilities();
Expand Down
137 changes: 137 additions & 0 deletions inc/Abilities/VenueStatsAbilities.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php
/**
* Venue Stats Abilities
*
* Exposes a tiny `data-machine-events/venue-stats` ability that returns
* three counts: venue terms total, venue terms with empty
* `_venue_address`, and venue terms with `wp_term_taxonomy.count = 0`.
*
* Part C of issue #277. The weekly qualify-digest (extrachill-events#79)
* is the intended consumer — it will read this ability each Monday and
* surface the trend lines so we can spot regressions in the venue
* dedup pipeline.
*
* Kept deliberately small. This is a read-only stats surface; the
* actual repair work lives in the two `check` CLI commands. Wiring the
* digest itself is a follow-up in the extrachill-events repo so this
* PR can stay scoped to data-machine-events (no cross-plugin edits).
*
* @package DataMachineEvents\Abilities
* @since 0.38.0
*/

namespace DataMachineEvents\Abilities;

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

class VenueStatsAbilities {

private static bool $registered = false;

public function __construct() {
if ( ! self::$registered ) {
$this->registerAbilities();
self::$registered = true;
}
}

private function registerAbilities(): void {
$register_callback = function () {
wp_register_ability(
'data-machine-events/venue-stats',
array(
'label' => __( 'Venue Stats', 'data-machine-events' ),
'description' => __( 'Network-cheap counts for the venue audit digest: total venues, terms with no _venue_address, and orphan terms (wp_term_taxonomy.count = 0).', 'data-machine-events' ),
'category' => 'datamachine-events-venues',
'input_schema' => array(
'type' => 'object',
'properties' => new \stdClass(),
),
'output_schema' => array(
'type' => 'object',
'properties' => array(
'no_address' => array(
'type' => 'integer',
'description' => 'Count of venue terms whose _venue_address meta is empty or missing.',
),
'orphans' => array(
'type' => 'integer',
'description' => 'Count of venue terms whose wp_term_taxonomy.count = 0.',
),
'total' => array(
'type' => 'integer',
'description' => 'Total count of venue terms.',
),
'queried_at' => array(
'type' => 'integer',
'description' => 'Unix timestamp at which the stats were computed.',
),
),
),
'execute_callback' => array( $this, 'executeVenueStats' ),
'permission_callback' => function () {
return current_user_can( 'manage_options' )
|| ( defined( 'WP_CLI' ) && WP_CLI );
},
'meta' => array(
'show_in_rest' => true,
'annotations' => array(
'readonly' => true,
'idempotent' => true,
),
),
)
);
};

if ( did_action( 'wp_abilities_api_init' ) ) {
$register_callback();
} else {
add_action( 'wp_abilities_api_init', $register_callback );
}
}

/**
* Execute the venue-stats ability.
*
* Uses two cheap aggregate queries instead of pulling every term
* into PHP. The digest is expected to call this weekly across
* multiple sites, so we keep the cost bounded.
*
* @param array $input Unused — the ability takes no inputs.
* @return array{no_address:int,orphans:int,total:int,queried_at:int}
*/
public function executeVenueStats( array $input ): array {
global $wpdb;

$total = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM {$wpdb->term_taxonomy} WHERE taxonomy = 'venue'"
);

$orphans = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM {$wpdb->term_taxonomy}
WHERE taxonomy = 'venue' AND count = 0"
);

// no_address: venue terms whose `_venue_address` meta is NULL,
// missing, or an empty string. Left-join so terms with no row
// in termmeta at all are still counted.
$no_address = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM {$wpdb->term_taxonomy} tt
LEFT JOIN {$wpdb->termmeta} tm
ON tm.term_id = tt.term_id
AND tm.meta_key = '_venue_address'
WHERE tt.taxonomy = 'venue'
AND ( tm.meta_value IS NULL OR tm.meta_value = '' )"
);

return array(
'no_address' => $no_address,
'orphans' => $orphans,
'total' => $total,
'queried_at' => time(),
);
}
}
Loading
Loading