get( $ability_key, 'abilities', true, false ); } public static function allowed_post_statuses() { return array_map( 'sanitize_text_field', apply_filters( 'adcmdr_ability_list_ads_allowed_post_statuses', array( 'publish', 'draft' ) ) ); } private static function ability_category() { return 'ad-management'; } public function register_categories( $categories ) { wp_register_ability_category( self::ability_category(), array( 'label' => __( 'Ad Management', 'ad-commander' ), 'description' => __( 'Abilities for managing ads.', 'ad-commander' ), ) ); } public function register_abilities( $abilities ) { if ( $this->is_enabled( 'ability_get_ad_stats' ) ) { $this->register_ability_get_ad_stats(); } if ( $this->is_enabled( 'ability_list_ads' ) ) { $this->register_ability_list_ads(); $this->register_ability_get_ad(); } } private function register_ability_get_ad_stats() { wp_register_ability( 'ad-commander/get-ad-stats', array( 'label' => __( 'Get Ad Statistics', 'ad-commander' ), 'description' => __( 'Retrieves impression and click statistics for a specific ad or all ads within a date range.', 'ad-commander' ), 'category' => self::ability_category(), 'input_schema' => array( 'type' => 'object', 'properties' => array( 'period' => array( 'type' => 'string', 'enum' => array_keys( AdminReports::allowed_periods() ), 'description' => __( 'The time period for which to retrieve statistics. Defaults to past_7_days. Use custom to specify a custom date range.', 'ad-commander' ), ), 'group_by' => array( 'type' => 'string', 'enum' => array_keys( AdminReports::allowed_group_by() ), 'description' => __( 'How to group the statistics by time period. Defaults to day.', 'ad-commander' ), ), 'start_date' => array( 'type' => 'string', 'description' => __( 'Start date in Y-m-d format. Required when period is custom.', 'ad-commander' ), ), 'end_date' => array( 'type' => 'string', 'description' => __( 'End date in Y-m-d format. Required when period is custom.', 'ad-commander' ), ), 'filter_by_ad_ids' => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ), 'description' => __( 'Optional array of ad post IDs to filter results by.', 'ad-commander' ), ), ), ), 'output_schema' => array( 'type' => 'object', 'properties' => array( 'by_date' => array( 'type' => 'array', 'description' => __( 'Statistics grouped by date.', 'ad-commander' ), 'items' => array( 'type' => 'object', 'properties' => array( 'date' => array( 'type' => 'string', 'description' => __( 'Formatted date label for the item period.', 'ad-commander' ), ), 'date_alt' => array( 'type' => 'string', 'description' => __( 'Alternate shorter date label for the item period.', 'ad-commander' ), ), 'timestamp' => array( 'type' => 'integer', 'description' => __( 'Unix timestamp for the item period. If group_by is week or month, this represents the start of the period.', 'ad-commander' ), ), 'impressions' => array( 'type' => 'integer', 'description' => __( 'The number of impressions for all ads on this item period.', 'ad-commander' ), ), 'clicks' => array( 'type' => 'integer', 'description' => __( 'The number of clicks on all ads on this item period.', 'ad-commander' ), ), 'ctr' => array( 'type' => 'number', 'description' => __( 'Click-through rate as a percentage for all ads on this item period.', 'ad-commander' ), ), ), ), ), 'by_ad' => array( 'type' => 'array', 'description' => __( 'Statistics grouped by ad.', 'ad-commander' ), 'items' => array( 'type' => 'object', 'properties' => array( 'ad_id' => array( 'type' => 'integer', 'description' => __( 'The ad\'s post ID.', 'ad-commander' ), ), 'ad' => array( 'type' => 'string', 'description' => __( 'The ad title.', 'ad-commander' ), ), 'edit_link' => array( 'type' => 'string', 'description' => __( 'URL to edit the ad.', 'ad-commander' ), ), 'impressions' => array( 'type' => 'integer', 'description' => __( 'The number of impressions for the ad in the chosen time period.', 'ad-commander' ), ), 'clicks' => array( 'type' => 'integer', 'description' => __( 'The number of clicks on the ad in the chosen time period.', 'ad-commander' ), ), 'ctr' => array( 'type' => 'number', 'description' => __( 'Click-through rate as a percentage for the ad during the chosen time period.', 'ad-commander' ), ), ), ), ), 'by_group' => array( 'type' => 'array', 'description' => __( 'Statistics grouped by ad group. Includes ads currently in groups, even if they are in the trash or draft mode. Ads removed from a group are not counted. If an ad is in multiple groups, its stats will be included in each group, regardless of where the ad displayed.', 'ad-commander' ), 'items' => array( 'type' => 'object', 'properties' => array( 'group_id' => array( 'type' => 'integer', 'description' => __( 'The group\'s term ID.', 'ad-commander' ), ), 'group' => array( 'type' => 'string', 'description' => __( 'The group name.', 'ad-commander' ), ), 'impressions' => array( 'type' => 'integer', 'description' => __( 'The number of impressions for all ads in the group during the chosen time period.', 'ad-commander' ), ), 'clicks' => array( 'type' => 'integer', 'description' => __( 'The number of clicks on all ads in the group during the chosen time period.', 'ad-commander' ), ), 'ctr' => array( 'type' => 'number', 'description' => __( 'Click-through rate as a percentage for the group during the chosen time period.', 'ad-commander' ), ), ), ), ), 'by_campaign' => array( 'type' => 'array', 'description' => __( 'Statistics grouped by campaign. Includes ads currently in campaigns, even if they are in the trash or draft mode. Ads removed from a campaign are not counted. If an ad is in multiple campaigns, its stats will be included in each campaign, regardless of where the ad displayed.', 'ad-commander' ), 'items' => array( 'type' => 'object', 'properties' => array( 'campaign_id' => array( 'type' => 'integer', 'description' => __( 'The campaign\'s term ID.', 'ad-commander' ), ), 'campaign' => array( 'type' => 'string', 'description' => __( 'The campaign name.', 'ad-commander' ), ), 'impressions' => array( 'type' => 'integer', 'description' => __( 'The number of impressions for all ads in the campaign during the chosen time period.', 'ad-commander' ), ), 'clicks' => array( 'type' => 'integer', 'description' => __( 'The number of clicks on all ads in the campaign during the chosen time period.', 'ad-commander' ), ), 'ctr' => array( 'type' => 'number', 'description' => __( 'Click-through rate as a percentage for the campaign during the chosen time period.', 'ad-commander' ), ), ), ), ), 'by_advertiser' => array( 'type' => 'array', 'description' => __( 'Statistics grouped by advertiser. Includes ads currently assigned to advertisers, even if they are in the trash or draft mode. Ads removed from an advertiser are not counted. If an ad is assigned to multiple advertisers, its stats will be included in each advertiser, regardless of where the ad displayed.', 'ad-commander' ), 'items' => array( 'type' => 'object', 'properties' => array( 'advertiser_id' => array( 'type' => 'integer', 'description' => __( 'The advertiser\'s term ID.', 'ad-commander' ), ), 'advertiser' => array( 'type' => 'string', 'description' => __( 'The advertiser name.', 'ad-commander' ), ), 'impressions' => array( 'type' => 'integer', 'description' => __( 'The number of impressions for all ads assigned to the advertiser during the chosen time period.', 'ad-commander' ), ), 'clicks' => array( 'type' => 'integer', 'description' => __( 'The number of clicks on all ads assigned to the advertiser during the chosen time period.', 'ad-commander' ), ), 'ctr' => array( 'type' => 'number', 'description' => __( 'Click-through rate as a percentage for the advertiser during the chosen time period.', 'ad-commander' ), ), ), ), ), ), ), 'execute_callback' => 'adcmdr_ability_get_ad_stats', 'permission_callback' => function () { return current_user_can( AdCommander::capability() ); }, 'meta' => array( 'show_in_rest' => true, 'mcp' => array( 'public' => true, 'type' => 'tool', ), 'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true, ), ), ) ); } private static function shared_list_ad_input_schema() { return array( 'post_statuses' => array( 'type' => 'array', 'items' => array( 'type' => 'string', 'enum' => self::allowed_post_statuses(), ), 'description' => __( 'Optional array of post statuses to filter by. Defaults to both.', 'ad-commander' ), ), 'detailed' => array( 'type' => 'boolean', 'description' => __( 'Whether to include detailed information about each ad, including but not limited to the ad type, expiration options, and more. Does not include ad statistics. Defaults to false.', 'ad-commander' ), ), 'include_groups' => array( 'type' => 'boolean', 'description' => __( 'Whether to include the ad groups that each ad belongs to in the output. Defaults to false.', 'ad-commander' ), ), 'include_campaigns' => array( 'type' => 'boolean', 'description' => __( 'Whether to include the campaigns that each ad belongs to in the output. Defaults to false.', 'ad-commander' ), ), 'include_advertisers' => array( 'type' => 'boolean', 'description' => __( 'Whether to include the advertisers that each ad is assigned to in the output. Defaults to false.', 'ad-commander' ), ), ); } private static function shared_list_ad_output_schema() { return apply_filters( 'adcmdr_ability_list_ads_output_properties', array( 'ad_id' => array( 'type' => 'integer', 'description' => __( 'The ad\'s post ID.', 'ad-commander' ), ), 'ad_title' => array( 'type' => 'string', 'description' => __( 'The ad title.', 'ad-commander' ), ), 'ad_status' => array( 'type' => 'string', 'description' => __( 'The ad\'s post status.', 'ad-commander' ), ), 'ad_type' => array( 'type' => 'string', 'description' => __( 'The ad type, which will indicate whether this is an Image/Banner ad, AdSense ad, Text or Code (ad network) ad, or Rich Content ad. Only included when detailed is true.', 'ad-commander' ), ), 'banner_image_url' => array( 'type' => 'string', 'description' => __( 'The URL of the banner image for this ad. Only included when ad_type is "bannerad" and when detailed is true.', 'ad-commander' ), ), 'banner_image_width' => array( 'type' => 'integer', 'description' => __( 'The width of the banner image for this ad in pixels. Only included when ad_type is "bannerad" and when detailed is true.', 'ad-commander' ), ), 'banner_image_height' => array( 'type' => 'integer', 'description' => __( 'The height of the banner image for this ad in pixels. Only included when ad_type is "bannerad" and when detailed is true.', 'ad-commander' ), ), 'banner_linked_url' => array( 'type' => 'string', 'description' => __( 'The URL that the banner image for this ad links to when clicked. Only included when ad_type is "bannerad" and when detailed is true.', 'ad-commander' ), ), 'adsense_ad_mode' => array( 'type' => 'string', 'description' => __( 'The ad mode for this ad if it is an AdSense ad. This could be manual, direct, or ad_code. Manual ads are built with fields, Direct ads are selected through the AdSense API, and ad_code ads use custom ad code. Only included when ad_type is "adsense" and when detailed is true.', 'ad-commander' ), ), ) ); } private static function shared_list_ad_meta() { return array( 'show_in_rest' => true, 'mcp' => array( 'public' => true, 'type' => 'tool', ), 'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true, ), ); } private function register_ability_list_ads() { wp_register_ability( 'ad-commander/list-ads', array( 'label' => __( 'List Ads', 'ad-commander' ), 'description' => __( 'Retrieves a list of ads with basic information to help identify them. Only ads with publish or draft status are returned.', 'ad-commander' ), 'category' => self::ability_category(), 'input_schema' => array( 'type' => 'object', 'properties' => array_merge( array( 'ad_ids' => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ), 'description' => __( 'Optional array of ad post IDs to retrieve. If not specified, all ads are returned.', 'ad-commander' ), ), ), self::shared_list_ad_input_schema(), ), ), 'output_schema' => array( 'type' => 'array', 'description' => __( 'A list of ads.', 'ad-commander' ), 'items' => array( 'type' => 'object', 'properties' => self::shared_list_ad_output_schema(), ), ), 'execute_callback' => 'adcmdr_ability_list_ads', 'permission_callback' => function () { return current_user_can( AdCommander::capability() ); }, 'meta' => self::shared_list_ad_meta(), ) ); } private function register_ability_get_ad() { wp_register_ability( 'ad-commander/get-ad', array( 'label' => __( 'Get Ad', 'ad-commander' ), 'description' => __( 'Retrieves detailed information about a specific ad.', 'ad-commander' ), 'category' => self::ability_category(), 'input_schema' => array( 'type' => 'object', 'properties' => array_merge( array( 'ad_id' => array( 'type' => 'integer', 'description' => __( 'The ID of the ad to retrieve.', 'ad-commander' ), ), ), self::shared_list_ad_input_schema() ), ), 'output_schema' => array( 'type' => 'object', 'description' => __( 'Detailed information about the ad.', 'ad-commander' ), 'properties' => self::shared_list_ad_output_schema(), ), 'execute_callback' => 'adcmdr_ability_list_ads', 'permission_callback' => function () { return current_user_can( AdCommander::capability() ); }, 'meta' => self::shared_list_ad_meta(), ) ); } }