Completed
Push — fix/useBlockEditContext-usage ( 1e6b8b...d10938 )
by
unknown
199:36 queued 191:34
created

Plugins_Handler::get_active_plugins()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/* HEADER */ // phpcs:ignore
3
4
/**
5
 * This class provides information about the current plugin and the site's active plugins.
6
 */
7
class Plugins_Handler {
8
9
	/**
10
	 * Returns an array containing the directories of all active plugins and all known activating plugins.
11
	 *
12
	 * @return Array An array of plugin directories as strings or an empty array.
13
	 */
14
	public function get_all_active_plugins() {
15
		global $jetpack_autoloader_activating_plugins;
16
17
		$active_plugins    = $this->convert_plugins_to_dirs( $this->get_active_plugins() );
18
		$multisite_plugins = $this->convert_plugins_to_dirs( $this->get_multisite_plugins() );
19
		$active_plugins    = array_merge( $multisite_plugins, $active_plugins );
20
21
		$activating_plugins = $this->convert_plugins_to_dirs( $this->get_plugins_activating_via_request() );
22
		$activating_plugins = array_unique( array_merge( $activating_plugins, $jetpack_autoloader_activating_plugins ) );
23
24
		$plugins = array_unique( array_merge( $active_plugins, $activating_plugins ) );
25
		return $plugins;
26
	}
27
28
	/**
29
	 * Returns an array containing the names for the active sitewide plugins in a multisite environment.
30
	 *
31
	 * @return Array The names of the active sitewide plugins or an empty array.
32
	 */
33
	protected function get_multisite_plugins() {
34
		return is_multisite()
35
			? array_keys( get_site_option( 'active_sitewide_plugins', array() ) )
36
			: array();
37
	}
38
39
	/**
40
	 * Returns an array containing the names of the currently active plugins.
41
	 *
42
	 * @return Array The active plugins' names or an empty array.
43
	 */
44
	protected function get_active_plugins() {
45
		return (array) get_option( 'active_plugins', array() );
46
	}
47
48
	/**
49
	 * Ensure the plugin has its own directory and not a single-file plugin.
50
	 *
51
	 * @param string $plugin Plugin name, may be prefixed with "/".
52
	 *
53
	 * @return bool
54
	 */
55
	public function is_directory_plugin( $plugin ) {
56
		return false !== strpos( $plugin, '/', 1 );
57
	}
58
59
	/**
60
	 * Returns the plugin's directory.
61
	 *
62
	 * The input is a string with the format 'dir/file.php'. This method removes the 'file.php' part. The directory
63
	 * alone can be used to identify the plugin.
64
	 *
65
	 * @param string $plugin The plugin string with the format 'dir/file.php'.
66
	 *
67
	 * @return string The plugin's directory.
68
	 */
69
	private function remove_plugin_file_from_string( $plugin ) {
70
		return explode( '/', $plugin )[0];
71
	}
72
73
	/**
74
	 * Converts an array of plugin strings with the format 'dir/file.php' to an array of directories. Also removes any
75
	 * single-file plugins since they cannot have packages.
76
	 *
77
	 * @param Array $plugins The array of plugin strings with the format 'dir/file.php'.
78
	 *
79
	 * @return Array An array of plugin directories.
80
	 */
81
	private function convert_plugins_to_dirs( $plugins ) {
82
		$plugins = array_filter( $plugins, array( $this, 'is_directory_plugin' ) );
83
		return array_map( array( $this, 'remove_plugin_file_from_string' ), $plugins );
84
	}
85
86
	/**
87
	 * Checks whether the autoloader should be reset. The autoloader should be reset
88
	 * when a plugin is activating via a method other than a request, for example
89
	 * using WP-CLI. When this occurs, the activating plugin was not known when
90
	 * the autoloader selected the package versions for the classmap and filemap
91
	 * globals, so the autoloader must reselect the versions.
92
	 *
93
	 * If the current plugin is not already known, this method will add it to the
94
	 * $jetpack_autoloader_activating_plugins global.
95
	 *
96
	 * @return Boolean True if the autoloder must be reset, else false.
97
	 */
98
	public function should_autoloader_reset() {
99
		global $jetpack_autoloader_activating_plugins;
100
101
		$plugins        = $this->get_all_active_plugins();
102
		$current_plugin = $this->get_current_plugin_dir();
103
		$plugin_unknown = ! in_array( $current_plugin, $plugins, true );
104
105
		if ( $plugin_unknown ) {
106
			// If the current plugin isn't known, add it to the activating plugins list.
107
			$jetpack_autoloader_activating_plugins[] = $current_plugin;
108
		}
109
110
		return $plugin_unknown;
111
	}
112
113
	/**
114
	 * Returns an array containing the names of plugins that are activating via a request.
115
	 *
116
	 * @return Array An array of names of the activating plugins or an empty array.
117
	 */
118
	private function get_plugins_activating_via_request() {
119
120
		 // phpcs:disable WordPress.Security.NonceVerification.Recommended
121
122
		$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : false;
123
		$plugin = isset( $_REQUEST['plugin'] ) ? $_REQUEST['plugin'] : false;
124
		$nonce  = isset( $_REQUEST['_wpnonce'] ) ? $_REQUEST['_wpnonce'] : false;
125
126
		/**
127
		 * Note: we're not actually checking the nonce here becase it's too early
128
		 * in the execution. The pluggable functions are not yet loaded to give
129
		 * plugins a chance to plug their versions. Therefore we're doing the bare
130
		 * minimum: checking whether the nonce exists and it's in the right place.
131
		 * The request will fail later if the nonce doesn't pass the check.
132
		 */
133
134
		// In case of a single plugin activation there will be a plugin slug.
135
		if ( 'activate' === $action && ! empty( $nonce ) ) {
136
			return array( wp_unslash( $plugin ) );
137
		}
138
139
		$plugins = isset( $_REQUEST['checked'] ) ? $_REQUEST['checked'] : array();
140
141
		// In case of bulk activation there will be an array of plugins.
142
		if ( 'activate-selected' === $action && ! empty( $nonce ) ) {
143
			return array_map( 'wp_unslash', $plugins );
144
		}
145
146
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
147
148
		return array();
149
	}
150
151
	/**
152
	 * Returns the directory of the current plugin.
153
	 *
154
	 * @return String The directory of the current plugin.
155
	 */
156
	public function get_current_plugin_dir() {
157
		return explode( '/', plugin_basename( __FILE__ ) )[0];
158
	}
159
160
	/**
161
	 * Resets the autoloader after a plugin update.
162
	 *
163
	 * @param bool  $response   Installation response.
164
	 * @param array $hook_extra Extra arguments passed to hooked filters.
165
	 * @param array $result     Installation result data.
166
	 *
167
	 * @return bool The passed in $response param.
168
	 */
169
	public function reset_maps_after_update( $response, $hook_extra, $result ) {
170
		global $jetpack_autoloader_latest_version;
171
		global $jetpack_packages_classmap;
172
173
		if ( isset( $hook_extra['plugin'] ) ) {
174
			$plugin = $hook_extra['plugin'];
175
176
			if ( ! $this->is_directory_plugin( $plugin ) ) {
177
				// Single-file plugins don't use packages, so bail.
178
				return $response;
179
			}
180
181
			if ( ! is_plugin_active( $plugin ) ) {
182
				// The updated plugin isn't active, so bail.
183
				return $response;
184
			}
185
186
			$plugin_path = trailingslashit( WP_PLUGIN_DIR ) . trailingslashit( explode( '/', $plugin )[0] );
187
188
			if ( is_readable( $plugin_path . 'vendor/autoload_functions.php' ) ) {
189
				// The plugin has a v2.x autoloader, so reset it.
190
				$jetpack_autoloader_latest_version = null;
191
				$jetpack_packages_classmap         = array();
192
193
				require $plugin_path . 'vendor/autoload_packages.php';
194
			}
195
		}
196
197
		return $response;
198
	}
199
}
200