Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Initial_State
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 9
462
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 render
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_initial_state
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
12
 get_wp_api_root
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 current_user_data
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
12
 get_post_types_with_labels
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 get_purchase_token
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 generate_purchase_token
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 current_user_can_purchase
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * The React initial state.
4 *
5 * @package automattic/jetpack-search
6 */
7
8namespace Automattic\Jetpack\Search;
9
10use Automattic\Jetpack\Connection\Manager as Connection_Manager;
11use Automattic\Jetpack\Status;
12use Jetpack_Options;
13
14/**
15 * The React initial state.
16 */
17class Initial_State {
18
19    /**
20     * Connection Manager
21     *
22     * @var Connection_Manager
23     */
24    protected $connection_manager;
25
26    /**
27     * Search Module Control
28     *
29     * @var Module_Control
30     */
31    protected $module_control;
32
33    /**
34     * Constructor
35     *
36     * @param Connection_Manager $connection_manager - Connection mananger instance.
37     * @param Module_Control     $module_control - Module control instance.
38     */
39    public function __construct( $connection_manager = null, $module_control = null ) {
40        $this->connection_manager = $connection_manager ? $connection_manager : new Connection_Manager( Package::SLUG );
41        $this->module_control     = $module_control ? $module_control : new Module_Control();
42    }
43
44    /**
45     * Render JS for the initial state
46     *
47     * @return string - JS string.
48     */
49    public function render() {
50        return 'var JETPACK_SEARCH_DASHBOARD_INITIAL_STATE=' . wp_json_encode( $this->get_initial_state(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ';';
51    }
52
53    /**
54     * Get the initial state data.
55     *
56     * @return array
57     */
58    public function get_initial_state() {
59        return array(
60            'siteData'        => array(
61                'WP_API_root'        => esc_url_raw( rest_url() ),
62                'wpcomOriginApiUrl'  => $this->get_wp_api_root(),
63                'WP_API_nonce'       => wp_create_nonce( 'wp_rest' ),
64                'registrationNonce'  => wp_create_nonce( 'jetpack-registration-nonce' ),
65                'purchaseToken'      => $this->get_purchase_token(),
66                /**
67                 * Whether promotions are visible or not.
68                 *
69                 * @param bool $are_promotions_active Status of promotions visibility. True by default.
70                 */
71                'showPromotions'     => apply_filters( 'jetpack_show_promotions', true ),
72                'adminUrl'           => esc_url( admin_url() ),
73                'blogId'             => Jetpack_Options::get_option( 'id', 0 ),
74                'version'            => Package::VERSION,
75                'calypsoSlug'        => ( new Status() )->get_site_suffix(),
76                'title'              => get_bloginfo( 'name' ),
77                'postTypes'          => $this->get_post_types_with_labels(),
78                'isWpcom'            => Helper::is_wpcom(),
79                // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
80                'isPlanJustUpgraded' => isset( $_GET['just_upgraded'] ) && wp_unslash( $_GET['just_upgraded'] ),
81            ),
82            'userData'        => array(
83                'currentUser' => $this->current_user_data(),
84            ),
85            'jetpackSettings' => array(
86                'search'                 => $this->module_control->is_active(),
87                'instant_search_enabled' => $this->module_control->is_instant_search_enabled(),
88            ),
89            'features'        => array_map(
90                'sanitize_text_field',
91                // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
92                isset( $_GET['features'] ) ? explode( ',', wp_unslash( $_GET['features'] ) ) : array()
93            ),
94        );
95    }
96
97    /**
98     * Get API root.
99     *
100     * It return first party API root for WPCOM simple sites.
101     */
102    protected function get_wp_api_root() {
103        if ( ! Helper::is_wpcom() ) {
104            return esc_url_raw( rest_url() );
105        }
106        // First party API prefix for WPCOM.
107        return esc_url_raw( site_url( '/wp-json/wpcom-origin/' ) );
108    }
109
110    /**
111     * Gather data about the current user.
112     *
113     * @return array
114     */
115    protected function current_user_data() {
116        $current_user      = wp_get_current_user();
117        $is_user_connected = $this->connection_manager->is_user_connected( $current_user->ID );
118        $is_master_user    = $is_user_connected && (int) $current_user->ID && (int) Jetpack_Options::get_option( 'master_user' ) === (int) $current_user->ID;
119        $dotcom_data       = $this->connection_manager->get_connected_user_data();
120
121        $current_user_data = array(
122            'isConnected' => $is_user_connected,
123            'isMaster'    => $is_master_user,
124            'username'    => $current_user->user_login,
125            'id'          => $current_user->ID,
126            'wpcomUser'   => $dotcom_data,
127            'permissions' => array(
128                'manage_options' => current_user_can( 'manage_options' ),
129            ),
130        );
131
132        return $current_user_data;
133    }
134
135    /**
136     * Gets the post type labels for all of the site's post types (including custom post types)
137     *
138     * @return array
139     */
140    protected function get_post_types_with_labels() {
141
142        $args = array(
143            'public' => true,
144        );
145
146        $post_types_with_labels = array();
147
148        $post_types = get_post_types( $args, 'objects' );
149
150        // We don't need all the additional post_type data, just the slug & label
151        foreach ( $post_types as $post_type ) {
152            $post_type_with_label = array(
153                'slug'  => $post_type->name,
154                'label' => $post_type->label,
155            );
156
157            $post_types_with_labels[ $post_type->name ] = $post_type_with_label;
158        }
159        return $post_types_with_labels;
160    }
161
162    /**
163     * Gets a purchase token that is used for Jetpack logged out visitor checkout.
164     * The purchase token should be appended to all CTA url's that lead to checkout.
165     *
166     * @return string|boolean
167     */
168    protected function get_purchase_token() {
169        if ( ! $this->current_user_can_purchase() ) {
170            return false;
171        }
172
173        $purchase_token = Jetpack_Options::get_option( 'purchase_token', false );
174
175        if ( $purchase_token ) {
176            return $purchase_token;
177        }
178        // If the purchase token is not saved in the options table yet, then add it.
179        Jetpack_Options::update_option( 'purchase_token', $this->generate_purchase_token(), true );
180        return Jetpack_Options::get_option( 'purchase_token', false );
181    }
182
183    /**
184     * Generates a purchase token that is used for Jetpack logged out visitor checkout.
185     *
186     * @return string
187     */
188    protected function generate_purchase_token() {
189        return wp_generate_password( 12, false );
190    }
191
192    /**
193     * Determine if the current user is allowed to make Jetpack purchases without
194     * a WordPress.com account
195     *
196     * @return boolean True if the user can make purchases, false if not
197     */
198    public function current_user_can_purchase() {
199        // The site must be site-connected to Jetpack (no users connected).
200        if ( ! $this->connection_manager->is_site_connection() ) {
201            return false;
202        }
203
204        // Make sure only administrators can make purchases.
205        if ( ! current_user_can( 'manage_options' ) ) {
206            return false;
207        }
208
209        return true;
210    }
211}