Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
92.50% |
37 / 40 |
|
33.33% |
1 / 3 |
CRAP | n/a |
0 / 0 |
|
| Automattic\Jetpack\Jetpack_Mu_Wpcom\Jetpack_AI_Hub\configure | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
| Automattic\Jetpack\Jetpack_Mu_Wpcom\Jetpack_AI_Hub\get_plan_info | |
88.24% |
15 / 17 |
|
0.00% |
0 / 1 |
6.06 | |||
| Automattic\Jetpack\Jetpack_Mu_Wpcom\Jetpack_AI_Hub\register | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
5.02 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * WordPress.com Simple integration for the Jetpack AI Hub. |
| 4 | * |
| 5 | * @package automattic/jetpack-mu-wpcom |
| 6 | */ |
| 7 | |
| 8 | namespace Automattic\Jetpack\Jetpack_Mu_Wpcom\Jetpack_AI_Hub; |
| 9 | |
| 10 | use Automattic\Jetpack\Jetpack_Mu_Wpcom\Expiry_Notices\Expiry_Data; |
| 11 | |
| 12 | /** |
| 13 | * Point the upstream Hub at WordPress.com's native site-scoped MCP API and |
| 14 | * supply the Simple answers for the host-specific configuration. |
| 15 | * |
| 16 | * @param array $config Upstream AI Hub host configuration. |
| 17 | * @return array WordPress.com Simple configuration. |
| 18 | */ |
| 19 | function configure( $config ) { |
| 20 | $blog_id = get_current_blog_id(); |
| 21 | |
| 22 | // On Simple the jetpack_mu_wpcom_load_jetpack_ai_hub filter is the gate: |
| 23 | // when the Hub is deliberately loaded here, every view shows. No second |
| 24 | // predicate — turning Simple on stays exactly one filter flip. |
| 25 | $config['showGatedViews'] = true; |
| 26 | // Host-opened, not internal-gated: no "A12s only" badge on the tabs. |
| 27 | $config['gatedViewsBadge'] = false; |
| 28 | // Simple users are WordPress.com users by construction, so the usage |
| 29 | // endpoint can always proxy as the current user. |
| 30 | $config['isUserConnected'] = true; |
| 31 | // The Overview plan card — get_plan_info() says why Simple answers it. |
| 32 | $config['planInfo'] = get_plan_info(); |
| 33 | $config['mcpSettingsApi'] = array( |
| 34 | 'path' => '/wpcom/v2/sites/' . $blog_id . '/mcp-abilities', |
| 35 | 'format' => 'wpcom', |
| 36 | ); |
| 37 | |
| 38 | return $config; |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Name, renewal date, and auto-renew state of the site's WordPress.com plan, |
| 43 | * for the Hub's Overview plan card. |
| 44 | * |
| 45 | * Answered from the WordPress.com store — the site's plan purchase, named |
| 46 | * via the product list — because My Jetpack's purchase lookup signs a |
| 47 | * blog-token request Simple sites cannot make. All-or-nothing like upstream: |
| 48 | * a plan that cannot be named reports the empty shape. |
| 49 | * |
| 50 | * @return array{name: string, renews_on: string, auto_renew: bool} |
| 51 | */ |
| 52 | function get_plan_info() { |
| 53 | $info = array( |
| 54 | 'name' => '', |
| 55 | 'renews_on' => '', |
| 56 | 'auto_renew' => true, |
| 57 | ); |
| 58 | |
| 59 | if ( ! function_exists( 'wpcom_get_site_purchases' ) || ! class_exists( '\Store_Product_List' ) ) { |
| 60 | return $info; |
| 61 | } |
| 62 | |
| 63 | // The store returns active subscriptions only; the expiry-notices picker |
| 64 | // selects the latest-expiring plan row if several are active at once. |
| 65 | $plan = Expiry_Data::pick_primary_plan_purchase( wpcom_get_site_purchases() ); |
| 66 | if ( ! is_object( $plan ) ) { |
| 67 | return $info; |
| 68 | } |
| 69 | |
| 70 | $name = \Store_Product_List::get_from_cache()[ (int) ( $plan->product_id ?? 0 ) ]['product_name'] ?? ''; |
| 71 | if ( ! is_string( $name ) || '' === $name ) { |
| 72 | return $info; |
| 73 | } |
| 74 | |
| 75 | // Raw store name; the Hub page trims the brand prefixes in one place. |
| 76 | $info['name'] = $name; |
| 77 | // Always an ISO8601 string: the store normalizer rewrites empty and |
| 78 | // '0000-00-00' (never-expiring) expiries before they reach purchases. |
| 79 | $info['renews_on'] = (string) ( $plan->expiry_date ?? '' ); |
| 80 | // Absent means unknown, not off — and Simple store rows historically carry |
| 81 | // the flag as user_allows_auto_renew, with auto_renew as its alias. |
| 82 | $info['auto_renew'] = (bool) ( $plan->user_allows_auto_renew ?? $plan->auto_renew ?? true ); |
| 83 | |
| 84 | return $info; |
| 85 | } |
| 86 | |
| 87 | // Scheduled tasks are a WordPress.com-backed experience and should be visible |
| 88 | // whenever the AI Hub integration is loaded on Simple sites. |
| 89 | add_filter( 'jetpack_feature_flag_enabled_ai-hub-scheduled-tasks', '__return_true' ); |
| 90 | |
| 91 | /** |
| 92 | * Register the upstream AI Hub page on WordPress.com Simple. |
| 93 | */ |
| 94 | function register() { |
| 95 | if ( ! defined( 'JETPACK__PLUGIN_DIR' ) ) { |
| 96 | return; |
| 97 | } |
| 98 | |
| 99 | $page_path = JETPACK__PLUGIN_DIR . '_inc/lib/admin-pages/class-jetpack-ai-page.php'; |
| 100 | if ( ! file_exists( $page_path ) ) { |
| 101 | return; |
| 102 | } |
| 103 | |
| 104 | require_once $page_path; |
| 105 | // @phan-suppress-next-line PhanUndeclaredClassReference -- loaded from the sibling Jetpack plugin above and guarded at runtime. |
| 106 | if ( ! class_exists( '\Jetpack_AI_Page' ) || ! method_exists( '\Jetpack_AI_Page', 'add_actions' ) ) { |
| 107 | return; |
| 108 | } |
| 109 | |
| 110 | add_filter( 'jetpack_ai_admin_config', __NAMESPACE__ . '\\configure' ); |
| 111 | |
| 112 | // @phan-suppress-next-line PhanUndeclaredClassMethod -- loaded from the sibling Jetpack plugin above and guarded at runtime. |
| 113 | $page = new \Jetpack_AI_Page(); |
| 114 | // @phan-suppress-next-line PhanUndeclaredClassInCallable -- loaded from the sibling Jetpack plugin above and guarded at runtime. |
| 115 | add_action( 'admin_menu', array( $page, 'add_actions' ), 998 ); |
| 116 | } |
| 117 | |
| 118 | register(); |