Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.33% covered (warning)
83.33%
40 / 48
33.33% covered (danger)
33.33%
1 / 3
CRAP
n/a
0 / 0
Automattic\Jetpack\Extensions\AIChat\register_block
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
Automattic\Jetpack\Extensions\AIChat\load_assets
89.47% covered (warning)
89.47%
17 / 19
0.00% covered (danger)
0.00%
0 / 1
9.09
Automattic\Jetpack\Extensions\AIChat\add_ai_chat_block_data
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
2.00
1<?php
2/**
3 * Jetpack AI Chat.
4 *
5 * @since 12.1
6 *
7 * @package automattic/jetpack
8 */
9
10namespace Automattic\Jetpack\Extensions\AIChat;
11
12use Automattic\Jetpack\Blocks;
13use Automattic\Jetpack\Connection\Manager as Connection_Manager;
14use Automattic\Jetpack\Search\Module_Control as Search_Module_Control;
15use Automattic\Jetpack\Search\Plan as Search_Plan;
16use Automattic\Jetpack\Search\Search_Blocks;
17use Automattic\Jetpack\Status;
18use Automattic\Jetpack\Status\Host;
19use Jetpack_Gutenberg;
20
21if ( ! defined( 'ABSPATH' ) ) {
22    exit( 0 );
23}
24
25// Required directly rather than relying on the plugin bootstrap: on
26// WordPress.com Simple the extension files load through wpcom's own loader
27// and load-jetpack.php never runs. Without it the is_ai_enabled() master-gate
28// check below would fatal there.
29require_once __DIR__ . '/../../../_inc/lib/class-jetpack-ai-settings.php';
30
31/**
32 * Registers our block for use in Gutenberg
33 * This is done via an action so that we can disable
34 * registration if we need to.
35 */
36function register_block() {
37    if (
38        (
39            ( new Host() )->is_wpcom_simple()
40            || ( ( new Connection_Manager( 'jetpack' ) )->has_connected_owner() && ! ( new Status() )->is_offline_mode() )
41        )
42        && \Jetpack_AI_Settings::is_ai_enabled()
43    ) {
44        Blocks::jetpack_register_block(
45            __DIR__,
46            array( 'render_callback' => __NAMESPACE__ . '\load_assets' )
47        );
48    }
49}
50add_action( 'init', __NAMESPACE__ . '\register_block' );
51
52/**
53 * Jetpack AI Paragraph block registration/dependency declaration.
54 *
55 * @param array $attr Array containing the Jetpack AI Chat block attributes.
56 *
57 * @return string
58 */
59function load_assets( $attr ) {
60    /*
61     * Enqueue necessary scripts and styles.
62     */
63    Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
64
65    $ask_button_label = $attr['askButtonLabel'] ?? __( 'Ask', 'jetpack' );
66    $placeholder      = $attr['placeholder'] ?? __( 'Ask a question about this site.', 'jetpack' );
67
68    if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
69        $blog_id = get_current_blog_id();
70        $type    = 'wpcom'; // WPCOM simple sites.
71    } else {
72        $blog_id = \Jetpack_Options::get_option( 'id' );
73        $type    = 'jetpack'; // Self-hosted (includes Atomic)
74    }
75
76    return sprintf(
77        '<div class="%1$s" data-ask-button-label="%2$s" id="jetpack-ai-chat" data-blog-id="%3$d" data-blog-type="%4$s" data-placeholder="%5$s" data-show-copy="%6$d" data-show-feedback="%7$d" data-show-sources="%8$d"></div>',
78        esc_attr( Blocks::classes( Blocks::get_block_feature( __DIR__ ), $attr ) ),
79        esc_attr( $ask_button_label ),
80        esc_attr( $blog_id ),
81        esc_attr( $type ),
82        esc_attr( $placeholder ),
83        esc_attr( isset( $attr['showCopy'] ) ? ( $attr['showCopy'] ? 1 : 0 ) : 1 ),
84        esc_attr( isset( $attr['showFeedback'] ) ? ( $attr['showFeedback'] ? 1 : 0 ) : 1 ),
85        esc_attr( isset( $attr['showSources'] ) ? ( $attr['showSources'] ? 1 : 0 ) : 1 )
86    );
87}
88
89/**
90 * Add the initial state for the AI Chat block.
91 */
92function add_ai_chat_block_data() {
93    // Only relevant to the editor right now.
94    if ( ! is_admin() ) {
95        return;
96    }
97    $search        = new Search_Module_Control();
98    $plan          = new Search_Plan();
99    $initial_state = array(
100        'jetpackSettings' => array(
101            // `module_active` reflects whether the Jetpack Search module is on, which is
102            // what controls site indexing â€” independent of the chosen front-end experience
103            // (Overlay / Theme / Inline / Embedded). The AI Chat block only needs the
104            // index, so it gates on this rather than on `instant_search_enabled`.
105            'module_active'          => $search->is_active(),
106            'instant_search_enabled' => $search->is_instant_search_enabled(),
107            'plan_supports_search'   => $plan->supports_instant_search(),
108            'supports_paid_search'   => Search_Blocks::supports_paid_search(),
109        ),
110    );
111    wp_add_inline_script(
112        'jetpack-blocks-editor',
113        'var Jetpack_AIChatBlock = ' . wp_json_encode( $initial_state, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';',
114        'before'
115    );
116}
117add_action( 'enqueue_block_assets', __NAMESPACE__ . '\add_ai_chat_block_data', 11 );