Completed
Push — renovate/husky-2.x ( 960535...eacdcf )
by
unknown
07:05
created

modules/calypsoify/class.jetpack-calypsoify.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * This is Calypso skin of the wp-admin interface that is conditionally triggered via the ?calypsoify=1 param.
4
 * Ported from an internal Automattic plugin.
5
 */
6
class Jetpack_Calypsoify {
7
8
	/**
9
	 * Singleton instance of `Jetpack_Calypsoify`.
10
	 *
11
	 * @var object
12
	 */
13
	public static $instance = false;
14
15
	/**
16
	 * Is Calypsoify enabled, based on any value of `calypsoify` user meta.
17
	 *
18
	 * @var bool
19
	 */
20
	public $is_calypsoify_enabled = false;
21
22
	private function __construct() {
23
		add_action( 'wp_loaded', array( $this, 'setup' ) );
24
	}
25
26
	public static function getInstance() {
27
		if ( ! self::$instance ) {
28
			self::$instance = new self();
29
		}
30
31
		return self::$instance;
32
	}
33
34
	public function setup() {
35
		$this->is_calypsoify_enabled = 1 == (int) get_user_meta( get_current_user_id(), 'calypsoify', true );
36
		add_action( 'admin_init', array( $this, 'check_param' ), 4 );
37
38
		if ( $this->is_calypsoify_enabled ) {
39
			add_action( 'admin_init', array( $this, 'setup_admin' ), 6 );
40
		}
41
42
		// Make this always available -- in case calypsoify gets toggled off.
43
		add_action( 'wp_ajax_jetpack_toggle_autoupdate', array( $this, 'jetpack_toggle_autoupdate' ) );
44
		add_filter( 'handle_bulk_actions-plugins', array( $this, 'handle_bulk_actions_plugins' ), 10, 3 );
45
	}
46
47
	public function setup_admin() {
48
		// Masterbar is currently required for this to work properly. Mock the instance of it
49
		if ( ! Jetpack::is_module_active( 'masterbar' ) ) {
50
			$this->mock_masterbar_activation();
51
		}
52
53
		if ( $this->is_page_gutenberg() ) {
54
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_for_gutenberg' ), 100 );
55
			return;
56
		}
57
58
		add_action( 'admin_init', array( $this, 'check_page' ) );
59
		add_action( 'admin_menu', array( $this, 'remove_core_menus' ), 100 );
60
		add_action( 'admin_menu', array( $this, 'add_plugin_menus' ), 101 );
61
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ), 100 );
62
		add_action( 'in_admin_header', array( $this, 'insert_sidebar_html' ) );
63
		add_action( 'wp_before_admin_bar_render', array( $this, 'modify_masterbar' ), 100000 );
64
65
		add_filter( 'get_user_option_admin_color', array( $this, 'admin_color_override' ) );
66
67
		add_action( 'manage_plugins_columns', array( $this, 'manage_plugins_columns_header' ) );
68
		add_action( 'manage_plugins_custom_column', array( $this, 'manage_plugins_custom_column' ), 10, 2 );
69
		add_filter( 'bulk_actions-plugins', array( $this, 'bulk_actions_plugins' ) );
70
71
		if ( 'plugins.php' === basename( $_SERVER['PHP_SELF'] ) ) {
72
			add_action( 'admin_notices', array( $this, 'plugins_admin_notices' ) );
73
		}
74
	}
75
76
	public function manage_plugins_columns_header( $columns ) {
77
		if ( current_user_can( 'jetpack_manage_autoupdates' ) ) {
78
			$columns['autoupdate'] = __( 'Automatic Update', 'jetpack' );
79
		}
80
		return $columns;
81
	}
82
83
	public function manage_plugins_custom_column( $column_name, $slug ) {
84
		static $repo_plugins = array();
85
86
		if ( ! current_user_can( 'jetpack_manage_autoupdates' ) ) {
87
			return;
88
		}
89
90
		if ( empty( $repo_plugins ) ) {
91
			$repo_plugins = self::get_dotorg_repo_plugins();
92
		}
93
94
		$autoupdating_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
95
		// $autoupdating_plugins_translations = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
96
		if ( 'autoupdate' === $column_name ) {
97
			if ( ! in_array( $slug, $repo_plugins ) ) {
98
				return;
99
			}
100
			// Shamelessly swiped from https://github.com/Automattic/wp-calypso/blob/59bdfeeb97eda4266ad39410cb0a074d2c88dbc8/client/components/forms/form-toggle
101
			?>
102
103
			<span class="form-toggle__wrapper">
104
				<input
105
					id="autoupdate_plugin-toggle-<?php echo esc_attr( $slug ) ?>"
106
					name="autoupdate_plugins[<?php echo esc_attr( $slug ) ?>]"
107
					value="autoupdate"
108
					class="form-toggle autoupdate-toggle"
109
					type="checkbox"
110
					<?php checked( in_array( $slug, $autoupdating_plugins ) ); ?>
111
					readonly
112
					data-slug="<?php echo esc_attr( $slug ); ?>"
113
				/>
114
				<label class="form-toggle__label" for="autoupdate_plugin-toggle-<?php echo esc_attr( $slug ) ?>">
115
					<span class="form-toggle__switch" role="checkbox"></span>
116
					<span class="form-toggle__label-content"><?php /*  */ ?></span>
117
				</label>
118
			</span>
119
120
			<?php
121
		}
122
	}
123
124
	public static function get_dotorg_repo_plugins() {
125
		$plugins = get_site_transient( 'update_plugins' );
126
		return array_merge( array_keys( $plugins->response ), array_keys( $plugins->no_update ) );
127
	}
128
129
	public function bulk_actions_plugins( $bulk_actions ) {
130
		$bulk_actions['jetpack_enable_plugin_autoupdates'] = __( 'Enable Automatic Updates', 'jetpack' );
131
		$bulk_actions['jetpack_disable_plugin_autoupdates'] = __( 'Disable Automatic Updates', 'jetpack' );
132
		return $bulk_actions;
133
	}
134
135
	public function handle_bulk_actions_plugins( $redirect_to, $action, $slugs ) {
136
		$redirect_to = remove_query_arg( array( 'jetpack_enable_plugin_autoupdates', 'jetpack_disable_plugin_autoupdates' ), $redirect_to );
137
		if ( in_array( $action, array( 'jetpack_enable_plugin_autoupdates', 'jetpack_disable_plugin_autoupdates' ) ) ) {
138
			$list = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
139
			$initial_qty = sizeof( $list );
140
141
			if ( 'jetpack_enable_plugin_autoupdates' === $action ) {
142
				$list = array_unique( array_merge( $list, $slugs ) );
143
			} elseif ( 'jetpack_disable_plugin_autoupdates' === $action ) {
144
				$list = array_diff( $list, $slugs );
145
			}
146
147
			Jetpack_Options::update_option( 'autoupdate_plugins', $list );
148
			$redirect_to = add_query_arg( $action, absint( sizeof( $list ) - $initial_qty ), $redirect_to );
149
		}
150
		return $redirect_to;
151
	}
152
153
	public function plugins_admin_notices() {
154
		if ( ! empty( $_GET['jetpack_enable_plugin_autoupdates'] ) ) {
155
			$qty = (int) $_GET['jetpack_enable_plugin_autoupdates'];
156
			printf( '<div id="message" class="updated fade"><p>' . _n( 'Enabled automatic updates on %d plugin.', 'Enabled automatic updates on %d plugins.', $qty, 'jetpack' ) . '</p></div>', $qty );
157
		} elseif ( ! empty( $_GET['jetpack_disable_plugin_autoupdates'] ) ) {
158
			$qty = (int) $_GET['jetpack_disable_plugin_autoupdates'];
159
			printf( '<div id="message" class="updated fade"><p>' . _n( 'Disabled automatic updates on %d plugin.', 'Disabled automatic updates on %d plugins.', $qty, 'jetpack' ) . '</p></div>', $qty );
160
		}
161
	}
162
163
	public function jetpack_toggle_autoupdate() {
164
		if ( ! current_user_can( 'jetpack_manage_autoupdates' ) ) {
165
			wp_send_json_error();
166
			return;
167
		}
168
169
		$type   = $_POST['type'];
170
		$slug   = $_POST['slug'];
171
		$active = 'false' !== $_POST['active'];
172
173
		check_ajax_referer( "jetpack_toggle_autoupdate-{$type}" );
174
175
		if ( ! in_array( $type, array( 'plugins', 'plugins_translations' ) ) ) {
176
			wp_send_json_error();
177
			return;
178
		}
179
180
		$jetpack_option_name = "autoupdate_{$type}";
181
182
		$list = Jetpack_Options::get_option( $jetpack_option_name, array() );
183
184
		if ( $active ) {
185
			$list = array_unique( array_merge( $list, (array) $slug ) );
186
		} else {
187
			$list = array_diff( $list, (array) $slug );
188
		}
189
190
		Jetpack_Options::update_option( $jetpack_option_name, $list );
191
192
		wp_send_json_success( $list );
193
	}
194
195
	public function admin_color_override( $color ) {
196
		return 'fresh';
197
	}
198
199
	public function mock_masterbar_activation() {
200
		include_once JETPACK__PLUGIN_DIR . 'modules/masterbar/masterbar.php';
201
		new A8C_WPCOM_Masterbar;
202
	}
203
204
	public function remove_core_menus() {
205
		remove_menu_page( 'index.php' );
206
		remove_menu_page( 'jetpack' );
207
		remove_menu_page( 'edit.php' );
208
		remove_menu_page( 'edit.php?post_type=feedback' );
209
		remove_menu_page( 'upload.php' );
210
		remove_menu_page( 'edit.php?post_type=page' );
211
		remove_menu_page( 'edit-comments.php' );
212
		remove_menu_page( 'themes.php' );
213
		remove_menu_page( 'plugins.php' );
214
		remove_menu_page( 'users.php' );
215
		remove_menu_page( 'tools.php' );
216
		remove_menu_page( 'link-manager.php' );
217
218
		// Core settings pages
219
		remove_submenu_page( 'options-general.php', 'options-general.php' );
220
		remove_submenu_page( 'options-general.php', 'options-writing.php' );
221
		remove_submenu_page( 'options-general.php', 'options-reading.php' );
222
		remove_submenu_page( 'options-general.php', 'options-discussion.php' );
223
		remove_submenu_page( 'options-general.php', 'options-media.php' );
224
		remove_submenu_page( 'options-general.php', 'options-permalink.php' );
225
		remove_submenu_page( 'options-general.php', 'privacy.php' );
226
		remove_submenu_page( 'options-general.php', 'sharing' );
227
	}
228
229
	public function add_plugin_menus() {
230
		global $menu, $submenu;
231
232
		add_menu_page( __( 'Manage Plugins', 'jetpack' ), __( 'Manage Plugins', 'jetpack' ), 'activate_plugins', 'plugins.php', '', $this->installed_plugins_icon(), 1 );
233
234
		// // Count the settings page submenus, if it's zero then don't show this.
235
		if ( empty( $submenu['options-general.php'] ) ) {
236
			remove_menu_page( 'options-general.php' );
237
		} else {
238
			// Rename and make sure the plugin settings menu is always last.
239
			// Sneaky plugins seem to override this otherwise.
240
			// Settings is always key 80.
241
			$menu[80][0]                            = __( 'Plugin Settings', 'jetpack' );
242
			$menu[ max( array_keys( $menu ) ) + 1 ] = $menu[80];
243
			unset( $menu[80] );
244
		}
245
	}
246
247
	public function enqueue() {
248
		wp_enqueue_style( 'calypsoify_wpadminmods_css', plugin_dir_url( __FILE__ ) . 'style.min.css', false, JETPACK__VERSION );
249
		wp_style_add_data( 'calypsoify_wpadminmods_css', 'rtl', 'replace' );
250
        wp_style_add_data( 'calypsoify_wpadminmods_css', 'suffix', '.min' );
251
252
		wp_enqueue_script( 'calypsoify_wpadminmods_js', plugin_dir_url( __FILE__ ) . 'mods.js', false, JETPACK__VERSION );
253
		wp_localize_script( 'calypsoify_wpadminmods_js', 'CalypsoifyOpts', array(
254
			'nonces' => array(
255
				'autoupdate_plugins' => wp_create_nonce( 'jetpack_toggle_autoupdate-plugins' ),
256
				'autoupdate_plugins_translations' => wp_create_nonce( 'jetpack_toggle_autoupdate-plugins_translations' ),
257
			)
258
		) );
259
	}
260
261
	public function enqueue_for_gutenberg() {
262
		wp_enqueue_style( 'calypsoify_wpadminmods_css', plugin_dir_url( __FILE__ ) . 'style-gutenberg.min.css', false, JETPACK__VERSION );
263
		wp_style_add_data( 'calypsoify_wpadminmods_css', 'rtl', 'replace' );
264
        wp_style_add_data( 'calypsoify_wpadminmods_css', 'suffix', '.min' );
265
266
		wp_enqueue_script( 'calypsoify_wpadminmods_js', plugin_dir_url( __FILE__ ) . 'mods-gutenberg.js', false, JETPACK__VERSION );
267
		wp_localize_script(
268
			'calypsoify_wpadminmods_js',
269
			'calypsoifyGutenberg',
270
			array(
271
				'closeUrl'   => $this->get_close_gutenberg_url(),
272
			)
273
		);
274
	}
275
276
	public function insert_sidebar_html() { ?>
277
		<a href="<?php echo esc_url( 'https://wordpress.com/stats/day/' . Jetpack::build_raw_urls( home_url() ) ); ?>" id="calypso-sidebar-header">
278
			<svg class="gridicon gridicons-chevron-left" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M14 20l-8-8 8-8 1.414 1.414L8.828 12l6.586 6.586"></path></g></svg>
279
280
			<ul>
281
				<li id="calypso-sitename"><?php bloginfo( 'name' ); ?></li>
282
				<li id="calypso-plugins"><?php esc_html_e( 'Plugins' ); ?></li>
283
			</ul>
284
		</a>
285
		<?php
286
	}
287
288
	public function modify_masterbar() {
289
		global $wp_admin_bar;
290
291
		// Add proper links to masterbar top sections.
292
		$my_sites_node       = (object) $wp_admin_bar->get_node( 'blog' );
293
		$my_sites_node->href = 'https://wordpress.com/stats/day/' . Jetpack::build_raw_urls( home_url() );
294
		$wp_admin_bar->add_node( $my_sites_node );
295
296
		$reader_node       = (object) $wp_admin_bar->get_node( 'newdash' );
297
		$reader_node->href = 'https://wordpress.com';
298
		$wp_admin_bar->add_node( $reader_node );
299
300
		$me_node       = (object) $wp_admin_bar->get_node( 'my-account' );
301
		$me_node->href = 'https://wordpress.com/me';
302
		$wp_admin_bar->add_node( $me_node );
303
	}
304
305
	private function installed_plugins_icon() {
306
		$svg = '<svg class="gridicon gridicons-plugins" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 24"><g><path d="M16 8V3c0-.552-.448-1-1-1s-1 .448-1 1v5h-4V3c0-.552-.448-1-1-1s-1 .448-1 1v5H5v4c0 2.79 1.637 5.193 4 6.317V22h6v-3.683c2.363-1.124 4-3.527 4-6.317V8h-3z" fill="black"></path></g></svg>';
307
308
		return 'data:image/svg+xml;base64,' . base64_encode( $svg );
309
	}
310
311
	/**
312
	 * Returns the Calypso domain that originated the current request.
313
	 *
314
	 * @return string
315
	 */
316
	private function get_calypso_origin() {
317
		$origin    = ! empty( $_GET['origin'] ) ? $_GET['origin'] : 'https://wordpress.com';
318
		$whitelist = array(
319
			'http://calypso.localhost:3000',
320
			'http://127.0.0.1:41050', // Desktop App
321
			'https://wpcalypso.wordpress.com',
322
			'https://horizon.wordpress.com',
323
			'https://wordpress.com',
324
		);
325
		return in_array( $origin, $whitelist ) ? $origin : 'https://wordpress.com';
326
	}
327
328
	/**
329
	 * Returns the site slug suffix to be used as part of the Calypso URLs. It already
330
	 * includes the slash separator at the beginning.
331
	 *
332
	 * @example "https://wordpress.com/block-editor" . $this->get_site_suffix()
333
	 *
334
	 * @return string
335
	 */
336
	private function get_site_suffix() {
337 View Code Duplication
		if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'build_raw_urls' ) ) {
338
			$site_suffix = Jetpack::build_raw_urls( home_url() );
339
		} elseif ( class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
340
			$site_suffix = WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
341
		}
342
343
		if ( $site_suffix ) {
344
			return "/${site_suffix}";
0 ignored issues
show
The variable $site_suffix does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
345
		}
346
		return '';
347
	}
348
349
	/**
350
	 * Returns the Calypso URL that displays either the current post type list (if no args
351
	 * are supplied) or the classic editor for the current post (if a post ID is supplied).
352
	 *
353
	 * @param int|null $post_id
354
	 * @return string
355
	 */
356
	public function get_calypso_url( $post_id = null ) {
357
		$screen = get_current_screen();
358
		$post_type = $screen->post_type;
359
		if ( is_null( $post_id ) ) {
360
			// E.g. `posts`, `pages`, or `types/some_custom_post_type`
361
			$post_type_suffix = ( 'post' === $post_type || 'page' === $post_type )
362
				? "/${post_type}s"
363
				: "/types/${post_type}";
364
			$post_suffix = '';
365
		} else {
366
			$post_type_suffix = ( 'post' === $post_type || 'page' === $post_type )
367
				? "/${post_type}"
368
				: "/edit/${post_type}";
369
			$post_suffix = "/${post_id}";
370
		}
371
372
		return $this->get_calypso_origin() . $post_type_suffix . $this->get_site_suffix() . $post_suffix;
373
	}
374
375
	/**
376
	 * Returns the URL to be used on the block editor close button for going back to the
377
	 * Calypso post list.
378
	 *
379
	 * @return string
380
	 */
381
	public function get_close_gutenberg_url() {
382
		return $this->get_calypso_url();
383
	}
384
385
	/**
386
	 * Returns the URL for switching the user's editor to the Calypso (WordPress.com Classic) editor.
387
	 *
388
	 * @return string
389
	 */
390
	public function get_switch_to_classic_editor_url() {
391
		return add_query_arg(
392
			'set-editor',
393
			'classic',
394
			$this->is_calypsoify_enabled ? $this->get_calypso_url( get_the_ID() ) : false
395
		);
396
	}
397
398
	public function check_param() {
399
		if ( isset( $_GET['calypsoify'] ) ) {
400
			if ( 1 == (int) $_GET['calypsoify'] ) {
401
				update_user_meta( get_current_user_id(), 'calypsoify', 1 );
402
			} else {
403
				update_user_meta( get_current_user_id(), 'calypsoify', 0 );
404
			}
405
406
			$page = remove_query_arg( 'calypsoify', wp_basename( $_SERVER['REQUEST_URI'] ) );
407
408
			wp_safe_redirect( admin_url( $page ) );
409
		}
410
	}
411
412
	public function check_page() {
413
		// If the user hits plain /wp-admin/ then disable Calypso styles.
414
		$page = wp_basename( esc_url( $_SERVER['REQUEST_URI'] ) );
415
416
		if ( false !== strpos( 'index.php', $page ) || false !== strpos( 'wp-admin', $page ) ) {
417
			update_user_meta( get_current_user_id(), 'calypsoify', 0 );
418
			wp_safe_redirect( admin_url() );
419
			die;
420
		}
421
	}
422
423
	/**
424
	 * Return whether a post type should display the Gutenberg/block editor.
425
	 *
426
	 * @since 6.7.0
427
	 */
428
	public function is_post_type_gutenberg( $post_type ) {
429
		return use_block_editor_for_post_type( $post_type );
430
	}
431
432
	public function is_page_gutenberg() {
433
		$page = wp_basename( esc_url( $_SERVER['REQUEST_URI'] ) );
434
435
		if ( false !== strpos( $page, 'post-new.php' ) && empty ( $_GET['post_type'] ) ) {
436
			return true;
437
		}
438
439
		if ( false !== strpos( $page, 'post-new.php' ) && isset( $_GET['post_type'] ) && $this->is_post_type_gutenberg( $_GET['post_type'] ) ) {
440
			return true;
441
		}
442
443 View Code Duplication
		if ( false !== strpos( $page, 'post.php' ) ) {
444
			$post = get_post( $_GET['post'] );
445
			if ( isset( $post ) && isset( $post->post_type ) && $this->is_post_type_gutenberg( $post->post_type ) ) {
446
				return true;
447
			}
448
		}
449
450 View Code Duplication
		if ( false !== strpos( $page, 'revision.php' ) ) {
451
			$post   = get_post( $_GET['revision'] );
452
			$parent = get_post( $post->post_parent );
453
			if ( isset( $parent ) && isset( $parent->post_type ) && $this->is_post_type_gutenberg( $parent->post_type ) ) {
454
				return true;
455
			}
456
		}
457
458
		return false;
459
	}
460
}
461
462
$Jetpack_Calypsoify = Jetpack_Calypsoify::getInstance();
463