Completed
Push — add/improve-histogram ( bde1c8...c8533f )
by
unknown
43:24 queued 36:14
created

get_dismissed_jetpack_notices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
include_once( 'class.jetpack-admin-page.php' );
3
4
// Builds the landing page and its menu
5
class Jetpack_React_Page extends Jetpack_Admin_Page {
6
7
	protected $dont_show_if_not_active = false;
8
9
	protected $is_redirecting = false;
10
11
	function get_page_hook() {
12
		// Add the main admin Jetpack menu
13
		return add_menu_page( 'Jetpack', 'Jetpack', 'jetpack_admin_page', 'jetpack', array( $this, 'render' ), 'div' );
14
	}
15
16
	function add_page_actions( $hook ) {
17
		/** This action is documented in class.jetpack.php */
18
		do_action( 'jetpack_admin_menu', $hook );
19
20
		// Place the Jetpack menu item on top and others in the order they appear
21
		add_filter( 'custom_menu_order',         '__return_true' );
22
		add_filter( 'menu_order',                array( $this, 'jetpack_menu_order' ) );
23
24
		if ( ! isset( $_GET['page'] ) || 'jetpack' !== $_GET['page'] ) {
25
			return; // No need to handle the fallback redirection if we are not on the Jetpack page
26
		}
27
28
		// Adding a redirect meta tag if the REST API is disabled
29
		if ( ! $this->is_rest_api_enabled() ) {
30
			$this->is_redirecting = true;
31
			add_action( 'admin_head', array( $this, 'add_fallback_head_meta' ) );
32
		}
33
34
		// Adding a redirect meta tag wrapped in noscript tags for all browsers in case they have JavaScript disabled
35
		add_action( 'admin_head', array( $this, 'add_noscript_head_meta' ) );
36
	}
37
38
	/**
39
	 * Add Jetpack Dashboard sub-link and point it to AAG if the user can view stats, manage modules or if Protect is active.
40
	 *
41
	 * Works in Dev Mode or when user is connected.
42
	 *
43
	 * @since 4.3.0
44
	 */
45
	function jetpack_add_dashboard_sub_nav_item() {
46 View Code Duplication
		if ( Jetpack::is_development_mode() || Jetpack::is_active() ) {
47
			global $submenu;
48
			if ( current_user_can( 'jetpack_admin_page' ) ) {
49
				$submenu['jetpack'][] = array( __( 'Dashboard', 'jetpack' ), 'jetpack_admin_page', 'admin.php?page=jetpack#/dashboard' );
50
			}
51
		}
52
	}
53
54
	/**
55
	 * If user is allowed to see the Jetpack Admin, add Settings sub-link.
56
	 *
57
	 * @since 4.3.0
58
	 */
59
	function jetpack_add_settings_sub_nav_item() {
60 View Code Duplication
		if ( ( Jetpack::is_development_mode() || Jetpack::is_active() ) && current_user_can( 'jetpack_admin_page' ) && current_user_can( 'edit_posts' ) ) {
61
			global $submenu;
62
			$submenu['jetpack'][] = array( __( 'Settings', 'jetpack' ), 'jetpack_admin_page', 'admin.php?page=jetpack#/settings' );
63
		}
64
	}
65
66
	function add_fallback_head_meta() {
67
		echo '<meta http-equiv="refresh" content="0; url=?page=jetpack_modules">';
68
	}
69
70
	function add_noscript_head_meta() {
71
		echo '<noscript>';
72
		$this->add_fallback_head_meta();
73
		echo '</noscript>';
74
	}
75
76 View Code Duplication
	function jetpack_menu_order( $menu_order ) {
77
		$jp_menu_order = array();
78
79
		foreach ( $menu_order as $index => $item ) {
80
			if ( $item != 'jetpack' )
81
				$jp_menu_order[] = $item;
82
83
			if ( $index == 0 )
84
				$jp_menu_order[] = 'jetpack';
85
		}
86
87
		return $jp_menu_order;
88
	}
89
90
	function page_render() {
91
		/** This action is already documented in views/admin/admin-page.php */
92
		do_action( 'jetpack_notices' );
93
94
		// Try fetching by patch
95
		$static_html = @file_get_contents( JETPACK__PLUGIN_DIR . '_inc/build/static.html' );
96
97
		if ( false === $static_html ) {
98
99
			// If we still have nothing, display an error
100
			echo '<p>';
101
			esc_html_e( 'Error fetching static.html. Try running: ', 'jetpack' );
102
			echo '<code>yarn distclean && yarn build</code>';
103
			echo '</p>';
104
		} else {
105
106
			// We got the static.html so let's display it
107
			echo $static_html;
108
		}
109
	}
110
111
	/**
112
	 * Gets array of any Jetpack notices that have been dismissed.
113
	 *
114
	 * @since 4.0.1
115
	 * @return mixed|void
116
	 */
117
	function get_dismissed_jetpack_notices() {
118
		$jetpack_dismissed_notices = get_option( 'jetpack_dismissed_notices', array() );
119
		/**
120
		 * Array of notices that have been dismissed.
121
		 *
122
		 * @since 4.0.1
123
		 *
124
		 * @param array $jetpack_dismissed_notices If empty, will not show any Jetpack notices.
125
		 */
126
		$dismissed_notices = apply_filters( 'jetpack_dismissed_notices', $jetpack_dismissed_notices );
127
		return $dismissed_notices;
128
	}
129
130
	function additional_styles() {
131
		Jetpack_Admin_Page::load_wrapper_styles();
132
	}
133
134
	function page_admin_scripts() {
135
		if ( $this->is_redirecting ) {
136
			return; // No need for scripts on a fallback page
137
		}
138
139
		$script_deps_path    = JETPACK__PLUGIN_DIR . '_inc/build/admin.deps.json';
140
		$script_dependencies = file_exists( $script_deps_path )
141
			? json_decode( file_get_contents( $script_deps_path ) )
142
			: array();
143
		$script_dependencies[] = 'wp-polyfill';
144
145
		wp_enqueue_script(
146
			'react-plugin',
147
			plugins_url( '_inc/build/admin.js', JETPACK__PLUGIN_FILE ),
148
			$script_dependencies,
149
			JETPACK__VERSION,
150
			true
151
		);
152
153
		if ( ! Jetpack::is_development_mode() && Jetpack::is_active() ) {
154
			// Required for Analytics.
155
			wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
156
		}
157
158
		// Add objects to be passed to the initial state of the app.
159
		wp_localize_script( 'react-plugin', 'Initial_State', $this->get_initial_state() );
160
	}
161
162
	function get_initial_state() {
163
		// Load API endpoint base classes and endpoints for getting the module list fed into the JS Admin Page
164
		require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php';
165
		require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php';
166
		$moduleListEndpoint = new Jetpack_Core_API_Module_List_Endpoint();
167
		$modules = $moduleListEndpoint->get_modules();
168
169
		// Preparing translated fields for JSON encoding by transforming all HTML entities to
170
		// respective characters.
171
		foreach( $modules as $slug => $data ) {
0 ignored issues
show
Bug introduced by
The expression $modules of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
172
			$modules[ $slug ]['name'] = html_entity_decode( $data['name'] );
173
			$modules[ $slug ]['description'] = html_entity_decode( $data['description'] );
174
			$modules[ $slug ]['short_description'] = html_entity_decode( $data['short_description'] );
175
			$modules[ $slug ]['long_description'] = html_entity_decode( $data['long_description'] );
176
		}
177
178
		// Collecting roles that can view site stats.
179
		$stats_roles = array();
180
		$enabled_roles = function_exists( 'stats_get_option' ) ? stats_get_option( 'roles' ) : array( 'administrator' );
181
182
		if ( ! function_exists( 'get_editable_roles' ) ) {
183
			require_once ABSPATH . 'wp-admin/includes/user.php';
184
		}
185
		foreach ( get_editable_roles() as $slug => $role ) {
186
			$stats_roles[ $slug ] = array(
187
				'name' => translate_user_role( $role['name'] ),
188
				'canView' => is_array( $enabled_roles ) ? in_array( $slug, $enabled_roles, true ) : false,
189
			);
190
		}
191
192
		// Get information about current theme.
193
		$current_theme = wp_get_theme();
194
195
		// Get all themes that Infinite Scroll provides support for natively.
196
		$inf_scr_support_themes = array();
197
		foreach ( Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules/infinite-scroll/themes' ) as $path ) {
198
			if ( is_readable( $path ) ) {
199
				$inf_scr_support_themes[] = basename( $path, '.php' );
200
			}
201
		}
202
203
		// Get last post, to build the link to Customizer in the Related Posts module.
204
		$last_post = get_posts( array( 'posts_per_page' => 1 ) );
205
		$last_post = isset( $last_post[0] ) && $last_post[0] instanceof WP_Post
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
206
			? get_permalink( $last_post[0]->ID )
207
			: get_home_url();
208
209
		// Ensure that class to get the affiliate code is loaded
210
		if ( ! class_exists( 'Jetpack_Affiliate' ) ) {
211
			require_once JETPACK__PLUGIN_DIR . 'class.jetpack-affiliate.php';
212
		}
213
214
		return array(
215
			'WP_API_root' => esc_url_raw( rest_url() ),
216
			'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
217
			'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ),
218
			'connectionStatus' => array(
219
				'isActive'  => Jetpack::is_active(),
220
				'isStaging' => Jetpack::is_staging_site(),
221
				'devMode'   => array(
222
					'isActive' => Jetpack::is_development_mode(),
223
					'constant' => defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG,
224
					'url'      => site_url() && false === strpos( site_url(), '.' ),
225
					'filter'   => apply_filters( 'jetpack_development_mode', false ),
226
				),
227
				'isPublic'	=> '1' == get_option( 'blog_public' ),
228
				'isInIdentityCrisis' => Jetpack::validate_sync_error_idc_option(),
229
				'sandboxDomain' => JETPACK__SANDBOX_DOMAIN,
230
			),
231
			'connectUrl' => Jetpack::init()->build_connect_url( true, false, false ),
232
			'dismissedNotices' => $this->get_dismissed_jetpack_notices(),
233
			'isDevVersion' => Jetpack::is_development_version(),
234
			'currentVersion' => JETPACK__VERSION,
235
			'is_gutenberg_available' => true,
236
			'getModules' => $modules,
237
			'showJumpstart' => jetpack_show_jumpstart(),
238
			'rawUrl' => Jetpack::build_raw_urls( get_home_url() ),
239
			'adminUrl' => esc_url( admin_url() ),
240
			'stats' => array(
241
				// data is populated asynchronously on page load
242
				'data'  => array(
243
					'general' => false,
244
					'day'     => false,
245
					'week'    => false,
246
					'month'   => false,
247
				),
248
				'roles' => $stats_roles,
249
			),
250
			'aff' => Jetpack_Affiliate::init()->get_affiliate_code(),
251
			'settings' => $this->get_flattened_settings( $modules ),
0 ignored issues
show
Bug introduced by
It seems like $modules defined by $moduleListEndpoint->get_modules() on line 167 can also be of type string; however, Jetpack_React_Page::get_flattened_settings() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
252
			'userData' => array(
253
//				'othersLinked' => Jetpack::get_other_linked_admins(),
254
				'currentUser'  => jetpack_current_user_data(),
255
			),
256
			'siteData' => array(
257
				'icon' => has_site_icon()
258
					? apply_filters( 'jetpack_photon_url', get_site_icon_url(), array( 'w' => 64 ) )
259
					: '',
260
				'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ),
261
				/**
262
				 * Whether promotions are visible or not.
263
				 *
264
				 * @since 4.8.0
265
				 *
266
				 * @param bool $are_promotions_active Status of promotions visibility. True by default.
267
				 */
268
				'showPromotions' => apply_filters( 'jetpack_show_promotions', true ),
269
				'isAtomicSite' => jetpack_is_atomic_site(),
270
				'plan' => Jetpack_Plan::get(),
271
				'showBackups' => Jetpack::show_backups_ui(),
272
			),
273
			'themeData' => array(
274
				'name'      => $current_theme->get( 'Name' ),
275
				'hasUpdate' => (bool) get_theme_update_available( $current_theme ),
276
				'support'   => array(
277
					'infinite-scroll' => current_theme_supports( 'infinite-scroll' ) || in_array( $current_theme->get_stylesheet(), $inf_scr_support_themes ),
278
				),
279
			),
280
			'locale' => Jetpack::get_i18n_data_json(),
281
			'localeSlug' => join( '-', explode( '_', get_user_locale() ) ),
282
			'jetpackStateNotices' => array(
283
				'messageCode' => Jetpack::state( 'message' ),
284
				'errorCode' => Jetpack::state( 'error' ),
285
				'errorDescription' => Jetpack::state( 'error_description' ),
286
			),
287
			'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
288
			'currentIp' => function_exists( 'jetpack_protect_get_ip' ) ? jetpack_protect_get_ip() : false,
289
			'lastPostUrl' => esc_url( $last_post ),
290
			'externalServicesConnectUrls' => $this->get_external_services_connect_urls()
291
		);
292
	}
293
294
	function get_external_services_connect_urls() {
295
		$connect_urls = array();
296
		jetpack_require_lib( 'class.jetpack-keyring-service-helper' );
297
		foreach ( Jetpack_Keyring_Service_Helper::$SERVICES as $service_name => $service_info ) {
298
			$connect_urls[ $service_name ] = Jetpack_Keyring_Service_Helper::connect_url( $service_name, $service_info[ 'for' ] );
299
		}
300
		return $connect_urls;
301
	}
302
303
	/**
304
	 * Returns an array of modules and settings both as first class members of the object.
305
	 *
306
	 * @param array $modules the result of an API request to get all modules.
307
	 *
308
	 * @return array flattened settings with modules.
309
	 */
310
	function get_flattened_settings( $modules ) {
311
		$core_api_endpoint = new Jetpack_Core_API_Data();
312
		$settings = $core_api_endpoint->get_all_options();
313
		return $settings->data;
314
	}
315
}
316
317
/*
318
 * Only show Jump Start on first activation.
319
 * Any option 'jumpstart' other than 'new connection' will hide it.
320
 *
321
 * The option can be of 4 things, and will be stored as such:
322
 * new_connection      : Brand new connection - Show
323
 * jumpstart_activated : Jump Start has been activated - dismiss
324
 * jumpstart_dismissed : Manual dismissal of Jump Start - dismiss
325
 * jetpack_action_taken: Deprecated since 7.3 But still listed here to respect behaviour for old versions.
326
 *                       Manual activation of a module already happened - dismiss.
327
 *
328
 * @todo move to functions.global.php when available
329
 * @since 3.6
330
 * @return bool | show or hide
331
 */
332
function jetpack_show_jumpstart() {
333
	if ( ! Jetpack::is_active() ) {
334
		return false;
335
	}
336
	$jumpstart_option = Jetpack_Options::get_option( 'jumpstart' );
337
338
	$hide_options = array(
339
		'jumpstart_activated',
340
		'jetpack_action_taken',
341
		'jumpstart_dismissed'
342
	);
343
344
	if ( ! $jumpstart_option || in_array( $jumpstart_option, $hide_options ) ) {
345
		return false;
346
	}
347
348
	return true;
349
}
350
351
/**
352
 * Gather data about the current user.
353
 *
354
 * @since 4.1.0
355
 *
356
 * @return array
357
 */
358
function jetpack_current_user_data() {
359
	$current_user = wp_get_current_user();
360
	$is_master_user = $current_user->ID == Jetpack_Options::get_option( 'master_user' );
361
	$dotcom_data    = Jetpack::get_connected_user_data();
362
	// Add connected user gravatar to the returned dotcom_data.
363
	$dotcom_data['avatar'] = get_avatar_url( $dotcom_data['email'], array( 'size' => 64, 'default' => 'mysteryman' ) );
364
365
	$current_user_data = array(
366
		'isConnected' => Jetpack::is_user_connected( $current_user->ID ),
367
		'isMaster'    => $is_master_user,
368
		'username'    => $current_user->user_login,
369
		'id'          => $current_user->ID,
370
		'wpcomUser'   => $dotcom_data,
371
		'gravatar'    => get_avatar( $current_user->ID, 40, 'mm', '', array( 'force_display' => true ) ),
372
		'permissions' => array(
373
			'admin_page'         => current_user_can( 'jetpack_admin_page' ),
374
			'connect'            => current_user_can( 'jetpack_connect' ),
375
			'disconnect'         => current_user_can( 'jetpack_disconnect' ),
376
			'manage_modules'     => current_user_can( 'jetpack_manage_modules' ),
377
			'network_admin'      => current_user_can( 'jetpack_network_admin_page' ),
378
			'network_sites_page' => current_user_can( 'jetpack_network_sites_page' ),
379
			'edit_posts'         => current_user_can( 'edit_posts' ),
380
			'publish_posts'      => current_user_can( 'publish_posts' ),
381
			'manage_options'     => current_user_can( 'manage_options' ),
382
			'view_stats'		 => current_user_can( 'view_stats' ),
383
			'manage_plugins'	 => current_user_can( 'install_plugins' )
384
									&& current_user_can( 'activate_plugins' )
385
									&& current_user_can( 'update_plugins' )
386
									&& current_user_can( 'delete_plugins' ),
387
		),
388
	);
389
390
	return $current_user_data;
391
}
392