Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
32.80% covered (danger)
32.80%
82 / 250
34.38% covered (danger)
34.38%
11 / 32
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Ai
32.66% covered (danger)
32.66%
81 / 248
34.38% covered (danger)
34.38%
11 / 32
2344.35
0.00% covered (danger)
0.00%
0 / 1
 get_plugin_slug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_plugin_filename
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_title
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_tiers
33.33% covered (danger)
33.33%
2 / 6
0.00% covered (danger)
0.00%
0 / 1
3.19
 get_features_by_tier
3.39% covered (danger)
3.39%
2 / 59
0.00% covered (danger)
0.00%
0 / 1
18.43
 get_current_usage_tier
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
 get_next_usage_tier
28.57% covered (danger)
28.57%
2 / 7
0.00% covered (danger)
0.00%
0 / 1
14.11
 get_description
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_long_description_by_usage_tier
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
4.59
 get_long_description
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 get_features_by_usage_tier
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
6
 get_features
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 get_pricing_for_ui_by_usage_tier
15.38% covered (danger)
15.38%
4 / 26
0.00% covered (danger)
0.00%
0 / 1
58.07
 get_pricing_for_ui
22.22% covered (danger)
22.22%
8 / 36
0.00% covered (danger)
0.00%
0 / 1
11.53
 get_wpcom_product_slug
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_wpcom_monthly_product_slug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_wpcom_bi_yearly_product_slug
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_paid_plan_product_slugs
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 is_upgradable
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
12.03
 get_post_checkout_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_post_activation_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_manage_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_plugin_installed
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_plugin_active
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is_active
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 get_ai_assistant_feature
16.67% covered (danger)
16.67%
2 / 12
0.00% covered (danger)
0.00%
0 / 1
26.83
 are_tier_plans_enabled
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
4.59
 is_site_connected
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 extend_plugin_action_links
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 admin_enqueue_scripts
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 add_ai_block
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2/**
3 * AI product
4 *
5 * @package my-jetpack
6 */
7
8namespace Automattic\Jetpack\My_Jetpack\Products;
9
10use Automattic\Jetpack\Connection\Manager as Connection_Manager;
11use Automattic\Jetpack\My_Jetpack\Initializer;
12use Automattic\Jetpack\My_Jetpack\Product;
13use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
14use WP_Post;
15
16if ( ! defined( 'ABSPATH' ) ) {
17    exit( 0 );
18}
19
20/**
21 * Class responsible for handling the Jetpack AI product
22 */
23class Jetpack_Ai extends Product {
24
25    const CURRENT_TIER_SLUG  = 'free';
26    const UPGRADED_TIER_SLUG = 'upgraded';
27
28    /**
29     * The product slug
30     *
31     * @var string
32     */
33    public static $slug = 'jetpack-ai';
34
35    /**
36     * The category of the product
37     *
38     * @var string
39     */
40    public static $category = 'create';
41
42    /**
43     * Whether this product has a free offering
44     *
45     * @var bool
46     */
47    public static $has_free_offering = true;
48
49    /**
50     * The feature slug that identifies the paid plan
51     *
52     * @var string
53     */
54    public static $feature_identifying_paid_plan = 'ai-assistant';
55
56    /**
57     * Get the plugin slug - ovewrite it and return Jetpack's
58     *
59     * @return ?string
60     */
61    public static function get_plugin_slug() {
62        return self::JETPACK_PLUGIN_SLUG;
63    }
64
65    /**
66     * Get the plugin filename - ovewrite it and return Jetpack's
67     *
68     * @return ?string
69     */
70    public static function get_plugin_filename() {
71        return self::JETPACK_PLUGIN_FILENAME;
72    }
73
74    /**
75     * Get the product name
76     *
77     * @return string
78     */
79    public static function get_name() {
80        return 'AI';
81    }
82
83    /**
84     * Get the product title
85     *
86     * @return string
87     */
88    public static function get_title() {
89        return 'Jetpack AI';
90    }
91
92    /**
93     * Get the product's available tiers
94     *
95     * @return string[] Slugs of the available tiers
96     */
97    public static function get_tiers() {
98        if ( ! self::are_tier_plans_enabled() ) {
99            return parent::get_tiers();
100        }
101
102        return array(
103            self::UPGRADED_TIER_SLUG,
104            self::CURRENT_TIER_SLUG,
105        );
106    }
107
108    /**
109     * Get the internationalized comparison of free vs upgraded features
110     *
111     * @return array[] Protect features comparison
112     */
113    public static function get_features_by_tier() {
114        if ( ! self::are_tier_plans_enabled() ) {
115            return parent::get_features_by_tier();
116        }
117
118        $current_tier        = self::get_current_usage_tier();
119        $current_description = 0 === $current_tier
120            ? __( 'Up to 20 requests', 'jetpack-my-jetpack' )
121            /* translators: number of requests */
122            : sprintf( __( 'Up to %d requests per month', 'jetpack-my-jetpack' ), $current_tier );
123        $next_tier        = self::get_next_usage_tier();
124        $next_description = $next_tier === null
125            ? __( 'Let\'s get in touch', 'jetpack-my-jetpack' )
126            /* translators: number of requests */
127            : sprintf( __( 'Up to %d requests per month', 'jetpack-my-jetpack' ), $next_tier );
128
129        return array(
130            array(
131                'name'  => __( 'Number of requests', 'jetpack-my-jetpack' ),
132                'info'  => array(
133                    'title'   => __( 'Requests', 'jetpack-my-jetpack' ),
134                    'content' => __( 'Increase your monthly request limit. Upgrade now and have the option to further increase your requests with additional upgrades.', 'jetpack-my-jetpack' ),
135                ),
136                'tiers' => array(
137                    self::CURRENT_TIER_SLUG  => array(
138                        'included'    => true,
139                        'description' => $current_description,
140                    ),
141                    self::UPGRADED_TIER_SLUG => array(
142                        'included'    => true,
143                        'description' => $next_description,
144                    ),
145                ),
146            ),
147            array(
148                'name'  => __( 'Generate and edit content', 'jetpack-my-jetpack' ),
149                'tiers' => array(
150                    self::CURRENT_TIER_SLUG  => array( 'included' => true ),
151                    self::UPGRADED_TIER_SLUG => array( 'included' => true ),
152                ),
153            ),
154            array(
155                'name'  => __( 'Build forms from prompts', 'jetpack-my-jetpack' ),
156                'tiers' => array(
157                    self::CURRENT_TIER_SLUG  => array( 'included' => true ),
158                    self::UPGRADED_TIER_SLUG => array( 'included' => true ),
159                ),
160            ),
161            array(
162                'name'  => __( 'Get feedback on posts', 'jetpack-my-jetpack' ),
163                'tiers' => array(
164                    self::CURRENT_TIER_SLUG  => array( 'included' => true ),
165                    self::UPGRADED_TIER_SLUG => array( 'included' => true ),
166                ),
167            ),
168            array(
169                'name'  => __( 'Generate featured images', 'jetpack-my-jetpack' ),
170                'tiers' => array(
171                    self::CURRENT_TIER_SLUG  => array( 'included' => true ),
172                    self::UPGRADED_TIER_SLUG => array( 'included' => true ),
173                ),
174            ),
175        );
176    }
177
178    /**
179     * Get the current usage tier
180     *
181     * @return int
182     */
183    public static function get_current_usage_tier() {
184        if ( ! self::is_site_connected() ) {
185            return 0;
186        }
187
188        $info = self::get_ai_assistant_feature();
189
190        // Bail early if it's not possible to fetch the feature data.
191        if ( is_wp_error( $info ) ) {
192            return 0;
193        }
194
195        $current_tier = $info['current-tier']['value'] ?? null;
196
197        return $current_tier;
198    }
199
200    /**
201     * Get the next usage tier
202     *
203     * @return int
204     */
205    public static function get_next_usage_tier() {
206        if ( ! self::is_site_connected() || ! self::has_paid_plan_for_product() ) {
207            // without site connection we can't know if tiers are enabled or not,
208            // hence we can't know if the next tier is 100 or 1 (unlimited).
209            return 100;
210        }
211
212        $info = self::get_ai_assistant_feature();
213
214        // Bail early if it's not possible to fetch the feature data or if it's included in a plan.
215        if ( is_wp_error( $info ) || empty( $info ) ) {
216            return null;
217        }
218
219        // Trust the next tier provided by the feature data.
220        $next_tier = $info['next-tier']['value'] ?? null;
221
222        return $next_tier;
223    }
224
225    /**
226     * Get the internationalized product description
227     *
228     * @return string
229     */
230    public static function get_description() {
231        return __( 'Turn your ideas into ready‑to‑publish content at lightspeed.', 'jetpack-my-jetpack' );
232    }
233
234    /**
235     * Get the internationalized usage tier long description by tier
236     *
237     * @param int|null $tier The usage tier.
238     * @return string
239     */
240    public static function get_long_description_by_usage_tier( $tier ) {
241        switch ( (int) $tier ) {
242            case 1:
243                return __( 'Jetpack AI Assistant brings the power of AI right into your WordPress editor, letting your content creation soar to new heights.', 'jetpack-my-jetpack' );
244            case 100:
245                return __( 'The most advanced AI technology Jetpack has to offer.', 'jetpack-my-jetpack' );
246            default:
247                return __( 'Upgrade and increase the amount of your available monthly requests to continue using the most advanced AI technology Jetpack has to offer.', 'jetpack-my-jetpack' );
248        }
249    }
250
251    /**
252     * Get the internationalized product long description
253     *
254     * @return string
255     */
256    public static function get_long_description() {
257        $next_tier = self::get_next_usage_tier();
258
259        return self::get_long_description_by_usage_tier( $next_tier );
260    }
261
262    /**
263     * Get the internationalized usage tier features by tier
264     *
265     * @param int $tier The usage tier.
266     * @return string
267     */
268    public static function get_features_by_usage_tier( $tier ) {
269        $is_tier_plan = $tier && intval( $tier ) > 1;
270
271        if ( $tier === 100 && ( ! self::is_site_connected() || ! self::has_paid_plan_for_product() ) ) {
272            // in these cases, get_next_usage_tier() will return 100
273            // 100 is fine as default when tiered plans are enabled, but not otherwise
274            $is_tier_plan = false;
275        }
276
277        $features = array(
278            __( 'High request capacity *', 'jetpack-my-jetpack' ),
279            __( 'Generate text, tables, lists, and forms', 'jetpack-my-jetpack' ),
280            __( 'Easily refine content to your liking', 'jetpack-my-jetpack' ),
281            __( 'Make your content easier to read', 'jetpack-my-jetpack' ),
282            __( 'Generate images with one-click', 'jetpack-my-jetpack' ),
283            __( 'Optimize your titles for better performance', 'jetpack-my-jetpack' ),
284            __( 'Priority support', 'jetpack-my-jetpack' ),
285        );
286
287        $tiered_features = array(
288            __( 'Prompt based content generation', 'jetpack-my-jetpack' ),
289            __( 'Generate text, tables, and lists', 'jetpack-my-jetpack' ),
290            __( 'Adaptive tone adjustment', 'jetpack-my-jetpack' ),
291            __( 'Superior spelling and grammar correction', 'jetpack-my-jetpack' ),
292            __( 'Title & summary generation', 'jetpack-my-jetpack' ),
293            __( 'Priority support', 'jetpack-my-jetpack' ),
294            /* translators: %d is the number of requests. */
295            sprintf( __( 'Up to %d requests per month', 'jetpack-my-jetpack' ), $tier ),
296        );
297
298        return $is_tier_plan ? $tiered_features : $features;
299    }
300
301    /**
302     * Get the internationalized features list
303     *
304     * @return array Jetpack AI features list
305     */
306    public static function get_features() {
307        $next_tier = self::get_next_usage_tier();
308
309        return self::get_features_by_usage_tier( $next_tier );
310    }
311
312    /**
313     * Get the product pricing details by tier
314     *
315     * @param int|null $tier The usage tier.
316     * @return array Pricing details
317     */
318    public static function get_pricing_for_ui_by_usage_tier( $tier ) {
319        if ( $tier === null ) {
320            return array();
321        }
322
323        $product = Wpcom_Products::get_product( static::get_wpcom_product_slug() );
324
325        if ( empty( $product ) ) {
326            return array();
327        }
328
329        $tier_plans_enabled = self::are_tier_plans_enabled();
330
331        /*
332         * when tiers are enabled and the price tier list is empty,
333         * we may need to renew the cache for the product data so
334         * we get the new price tier list.
335         *
336         * if the list is still empty after the fresh data, we will
337         * default to empty pricing (by returning an empty array).
338         */
339        if ( empty( $product->price_tier_list ) && $tier_plans_enabled ) {
340            $product = Wpcom_Products::get_product( static::get_wpcom_product_slug(), true );
341        }
342
343        // get the base pricing for the unlimited plan, for compatibility
344        $base_pricing = Wpcom_Products::get_product_pricing( static::get_wpcom_product_slug() );
345
346        $price_tier_list = $product->price_tier_list;
347        $yearly_prices   = array();
348
349        foreach ( $price_tier_list as $price_tier ) {
350            if ( isset( $price_tier->maximum_units ) && isset( $price_tier->maximum_price ) ) {
351                    // The prices are in cents
352                    $yearly_prices[ $price_tier->maximum_units ] = $price_tier->maximum_price / 100;
353            }
354        }
355
356        // add the base pricing to the list
357        $prices = array( 1 => $base_pricing );
358
359        foreach ( $yearly_prices as $units => $price ) {
360            $prices[ $units ] = array_merge(
361                $base_pricing,
362                array(
363                    'full_price'            => $price,
364                    'discount_price'        => $price,
365                    'is_introductory_offer' => false,
366                    'introductory_offer'    => null,
367                )
368            );
369        }
370
371        return $prices[ $tier ] ?? array();
372    }
373
374    /**
375     * Get the product pricing details
376     *
377     * @return array Pricing details
378     */
379    public static function get_pricing_for_ui() {
380        // no tiers
381        if ( ! self::are_tier_plans_enabled() ) {
382            return array_merge(
383                array(
384                    'available'          => true,
385                    'wpcom_product_slug' => static::get_wpcom_product_slug(),
386                ),
387                // hardcoding 1 as next tier if tiers are not enabled
388                self::get_pricing_for_ui_by_usage_tier( 1 )
389            );
390        }
391
392        $next_tier              = self::get_next_usage_tier();
393        $current_tier           = self::get_current_usage_tier();
394        $current_call_to_action = $current_tier === 0
395            ? __( 'Continue for free', 'jetpack-my-jetpack' )
396            : __( 'I\'m fine with my plan, thanks', 'jetpack-my-jetpack' );
397        $next_call_to_action    = $next_tier === null
398            ? __( 'Contact Us', 'jetpack-my-jetpack' )
399            : __( 'Upgrade', 'jetpack-my-jetpack' );
400
401        return array(
402            'tiers' => array(
403                self::CURRENT_TIER_SLUG  => array_merge(
404                    self::get_pricing_for_ui_by_usage_tier( $current_tier ),
405                    array(
406                        'available'      => true,
407                        'is_free'        => true,
408                        'call_to_action' => $current_call_to_action,
409                    )
410                ),
411                self::UPGRADED_TIER_SLUG => array_merge(
412                    self::get_pricing_for_ui_by_usage_tier( $next_tier ),
413                    array(
414                        'wpcom_product_slug' => static::get_wpcom_product_slug(),
415                        'quantity'           => $next_tier,
416                        'call_to_action'     => $next_call_to_action,
417                    )
418                ),
419            ),
420        );
421    }
422
423    /**
424     * Get the WPCOM product slug used to make the purchase
425     *
426     * @return string
427     */
428    public static function get_wpcom_product_slug() {
429        return 'jetpack_ai_yearly';
430    }
431
432    /**
433     * Get the WPCOM monthly product slug used to make the purchase
434     *
435     * @return string
436     */
437    public static function get_wpcom_monthly_product_slug() {
438        return 'jetpack_ai_monthly';
439    }
440
441    /**
442     * Get the WPCOM bi-yearly product slug used to make the purchase
443     *
444     * @return string
445     */
446    public static function get_wpcom_bi_yearly_product_slug() {
447        return 'jetpack_ai_bi_yearly';
448    }
449
450    /**
451     * Get the product-slugs of the paid plans for this product.
452     * (Do not include bundle plans, unless it's a bundle plan itself).
453     *
454     * @return array
455     */
456    public static function get_paid_plan_product_slugs() {
457        return array(
458            'jetpack_ai_yearly',
459            'jetpack_ai_monthly',
460            'jetpack_ai_bi_yearly',
461        );
462    }
463
464    /**
465     * Checks whether the product can be upgraded to a different product.
466     *
467     * @return boolean
468     */
469    public static function is_upgradable() {
470        $has_ai_feature     = static::does_site_have_feature( 'ai-assistant' );
471        $tier_plans_enabled = self::are_tier_plans_enabled();
472        $current_tier       = self::get_current_usage_tier();
473
474        if ( $has_ai_feature && ! $tier_plans_enabled && $current_tier >= 1 ) {
475            return false;
476        }
477
478        $next_tier = self::get_next_usage_tier();
479
480        // The check below is debatable, not having the feature should not flag as not upgradable.
481        // If user is free (tier = 0), not unlimited (tier = 1) and has a next tier, then it's upgradable.
482        if ( $current_tier !== null && $current_tier !== 1 && $next_tier ) {
483            return true;
484        }
485
486        // Mark as not upgradable if user is on unlimited tier or does not have any plan.
487        if ( ! $has_ai_feature || null === $current_tier || 1 === $current_tier ) {
488            return false;
489        }
490
491        return true;
492    }
493
494    /**
495     * Get the URL the user is taken after purchasing the product through the checkout
496     *
497     * @return ?string
498     */
499    public static function get_post_checkout_url() {
500        return self::get_manage_url();
501    }
502
503    /**
504     * Get the URL the user is taken after activating the product through the checkout
505     *
506     * @return ?string
507     */
508    public static function get_post_activation_url() {
509        return self::get_manage_url();
510    }
511
512    /**
513     * Get the URL where the user manages the product
514     *
515     * @return ?string
516     */
517    public static function get_manage_url() {
518        return admin_url( 'admin.php?page=my-jetpack#/jetpack-ai' );
519    }
520
521    /**
522     * Checks whether the plugin is installed
523     *
524     * @return boolean
525     */
526    public static function is_plugin_installed() {
527        return self::is_jetpack_plugin_installed();
528    }
529
530    /**
531     * Checks whether the plugin is active
532     *
533     * @return boolean
534     */
535    public static function is_plugin_active() {
536        return (bool) static::is_jetpack_plugin_active();
537    }
538
539    /**
540     * Checks whether the Product is active
541     *
542     * Overrides the parent method to respect the jetpack_ai_enabled filter.
543     *
544     * @return boolean
545     */
546    public static function is_active() {
547        /**
548         * Filter to enable/disable Jetpack AI.
549         *
550         * @since 5.28.3
551         *
552         * @param boolean $enabled True if Jetpack AI should be enabled, false otherwise. Default true.
553         */
554        $is_enabled = apply_filters( 'jetpack_ai_enabled', true );
555
556        return $is_enabled && parent::is_active();
557    }
558
559    /**
560     * Get data about the AI Assistant feature
561     *
562     * @return array
563     */
564    public static function get_ai_assistant_feature() {
565        // Bail early if the plugin is not active.
566        if ( ! self::is_jetpack_plugin_installed() ) {
567            return array();
568        }
569
570        // Check if the global constant is defined.
571        if ( ! defined( 'JETPACK__PLUGIN_DIR' ) ) {
572            return array();
573        }
574
575        // Bail early if the site is not connected.
576        if ( ! self::is_site_connected() ) {
577            return array();
578        }
579
580        // Check if class exists. If not, try to require it once.
581        if ( ! class_exists( 'Jetpack_AI_Helper' ) ) {
582            $class_file_path = JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-ai-helper.php';
583
584            // Check whether the file exists
585            if ( ! file_exists( $class_file_path ) ) {
586                return array();
587            }
588
589            require_once $class_file_path;
590        }
591
592        return \Jetpack_AI_Helper::get_ai_assistance_feature();
593    }
594
595    /**
596     * Get the AI Assistant tiered plans status
597     *
598     * @return boolean
599     */
600    public static function are_tier_plans_enabled() {
601        $info = self::get_ai_assistant_feature();
602        if ( is_wp_error( $info ) ) {
603            // this is another faulty default value, we'll assume disabled while
604            // production is enabled
605            return false;
606        }
607
608        if ( ! empty( $info ) && isset( $info['tier-plans-enabled'] ) ) {
609            return boolval( $info['tier-plans-enabled'] );
610        }
611        return false;
612    }
613
614    /**
615     * Checks whether the site is connected to WordPress.com.
616     *
617     * @return boolean
618     */
619    private static function is_site_connected() {
620        return ( new Connection_Manager() )->is_connected();
621    }
622
623    /**
624     * Get the URL where the user manages the product
625     *
626     * NOTE: this method is the only thing that resembles an initialization for the product.
627     *
628     * @return void
629     */
630    public static function extend_plugin_action_links() {
631        add_action( 'myjetpack_enqueue_scripts', array( static::class, 'admin_enqueue_scripts' ) );
632        add_filter( 'default_content', array( static::class, 'add_ai_block' ), 10, 2 );
633    }
634
635    /**
636     * Enqueue the AI Assistant script
637     *
638     * The script is just a global variable used for the nonce, needed for the create post link.
639     *
640     * @return void
641     */
642    public static function admin_enqueue_scripts() {
643        wp_register_script(
644            'my_jetpack_ai_app',
645            false,
646            array(),
647            Initializer::PACKAGE_VERSION,
648            array( 'in_footer' => true )
649        );
650        wp_localize_script(
651            'my_jetpack_ai_app',
652            'jetpackAi',
653            array(
654                'nonce' => wp_create_nonce( 'ai-assistant-content-nonce' ),
655            )
656        );
657        wp_enqueue_script( 'my_jetpack_ai_app' );
658    }
659
660    /**
661     * Add AI block to the post content
662     *
663     * Used only from the link on the product page, the filter will insert an AI Assistant block in the post content.
664     *
665     * @param string  $content The post content.
666     * @param WP_Post $post The post object.
667     * @return string
668     */
669    public static function add_ai_block( $content, $post ) {
670        if ( isset( $_GET['use_ai_block'] ) && isset( $_GET['_wpnonce'] )
671            && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'ai-assistant-content-nonce' )
672            && ! empty( $post )
673            && ! is_wp_error( $post )
674            && current_user_can( 'edit_post', $post->ID )
675            && '' === $content
676        ) {
677            return '<!-- wp:jetpack/ai-assistant /-->';
678        }
679        return $content;
680    }
681}