Passed
Push — main ( 67eb22...ce3ddb )
by TARIQ
01:40
created
brighty-core-plugin/vendor/tgmpa/tgm-plugin-activation/example.php 1 patch
Indentation   +63 added lines, -63 removed lines patch added patch discarded remove patch
@@ -53,65 +53,65 @@  discard block
 block discarded – undo
53 53
  * This function is hooked into `tgmpa_register`, which is fired on the WP `init` action on priority 10.
54 54
  */
55 55
 function my_theme_register_required_plugins() {
56
-	/*
56
+    /*
57 57
 	 * Array of plugin arrays. Required keys are name and slug.
58 58
 	 * If the source is NOT from the .org repo, then source is also required.
59 59
 	 */
60
-	$plugins = array(
60
+    $plugins = array(
61 61
 
62
-		// This is an example of how to include a plugin bundled with a theme.
63
-		array(
64
-			'name'               => 'TGM Example Plugin', // The plugin name.
65
-			'slug'               => 'tgm-example-plugin', // The plugin slug (typically the folder name).
66
-			'source'             => get_stylesheet_directory() . '/lib/plugins/tgm-example-plugin.zip', // The plugin source.
67
-			'required'           => true, // If false, the plugin is only 'recommended' instead of required.
68
-			'version'            => '', // E.g. 1.0.0. If set, the active plugin must be this version or higher. If the plugin version is higher than the plugin version installed, the user will be notified to update the plugin.
69
-			'force_activation'   => false, // If true, plugin is activated upon theme activation and cannot be deactivated until theme switch.
70
-			'force_deactivation' => false, // If true, plugin is deactivated upon theme switch, useful for theme-specific plugins.
71
-			'external_url'       => '', // If set, overrides default API URL and points to an external URL.
72
-			'is_callable'        => '', // If set, this callable will be be checked for availability to determine if a plugin is active.
73
-		),
62
+        // This is an example of how to include a plugin bundled with a theme.
63
+        array(
64
+            'name'               => 'TGM Example Plugin', // The plugin name.
65
+            'slug'               => 'tgm-example-plugin', // The plugin slug (typically the folder name).
66
+            'source'             => get_stylesheet_directory() . '/lib/plugins/tgm-example-plugin.zip', // The plugin source.
67
+            'required'           => true, // If false, the plugin is only 'recommended' instead of required.
68
+            'version'            => '', // E.g. 1.0.0. If set, the active plugin must be this version or higher. If the plugin version is higher than the plugin version installed, the user will be notified to update the plugin.
69
+            'force_activation'   => false, // If true, plugin is activated upon theme activation and cannot be deactivated until theme switch.
70
+            'force_deactivation' => false, // If true, plugin is deactivated upon theme switch, useful for theme-specific plugins.
71
+            'external_url'       => '', // If set, overrides default API URL and points to an external URL.
72
+            'is_callable'        => '', // If set, this callable will be be checked for availability to determine if a plugin is active.
73
+        ),
74 74
 
75
-		// This is an example of how to include a plugin from an arbitrary external source in your theme.
76
-		array(
77
-			'name'         => 'TGM New Media Plugin', // The plugin name.
78
-			'slug'         => 'tgm-new-media-plugin', // The plugin slug (typically the folder name).
79
-			'source'       => 'https://s3.amazonaws.com/tgm/tgm-new-media-plugin.zip', // The plugin source.
80
-			'required'     => true, // If false, the plugin is only 'recommended' instead of required.
81
-			'external_url' => 'https://github.com/thomasgriffin/New-Media-Image-Uploader', // If set, overrides default API URL and points to an external URL.
82
-		),
75
+        // This is an example of how to include a plugin from an arbitrary external source in your theme.
76
+        array(
77
+            'name'         => 'TGM New Media Plugin', // The plugin name.
78
+            'slug'         => 'tgm-new-media-plugin', // The plugin slug (typically the folder name).
79
+            'source'       => 'https://s3.amazonaws.com/tgm/tgm-new-media-plugin.zip', // The plugin source.
80
+            'required'     => true, // If false, the plugin is only 'recommended' instead of required.
81
+            'external_url' => 'https://github.com/thomasgriffin/New-Media-Image-Uploader', // If set, overrides default API URL and points to an external URL.
82
+        ),
83 83
 
84
-		// This is an example of how to include a plugin from a GitHub repository in your theme.
85
-		// This presumes that the plugin code is based in the root of the GitHub repository
86
-		// and not in a subdirectory ('/src') of the repository.
87
-		array(
88
-			'name'      => 'Adminbar Link Comments to Pending',
89
-			'slug'      => 'adminbar-link-comments-to-pending',
90
-			'source'    => 'https://github.com/jrfnl/WP-adminbar-comments-to-pending/archive/master.zip',
91
-		),
84
+        // This is an example of how to include a plugin from a GitHub repository in your theme.
85
+        // This presumes that the plugin code is based in the root of the GitHub repository
86
+        // and not in a subdirectory ('/src') of the repository.
87
+        array(
88
+            'name'      => 'Adminbar Link Comments to Pending',
89
+            'slug'      => 'adminbar-link-comments-to-pending',
90
+            'source'    => 'https://github.com/jrfnl/WP-adminbar-comments-to-pending/archive/master.zip',
91
+        ),
92 92
 
93
-		// This is an example of how to include a plugin from the WordPress Plugin Repository.
94
-		array(
95
-			'name'      => 'BuddyPress',
96
-			'slug'      => 'buddypress',
97
-			'required'  => false,
98
-		),
93
+        // This is an example of how to include a plugin from the WordPress Plugin Repository.
94
+        array(
95
+            'name'      => 'BuddyPress',
96
+            'slug'      => 'buddypress',
97
+            'required'  => false,
98
+        ),
99 99
 
100
-		// This is an example of the use of 'is_callable' functionality. A user could - for instance -
101
-		// have WPSEO installed *or* WPSEO Premium. The slug would in that last case be different, i.e.
102
-		// 'wordpress-seo-premium'.
103
-		// By setting 'is_callable' to either a function from that plugin or a class method
104
-		// `array( 'class', 'method' )` similar to how you hook in to actions and filters, TGMPA can still
105
-		// recognize the plugin as being installed.
106
-		array(
107
-			'name'        => 'WordPress SEO by Yoast',
108
-			'slug'        => 'wordpress-seo',
109
-			'is_callable' => 'wpseo_init',
110
-		),
100
+        // This is an example of the use of 'is_callable' functionality. A user could - for instance -
101
+        // have WPSEO installed *or* WPSEO Premium. The slug would in that last case be different, i.e.
102
+        // 'wordpress-seo-premium'.
103
+        // By setting 'is_callable' to either a function from that plugin or a class method
104
+        // `array( 'class', 'method' )` similar to how you hook in to actions and filters, TGMPA can still
105
+        // recognize the plugin as being installed.
106
+        array(
107
+            'name'        => 'WordPress SEO by Yoast',
108
+            'slug'        => 'wordpress-seo',
109
+            'is_callable' => 'wpseo_init',
110
+        ),
111 111
 
112
-	);
112
+    );
113 113
 
114
-	/*
114
+    /*
115 115
 	 * Array of configuration settings. Amend each line as needed.
116 116
 	 *
117 117
 	 * TGMPA will start providing localized text strings soon. If you already have translations of our standard
@@ -120,19 +120,19 @@  discard block
 block discarded – undo
120 120
 	 *
121 121
 	 * Only uncomment the strings in the config array if you want to customize the strings.
122 122
 	 */
123
-	$config = array(
124
-		'id'           => 'tgmpa',                 // Unique ID for hashing notices for multiple instances of TGMPA.
125
-		'default_path' => '',                      // Default absolute path to bundled plugins.
126
-		'menu'         => 'tgmpa-install-plugins', // Menu slug.
127
-		'parent_slug'  => 'themes.php',            // Parent menu slug.
128
-		'capability'   => 'edit_theme_options',    // Capability needed to view plugin install page, should be a capability associated with the parent menu used.
129
-		'has_notices'  => true,                    // Show admin notices or not.
130
-		'dismissable'  => true,                    // If false, a user cannot dismiss the nag message.
131
-		'dismiss_msg'  => '',                      // If 'dismissable' is false, this message will be output at top of nag.
132
-		'is_automatic' => false,                   // Automatically activate plugins after installation or not.
133
-		'message'      => '',                      // Message to output right before the plugins table.
123
+    $config = array(
124
+        'id'           => 'tgmpa',                 // Unique ID for hashing notices for multiple instances of TGMPA.
125
+        'default_path' => '',                      // Default absolute path to bundled plugins.
126
+        'menu'         => 'tgmpa-install-plugins', // Menu slug.
127
+        'parent_slug'  => 'themes.php',            // Parent menu slug.
128
+        'capability'   => 'edit_theme_options',    // Capability needed to view plugin install page, should be a capability associated with the parent menu used.
129
+        'has_notices'  => true,                    // Show admin notices or not.
130
+        'dismissable'  => true,                    // If false, a user cannot dismiss the nag message.
131
+        'dismiss_msg'  => '',                      // If 'dismissable' is false, this message will be output at top of nag.
132
+        'is_automatic' => false,                   // Automatically activate plugins after installation or not.
133
+        'message'      => '',                      // Message to output right before the plugins table.
134 134
 
135
-		/*
135
+        /*
136 136
 		'strings'      => array(
137 137
 			'page_title'                      => __( 'Install Required Plugins', 'theme-slug' ),
138 138
 			'menu_title'                      => __( 'Install Plugins', 'theme-slug' ),
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 			'nag_type'                        => '', // Determines admin notice type - can only be one of the typical WP notice classes, such as 'updated', 'update-nag', 'notice-warning', 'notice-info' or 'error'. Some of which may not work as expected in older WP versions.
209 209
 		),
210 210
 		*/
211
-	);
211
+    );
212 212
 
213
-	tgmpa( $plugins, $config );
213
+    tgmpa( $plugins, $config );
214 214
 }
Please login to merge, or discard this patch.
vendor/tgmpa/tgm-plugin-activation/class-tgm-plugin-activation.php 1 patch
Indentation   +3713 added lines, -3713 removed lines patch added patch discarded remove patch
@@ -34,737 +34,737 @@  discard block
 block discarded – undo
34 34
 
35 35
 if ( ! class_exists( 'TGM_Plugin_Activation' ) ) {
36 36
 
37
-	/**
38
-	 * Automatic plugin installation and activation library.
39
-	 *
40
-	 * Creates a way to automatically install and activate plugins from within themes.
41
-	 * The plugins can be either bundled, downloaded from the WordPress
42
-	 * Plugin Repository or downloaded from another external source.
43
-	 *
44
-	 * @since 1.0.0
45
-	 *
46
-	 * @package TGM-Plugin-Activation
47
-	 * @author  Thomas Griffin
48
-	 * @author  Gary Jones
49
-	 */
50
-	class TGM_Plugin_Activation {
51
-		/**
52
-		 * TGMPA version number.
53
-		 *
54
-		 * @since 2.5.0
55
-		 *
56
-		 * @const string Version number.
57
-		 */
58
-		const TGMPA_VERSION = '2.6.1';
59
-
60
-		/**
61
-		 * Regular expression to test if a URL is a WP plugin repo URL.
62
-		 *
63
-		 * @const string Regex.
64
-		 *
65
-		 * @since 2.5.0
66
-		 */
67
-		const WP_REPO_REGEX = '|^http[s]?://wordpress\.org/(?:extend/)?plugins/|';
68
-
69
-		/**
70
-		 * Arbitrary regular expression to test if a string starts with a URL.
71
-		 *
72
-		 * @const string Regex.
73
-		 *
74
-		 * @since 2.5.0
75
-		 */
76
-		const IS_URL_REGEX = '|^http[s]?://|';
77
-
78
-		/**
79
-		 * Holds a copy of itself, so it can be referenced by the class name.
80
-		 *
81
-		 * @since 1.0.0
82
-		 *
83
-		 * @var TGM_Plugin_Activation
84
-		 */
85
-		public static $instance;
86
-
87
-		/**
88
-		 * Holds arrays of plugin details.
89
-		 *
90
-		 * @since 1.0.0
91
-		 * @since 2.5.0 the array has the plugin slug as an associative key.
92
-		 *
93
-		 * @var array
94
-		 */
95
-		public $plugins = array();
96
-
97
-		/**
98
-		 * Holds arrays of plugin names to use to sort the plugins array.
99
-		 *
100
-		 * @since 2.5.0
101
-		 *
102
-		 * @var array
103
-		 */
104
-		protected $sort_order = array();
105
-
106
-		/**
107
-		 * Whether any plugins have the 'force_activation' setting set to true.
108
-		 *
109
-		 * @since 2.5.0
110
-		 *
111
-		 * @var bool
112
-		 */
113
-		protected $has_forced_activation = false;
114
-
115
-		/**
116
-		 * Whether any plugins have the 'force_deactivation' setting set to true.
117
-		 *
118
-		 * @since 2.5.0
119
-		 *
120
-		 * @var bool
121
-		 */
122
-		protected $has_forced_deactivation = false;
123
-
124
-		/**
125
-		 * Name of the unique ID to hash notices.
126
-		 *
127
-		 * @since 2.4.0
128
-		 *
129
-		 * @var string
130
-		 */
131
-		public $id = 'tgmpa';
132
-
133
-		/**
134
-		 * Name of the query-string argument for the admin page.
135
-		 *
136
-		 * @since 1.0.0
137
-		 *
138
-		 * @var string
139
-		 */
140
-		protected $menu = 'tgmpa-install-plugins';
141
-
142
-		/**
143
-		 * Parent menu file slug.
144
-		 *
145
-		 * @since 2.5.0
146
-		 *
147
-		 * @var string
148
-		 */
149
-		public $parent_slug = 'themes.php';
150
-
151
-		/**
152
-		 * Capability needed to view the plugin installation menu item.
153
-		 *
154
-		 * @since 2.5.0
155
-		 *
156
-		 * @var string
157
-		 */
158
-		public $capability = 'edit_theme_options';
159
-
160
-		/**
161
-		 * Default absolute path to folder containing bundled plugin zip files.
162
-		 *
163
-		 * @since 2.0.0
164
-		 *
165
-		 * @var string Absolute path prefix to zip file location for bundled plugins. Default is empty string.
166
-		 */
167
-		public $default_path = '';
168
-
169
-		/**
170
-		 * Flag to show admin notices or not.
171
-		 *
172
-		 * @since 2.1.0
173
-		 *
174
-		 * @var boolean
175
-		 */
176
-		public $has_notices = true;
177
-
178
-		/**
179
-		 * Flag to determine if the user can dismiss the notice nag.
180
-		 *
181
-		 * @since 2.4.0
182
-		 *
183
-		 * @var boolean
184
-		 */
185
-		public $dismissable = true;
186
-
187
-		/**
188
-		 * Message to be output above nag notice if dismissable is false.
189
-		 *
190
-		 * @since 2.4.0
191
-		 *
192
-		 * @var string
193
-		 */
194
-		public $dismiss_msg = '';
195
-
196
-		/**
197
-		 * Flag to set automatic activation of plugins. Off by default.
198
-		 *
199
-		 * @since 2.2.0
200
-		 *
201
-		 * @var boolean
202
-		 */
203
-		public $is_automatic = false;
204
-
205
-		/**
206
-		 * Optional message to display before the plugins table.
207
-		 *
208
-		 * @since 2.2.0
209
-		 *
210
-		 * @var string Message filtered by wp_kses_post(). Default is empty string.
211
-		 */
212
-		public $message = '';
213
-
214
-		/**
215
-		 * Holds configurable array of strings.
216
-		 *
217
-		 * Default values are added in the constructor.
218
-		 *
219
-		 * @since 2.0.0
220
-		 *
221
-		 * @var array
222
-		 */
223
-		public $strings = array();
224
-
225
-		/**
226
-		 * Holds the version of WordPress.
227
-		 *
228
-		 * @since 2.4.0
229
-		 *
230
-		 * @var int
231
-		 */
232
-		public $wp_version;
233
-
234
-		/**
235
-		 * Holds the hook name for the admin page.
236
-		 *
237
-		 * @since 2.5.0
238
-		 *
239
-		 * @var string
240
-		 */
241
-		public $page_hook;
242
-
243
-		/**
244
-		 * Adds a reference of this object to $instance, populates default strings,
245
-		 * does the tgmpa_init action hook, and hooks in the interactions to init.
246
-		 *
247
-		 * {@internal This method should be `protected`, but as too many TGMPA implementations
248
-		 * haven't upgraded beyond v2.3.6 yet, this gives backward compatibility issues.
249
-		 * Reverted back to public for the time being.}}
250
-		 *
251
-		 * @since 1.0.0
252
-		 *
253
-		 * @see TGM_Plugin_Activation::init()
254
-		 */
255
-		public function __construct() {
256
-			// Set the current WordPress version.
257
-			$this->wp_version = $GLOBALS['wp_version'];
258
-
259
-			// Announce that the class is ready, and pass the object (for advanced use).
260
-			do_action_ref_array( 'tgmpa_init', array( $this ) );
261
-
262
-			/*
37
+    /**
38
+     * Automatic plugin installation and activation library.
39
+     *
40
+     * Creates a way to automatically install and activate plugins from within themes.
41
+     * The plugins can be either bundled, downloaded from the WordPress
42
+     * Plugin Repository or downloaded from another external source.
43
+     *
44
+     * @since 1.0.0
45
+     *
46
+     * @package TGM-Plugin-Activation
47
+     * @author  Thomas Griffin
48
+     * @author  Gary Jones
49
+     */
50
+    class TGM_Plugin_Activation {
51
+        /**
52
+         * TGMPA version number.
53
+         *
54
+         * @since 2.5.0
55
+         *
56
+         * @const string Version number.
57
+         */
58
+        const TGMPA_VERSION = '2.6.1';
59
+
60
+        /**
61
+         * Regular expression to test if a URL is a WP plugin repo URL.
62
+         *
63
+         * @const string Regex.
64
+         *
65
+         * @since 2.5.0
66
+         */
67
+        const WP_REPO_REGEX = '|^http[s]?://wordpress\.org/(?:extend/)?plugins/|';
68
+
69
+        /**
70
+         * Arbitrary regular expression to test if a string starts with a URL.
71
+         *
72
+         * @const string Regex.
73
+         *
74
+         * @since 2.5.0
75
+         */
76
+        const IS_URL_REGEX = '|^http[s]?://|';
77
+
78
+        /**
79
+         * Holds a copy of itself, so it can be referenced by the class name.
80
+         *
81
+         * @since 1.0.0
82
+         *
83
+         * @var TGM_Plugin_Activation
84
+         */
85
+        public static $instance;
86
+
87
+        /**
88
+         * Holds arrays of plugin details.
89
+         *
90
+         * @since 1.0.0
91
+         * @since 2.5.0 the array has the plugin slug as an associative key.
92
+         *
93
+         * @var array
94
+         */
95
+        public $plugins = array();
96
+
97
+        /**
98
+         * Holds arrays of plugin names to use to sort the plugins array.
99
+         *
100
+         * @since 2.5.0
101
+         *
102
+         * @var array
103
+         */
104
+        protected $sort_order = array();
105
+
106
+        /**
107
+         * Whether any plugins have the 'force_activation' setting set to true.
108
+         *
109
+         * @since 2.5.0
110
+         *
111
+         * @var bool
112
+         */
113
+        protected $has_forced_activation = false;
114
+
115
+        /**
116
+         * Whether any plugins have the 'force_deactivation' setting set to true.
117
+         *
118
+         * @since 2.5.0
119
+         *
120
+         * @var bool
121
+         */
122
+        protected $has_forced_deactivation = false;
123
+
124
+        /**
125
+         * Name of the unique ID to hash notices.
126
+         *
127
+         * @since 2.4.0
128
+         *
129
+         * @var string
130
+         */
131
+        public $id = 'tgmpa';
132
+
133
+        /**
134
+         * Name of the query-string argument for the admin page.
135
+         *
136
+         * @since 1.0.0
137
+         *
138
+         * @var string
139
+         */
140
+        protected $menu = 'tgmpa-install-plugins';
141
+
142
+        /**
143
+         * Parent menu file slug.
144
+         *
145
+         * @since 2.5.0
146
+         *
147
+         * @var string
148
+         */
149
+        public $parent_slug = 'themes.php';
150
+
151
+        /**
152
+         * Capability needed to view the plugin installation menu item.
153
+         *
154
+         * @since 2.5.0
155
+         *
156
+         * @var string
157
+         */
158
+        public $capability = 'edit_theme_options';
159
+
160
+        /**
161
+         * Default absolute path to folder containing bundled plugin zip files.
162
+         *
163
+         * @since 2.0.0
164
+         *
165
+         * @var string Absolute path prefix to zip file location for bundled plugins. Default is empty string.
166
+         */
167
+        public $default_path = '';
168
+
169
+        /**
170
+         * Flag to show admin notices or not.
171
+         *
172
+         * @since 2.1.0
173
+         *
174
+         * @var boolean
175
+         */
176
+        public $has_notices = true;
177
+
178
+        /**
179
+         * Flag to determine if the user can dismiss the notice nag.
180
+         *
181
+         * @since 2.4.0
182
+         *
183
+         * @var boolean
184
+         */
185
+        public $dismissable = true;
186
+
187
+        /**
188
+         * Message to be output above nag notice if dismissable is false.
189
+         *
190
+         * @since 2.4.0
191
+         *
192
+         * @var string
193
+         */
194
+        public $dismiss_msg = '';
195
+
196
+        /**
197
+         * Flag to set automatic activation of plugins. Off by default.
198
+         *
199
+         * @since 2.2.0
200
+         *
201
+         * @var boolean
202
+         */
203
+        public $is_automatic = false;
204
+
205
+        /**
206
+         * Optional message to display before the plugins table.
207
+         *
208
+         * @since 2.2.0
209
+         *
210
+         * @var string Message filtered by wp_kses_post(). Default is empty string.
211
+         */
212
+        public $message = '';
213
+
214
+        /**
215
+         * Holds configurable array of strings.
216
+         *
217
+         * Default values are added in the constructor.
218
+         *
219
+         * @since 2.0.0
220
+         *
221
+         * @var array
222
+         */
223
+        public $strings = array();
224
+
225
+        /**
226
+         * Holds the version of WordPress.
227
+         *
228
+         * @since 2.4.0
229
+         *
230
+         * @var int
231
+         */
232
+        public $wp_version;
233
+
234
+        /**
235
+         * Holds the hook name for the admin page.
236
+         *
237
+         * @since 2.5.0
238
+         *
239
+         * @var string
240
+         */
241
+        public $page_hook;
242
+
243
+        /**
244
+         * Adds a reference of this object to $instance, populates default strings,
245
+         * does the tgmpa_init action hook, and hooks in the interactions to init.
246
+         *
247
+         * {@internal This method should be `protected`, but as too many TGMPA implementations
248
+         * haven't upgraded beyond v2.3.6 yet, this gives backward compatibility issues.
249
+         * Reverted back to public for the time being.}}
250
+         *
251
+         * @since 1.0.0
252
+         *
253
+         * @see TGM_Plugin_Activation::init()
254
+         */
255
+        public function __construct() {
256
+            // Set the current WordPress version.
257
+            $this->wp_version = $GLOBALS['wp_version'];
258
+
259
+            // Announce that the class is ready, and pass the object (for advanced use).
260
+            do_action_ref_array( 'tgmpa_init', array( $this ) );
261
+
262
+            /*
263 263
 			 * Load our text domain and allow for overloading the fall-back file.
264 264
 			 *
265 265
 			 * {@internal IMPORTANT! If this code changes, review the regex in the custom TGMPA
266 266
 			 * generator on the website.}}
267 267
 			 */
268
-			add_action( 'init', array( $this, 'load_textdomain' ), 5 );
269
-			add_filter( 'load_textdomain_mofile', array( $this, 'overload_textdomain_mofile' ), 10, 2 );
270
-
271
-			// When the rest of WP has loaded, kick-start the rest of the class.
272
-			add_action( 'init', array( $this, 'init' ) );
273
-		}
274
-
275
-		/**
276
-		 * Magic method to (not) set protected properties from outside of this class.
277
-		 *
278
-		 * {@internal hackedihack... There is a serious bug in v2.3.2 - 2.3.6  where the `menu` property
279
-		 * is being assigned rather than tested in a conditional, effectively rendering it useless.
280
-		 * This 'hack' prevents this from happening.}}
281
-		 *
282
-		 * @see https://github.com/TGMPA/TGM-Plugin-Activation/blob/2.3.6/tgm-plugin-activation/class-tgm-plugin-activation.php#L1593
283
-		 *
284
-		 * @since 2.5.2
285
-		 *
286
-		 * @param string $name  Name of an inaccessible property.
287
-		 * @param mixed  $value Value to assign to the property.
288
-		 * @return void  Silently fail to set the property when this is tried from outside of this class context.
289
-		 *               (Inside this class context, the __set() method if not used as there is direct access.)
290
-		 */
291
-		public function __set( $name, $value ) {
292
-			return;
293
-		}
294
-
295
-		/**
296
-		 * Magic method to get the value of a protected property outside of this class context.
297
-		 *
298
-		 * @since 2.5.2
299
-		 *
300
-		 * @param string $name Name of an inaccessible property.
301
-		 * @return mixed The property value.
302
-		 */
303
-		public function __get( $name ) {
304
-			return $this->{$name};
305
-		}
306
-
307
-		/**
308
-		 * Initialise the interactions between this class and WordPress.
309
-		 *
310
-		 * Hooks in three new methods for the class: admin_menu, notices and styles.
311
-		 *
312
-		 * @since 2.0.0
313
-		 *
314
-		 * @see TGM_Plugin_Activation::admin_menu()
315
-		 * @see TGM_Plugin_Activation::notices()
316
-		 * @see TGM_Plugin_Activation::styles()
317
-		 */
318
-		public function init() {
319
-			/**
320
-			 * By default TGMPA only loads on the WP back-end and not in an Ajax call. Using this filter
321
-			 * you can overrule that behaviour.
322
-			 *
323
-			 * @since 2.5.0
324
-			 *
325
-			 * @param bool $load Whether or not TGMPA should load.
326
-			 *                   Defaults to the return of `is_admin() && ! defined( 'DOING_AJAX' )`.
327
-			 */
328
-			if ( true !== apply_filters( 'tgmpa_load', ( is_admin() && ! defined( 'DOING_AJAX' ) ) ) ) {
329
-				return;
330
-			}
331
-
332
-			// Load class strings.
333
-			$this->strings = array(
334
-				'page_title'                      => __( 'Install Required Plugins', 'tgmpa' ),
335
-				'menu_title'                      => __( 'Install Plugins', 'tgmpa' ),
336
-				/* translators: %s: plugin name. */
337
-				'installing'                      => __( 'Installing Plugin: %s', 'tgmpa' ),
338
-				/* translators: %s: plugin name. */
339
-				'updating'                        => __( 'Updating Plugin: %s', 'tgmpa' ),
340
-				'oops'                            => __( 'Something went wrong with the plugin API.', 'tgmpa' ),
341
-				'notice_can_install_required'     => _n_noop(
342
-					/* translators: 1: plugin name(s). */
343
-					'This theme requires the following plugin: %1$s.',
344
-					'This theme requires the following plugins: %1$s.',
345
-					'tgmpa'
346
-				),
347
-				'notice_can_install_recommended'  => _n_noop(
348
-					/* translators: 1: plugin name(s). */
349
-					'This theme recommends the following plugin: %1$s.',
350
-					'This theme recommends the following plugins: %1$s.',
351
-					'tgmpa'
352
-				),
353
-				'notice_ask_to_update'            => _n_noop(
354
-					/* translators: 1: plugin name(s). */
355
-					'The following plugin needs to be updated to its latest version to ensure maximum compatibility with this theme: %1$s.',
356
-					'The following plugins need to be updated to their latest version to ensure maximum compatibility with this theme: %1$s.',
357
-					'tgmpa'
358
-				),
359
-				'notice_ask_to_update_maybe'      => _n_noop(
360
-					/* translators: 1: plugin name(s). */
361
-					'There is an update available for: %1$s.',
362
-					'There are updates available for the following plugins: %1$s.',
363
-					'tgmpa'
364
-				),
365
-				'notice_can_activate_required'    => _n_noop(
366
-					/* translators: 1: plugin name(s). */
367
-					'The following required plugin is currently inactive: %1$s.',
368
-					'The following required plugins are currently inactive: %1$s.',
369
-					'tgmpa'
370
-				),
371
-				'notice_can_activate_recommended' => _n_noop(
372
-					/* translators: 1: plugin name(s). */
373
-					'The following recommended plugin is currently inactive: %1$s.',
374
-					'The following recommended plugins are currently inactive: %1$s.',
375
-					'tgmpa'
376
-				),
377
-				'install_link'                    => _n_noop(
378
-					'Begin installing plugin',
379
-					'Begin installing plugins',
380
-					'tgmpa'
381
-				),
382
-				'update_link'                     => _n_noop(
383
-					'Begin updating plugin',
384
-					'Begin updating plugins',
385
-					'tgmpa'
386
-				),
387
-				'activate_link'                   => _n_noop(
388
-					'Begin activating plugin',
389
-					'Begin activating plugins',
390
-					'tgmpa'
391
-				),
392
-				'return'                          => __( 'Return to Required Plugins Installer', 'tgmpa' ),
393
-				'dashboard'                       => __( 'Return to the Dashboard', 'tgmpa' ),
394
-				'plugin_activated'                => __( 'Plugin activated successfully.', 'tgmpa' ),
395
-				'activated_successfully'          => __( 'The following plugin was activated successfully:', 'tgmpa' ),
396
-				/* translators: 1: plugin name. */
397
-				'plugin_already_active'           => __( 'No action taken. Plugin %1$s was already active.', 'tgmpa' ),
398
-				/* translators: 1: plugin name. */
399
-				'plugin_needs_higher_version'     => __( 'Plugin not activated. A higher version of %s is needed for this theme. Please update the plugin.', 'tgmpa' ),
400
-				/* translators: 1: dashboard link. */
401
-				'complete'                        => __( 'All plugins installed and activated successfully. %1$s', 'tgmpa' ),
402
-				'dismiss'                         => __( 'Dismiss this notice', 'tgmpa' ),
403
-				'notice_cannot_install_activate'  => __( 'There are one or more required or recommended plugins to install, update or activate.', 'tgmpa' ),
404
-				'contact_admin'                   => __( 'Please contact the administrator of this site for help.', 'tgmpa' ),
405
-			);
406
-
407
-			do_action( 'tgmpa_register' );
408
-
409
-			/* After this point, the plugins should be registered and the configuration set. */
410
-
411
-			// Proceed only if we have plugins to handle.
412
-			if ( empty( $this->plugins ) || ! is_array( $this->plugins ) ) {
413
-				return;
414
-			}
415
-
416
-			// Set up the menu and notices if we still have outstanding actions.
417
-			if ( true !== $this->is_tgmpa_complete() ) {
418
-				// Sort the plugins.
419
-				array_multisort( $this->sort_order, SORT_ASC, $this->plugins );
420
-
421
-				add_action( 'admin_menu', array( $this, 'admin_menu' ) );
422
-				add_action( 'admin_head', array( $this, 'dismiss' ) );
423
-
424
-				// Prevent the normal links from showing underneath a single install/update page.
425
-				add_filter( 'install_plugin_complete_actions', array( $this, 'actions' ) );
426
-				add_filter( 'update_plugin_complete_actions', array( $this, 'actions' ) );
427
-
428
-				if ( $this->has_notices ) {
429
-					add_action( 'admin_notices', array( $this, 'notices' ) );
430
-					add_action( 'admin_init', array( $this, 'admin_init' ), 1 );
431
-					add_action( 'admin_enqueue_scripts', array( $this, 'thickbox' ) );
432
-				}
433
-			}
434
-
435
-			// If needed, filter plugin action links.
436
-			add_action( 'load-plugins.php', array( $this, 'add_plugin_action_link_filters' ), 1 );
437
-
438
-			// Make sure things get reset on switch theme.
439
-			add_action( 'switch_theme', array( $this, 'flush_plugins_cache' ) );
440
-
441
-			if ( $this->has_notices ) {
442
-				add_action( 'switch_theme', array( $this, 'update_dismiss' ) );
443
-			}
444
-
445
-			// Setup the force activation hook.
446
-			if ( true === $this->has_forced_activation ) {
447
-				add_action( 'admin_init', array( $this, 'force_activation' ) );
448
-			}
449
-
450
-			// Setup the force deactivation hook.
451
-			if ( true === $this->has_forced_deactivation ) {
452
-				add_action( 'switch_theme', array( $this, 'force_deactivation' ) );
453
-			}
454
-		}
455
-
456
-		/**
457
-		 * Load translations.
458
-		 *
459
-		 * @since 2.6.0
460
-		 *
461
-		 * (@internal Uses `load_theme_textdomain()` rather than `load_plugin_textdomain()` to
462
-		 * get round the different ways of handling the path and deprecated notices being thrown
463
-		 * and such. For plugins, the actual file name will be corrected by a filter.}}
464
-		 *
465
-		 * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
466
-		 * generator on the website.}}
467
-		 */
468
-		public function load_textdomain() {
469
-			if ( is_textdomain_loaded( 'tgmpa' ) ) {
470
-				return;
471
-			}
472
-
473
-			if ( false !== strpos( __FILE__, WP_PLUGIN_DIR ) || false !== strpos( __FILE__, WPMU_PLUGIN_DIR ) ) {
474
-				// Plugin, we'll need to adjust the file name.
475
-				add_action( 'load_textdomain_mofile', array( $this, 'correct_plugin_mofile' ), 10, 2 );
476
-				load_theme_textdomain( 'tgmpa', dirname( __FILE__ ) . '/languages' );
477
-				remove_action( 'load_textdomain_mofile', array( $this, 'correct_plugin_mofile' ), 10 );
478
-			} else {
479
-				load_theme_textdomain( 'tgmpa', dirname( __FILE__ ) . '/languages' );
480
-			}
481
-		}
482
-
483
-		/**
484
-		 * Correct the .mo file name for (must-use) plugins.
485
-		 *
486
-		 * Themese use `/path/{locale}.mo` while plugins use `/path/{text-domain}-{locale}.mo`.
487
-		 *
488
-		 * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
489
-		 * generator on the website.}}
490
-		 *
491
-		 * @since 2.6.0
492
-		 *
493
-		 * @param string $mofile Full path to the target mofile.
494
-		 * @param string $domain The domain for which a language file is being loaded.
495
-		 * @return string $mofile
496
-		 */
497
-		public function correct_plugin_mofile( $mofile, $domain ) {
498
-			// Exit early if not our domain (just in case).
499
-			if ( 'tgmpa' !== $domain ) {
500
-				return $mofile;
501
-			}
502
-			return preg_replace( '`/([a-z]{2}_[A-Z]{2}.mo)$`', '/tgmpa-$1', $mofile );
503
-		}
504
-
505
-		/**
506
-		 * Potentially overload the fall-back translation file for the current language.
507
-		 *
508
-		 * WP, by default since WP 3.7, will load a local translation first and if none
509
-		 * can be found, will try and find a translation in the /wp-content/languages/ directory.
510
-		 * As this library is theme/plugin agnostic, translation files for TGMPA can exist both
511
-		 * in the WP_LANG_DIR /plugins/ subdirectory as well as in the /themes/ subdirectory.
512
-		 *
513
-		 * This method makes sure both directories are checked.
514
-		 *
515
-		 * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
516
-		 * generator on the website.}}
517
-		 *
518
-		 * @since 2.6.0
519
-		 *
520
-		 * @param string $mofile Full path to the target mofile.
521
-		 * @param string $domain The domain for which a language file is being loaded.
522
-		 * @return string $mofile
523
-		 */
524
-		public function overload_textdomain_mofile( $mofile, $domain ) {
525
-			// Exit early if not our domain, not a WP_LANG_DIR load or if the file exists and is readable.
526
-			if ( 'tgmpa' !== $domain || false === strpos( $mofile, WP_LANG_DIR ) || @is_readable( $mofile ) ) {
527
-				return $mofile;
528
-			}
529
-
530
-			// Current fallback file is not valid, let's try the alternative option.
531
-			if ( false !== strpos( $mofile, '/themes/' ) ) {
532
-				return str_replace( '/themes/', '/plugins/', $mofile );
533
-			} elseif ( false !== strpos( $mofile, '/plugins/' ) ) {
534
-				return str_replace( '/plugins/', '/themes/', $mofile );
535
-			} else {
536
-				return $mofile;
537
-			}
538
-		}
539
-
540
-		/**
541
-		 * Hook in plugin action link filters for the WP native plugins page.
542
-		 *
543
-		 * - Prevent activation of plugins which don't meet the minimum version requirements.
544
-		 * - Prevent deactivation of force-activated plugins.
545
-		 * - Add update notice if update available.
546
-		 *
547
-		 * @since 2.5.0
548
-		 */
549
-		public function add_plugin_action_link_filters() {
550
-			foreach ( $this->plugins as $slug => $plugin ) {
551
-				if ( false === $this->can_plugin_activate( $slug ) ) {
552
-					add_filter( 'plugin_action_links_' . $plugin['file_path'], array( $this, 'filter_plugin_action_links_activate' ), 20 );
553
-				}
554
-
555
-				if ( true === $plugin['force_activation'] ) {
556
-					add_filter( 'plugin_action_links_' . $plugin['file_path'], array( $this, 'filter_plugin_action_links_deactivate' ), 20 );
557
-				}
558
-
559
-				if ( false !== $this->does_plugin_require_update( $slug ) ) {
560
-					add_filter( 'plugin_action_links_' . $plugin['file_path'], array( $this, 'filter_plugin_action_links_update' ), 20 );
561
-				}
562
-			}
563
-		}
564
-
565
-		/**
566
-		 * Remove the 'Activate' link on the WP native plugins page if the plugin does not meet the
567
-		 * minimum version requirements.
568
-		 *
569
-		 * @since 2.5.0
570
-		 *
571
-		 * @param array $actions Action links.
572
-		 * @return array
573
-		 */
574
-		public function filter_plugin_action_links_activate( $actions ) {
575
-			unset( $actions['activate'] );
576
-
577
-			return $actions;
578
-		}
579
-
580
-		/**
581
-		 * Remove the 'Deactivate' link on the WP native plugins page if the plugin has been set to force activate.
582
-		 *
583
-		 * @since 2.5.0
584
-		 *
585
-		 * @param array $actions Action links.
586
-		 * @return array
587
-		 */
588
-		public function filter_plugin_action_links_deactivate( $actions ) {
589
-			unset( $actions['deactivate'] );
590
-
591
-			return $actions;
592
-		}
593
-
594
-		/**
595
-		 * Add a 'Requires update' link on the WP native plugins page if the plugin does not meet the
596
-		 * minimum version requirements.
597
-		 *
598
-		 * @since 2.5.0
599
-		 *
600
-		 * @param array $actions Action links.
601
-		 * @return array
602
-		 */
603
-		public function filter_plugin_action_links_update( $actions ) {
604
-			$actions['update'] = sprintf(
605
-				'<a href="%1$s" title="%2$s" class="edit">%3$s</a>',
606
-				esc_url( $this->get_tgmpa_status_url( 'update' ) ),
607
-				esc_attr__( 'This plugin needs to be updated to be compatible with your theme.', 'tgmpa' ),
608
-				esc_html__( 'Update Required', 'tgmpa' )
609
-			);
610
-
611
-			return $actions;
612
-		}
613
-
614
-		/**
615
-		 * Handles calls to show plugin information via links in the notices.
616
-		 *
617
-		 * We get the links in the admin notices to point to the TGMPA page, rather
618
-		 * than the typical plugin-install.php file, so we can prepare everything
619
-		 * beforehand.
620
-		 *
621
-		 * WP does not make it easy to show the plugin information in the thickbox -
622
-		 * here we have to require a file that includes a function that does the
623
-		 * main work of displaying it, enqueue some styles, set up some globals and
624
-		 * finally call that function before exiting.
625
-		 *
626
-		 * Down right easy once you know how...
627
-		 *
628
-		 * Returns early if not the TGMPA page.
629
-		 *
630
-		 * @since 2.1.0
631
-		 *
632
-		 * @global string $tab Used as iframe div class names, helps with styling
633
-		 * @global string $body_id Used as the iframe body ID, helps with styling
634
-		 *
635
-		 * @return null Returns early if not the TGMPA page.
636
-		 */
637
-		public function admin_init() {
638
-			if ( ! $this->is_tgmpa_page() ) {
639
-				return;
640
-			}
641
-
642
-			if ( isset( $_REQUEST['tab'] ) && 'plugin-information' === $_REQUEST['tab'] ) {
643
-				// Needed for install_plugin_information().
644
-				require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
645
-
646
-				wp_enqueue_style( 'plugin-install' );
647
-
648
-				global $tab, $body_id;
649
-				$body_id = 'plugin-information';
650
-				// @codingStandardsIgnoreStart
651
-				$tab     = 'plugin-information';
652
-				// @codingStandardsIgnoreEnd
653
-
654
-				install_plugin_information();
655
-
656
-				exit;
657
-			}
658
-		}
659
-
660
-		/**
661
-		 * Enqueue thickbox scripts/styles for plugin info.
662
-		 *
663
-		 * Thickbox is not automatically included on all admin pages, so we must
664
-		 * manually enqueue it for those pages.
665
-		 *
666
-		 * Thickbox is only loaded if the user has not dismissed the admin
667
-		 * notice or if there are any plugins left to install and activate.
668
-		 *
669
-		 * @since 2.1.0
670
-		 */
671
-		public function thickbox() {
672
-			if ( ! get_user_meta( get_current_user_id(), 'tgmpa_dismissed_notice_' . $this->id, true ) ) {
673
-				add_thickbox();
674
-			}
675
-		}
676
-
677
-		/**
678
-		 * Adds submenu page if there are plugin actions to take.
679
-		 *
680
-		 * This method adds the submenu page letting users know that a required
681
-		 * plugin needs to be installed.
682
-		 *
683
-		 * This page disappears once the plugin has been installed and activated.
684
-		 *
685
-		 * @since 1.0.0
686
-		 *
687
-		 * @see TGM_Plugin_Activation::init()
688
-		 * @see TGM_Plugin_Activation::install_plugins_page()
689
-		 *
690
-		 * @return null Return early if user lacks capability to install a plugin.
691
-		 */
692
-		public function admin_menu() {
693
-			// Make sure privileges are correct to see the page.
694
-			if ( ! current_user_can( 'install_plugins' ) ) {
695
-				return;
696
-			}
697
-
698
-			$args = apply_filters(
699
-				'tgmpa_admin_menu_args',
700
-				array(
701
-					'parent_slug' => $this->parent_slug,                     // Parent Menu slug.
702
-					'page_title'  => $this->strings['page_title'],           // Page title.
703
-					'menu_title'  => $this->strings['menu_title'],           // Menu title.
704
-					'capability'  => $this->capability,                      // Capability.
705
-					'menu_slug'   => $this->menu,                            // Menu slug.
706
-					'function'    => array( $this, 'install_plugins_page' ), // Callback.
707
-				)
708
-			);
709
-
710
-			$this->add_admin_menu( $args );
711
-		}
712
-
713
-		/**
714
-		 * Add the menu item.
715
-		 *
716
-		 * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
717
-		 * generator on the website.}}
718
-		 *
719
-		 * @since 2.5.0
720
-		 *
721
-		 * @param array $args Menu item configuration.
722
-		 */
723
-		protected function add_admin_menu( array $args ) {
724
-			if ( has_filter( 'tgmpa_admin_menu_use_add_theme_page' ) ) {
725
-				_deprecated_function( 'The "tgmpa_admin_menu_use_add_theme_page" filter', '2.5.0', esc_html__( 'Set the parent_slug config variable instead.', 'tgmpa' ) );
726
-			}
727
-
728
-			if ( 'themes.php' === $this->parent_slug ) {
729
-				$this->page_hook = call_user_func( 'add_theme_page', $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
730
-			} else {
731
-				$this->page_hook = call_user_func( 'add_submenu_page', $args['parent_slug'], $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
732
-			}
733
-		}
734
-
735
-		/**
736
-		 * Echoes plugin installation form.
737
-		 *
738
-		 * This method is the callback for the admin_menu method function.
739
-		 * This displays the admin page and form area where the user can select to install and activate the plugin.
740
-		 * Aborts early if we're processing a plugin installation action.
741
-		 *
742
-		 * @since 1.0.0
743
-		 *
744
-		 * @return null Aborts early if we're processing a plugin installation action.
745
-		 */
746
-		public function install_plugins_page() {
747
-			// Store new instance of plugin table in object.
748
-			$plugin_table = new TGMPA_List_Table;
749
-
750
-			// Return early if processing a plugin installation action.
751
-			if ( ( ( 'tgmpa-bulk-install' === $plugin_table->current_action() || 'tgmpa-bulk-update' === $plugin_table->current_action() ) && $plugin_table->process_bulk_actions() ) || $this->do_plugin_install() ) {
752
-				return;
753
-			}
754
-
755
-			// Force refresh of available plugin information so we'll know about manual updates/deletes.
756
-			wp_clean_plugins_cache( false );
757
-
758
-			?>
268
+            add_action( 'init', array( $this, 'load_textdomain' ), 5 );
269
+            add_filter( 'load_textdomain_mofile', array( $this, 'overload_textdomain_mofile' ), 10, 2 );
270
+
271
+            // When the rest of WP has loaded, kick-start the rest of the class.
272
+            add_action( 'init', array( $this, 'init' ) );
273
+        }
274
+
275
+        /**
276
+         * Magic method to (not) set protected properties from outside of this class.
277
+         *
278
+         * {@internal hackedihack... There is a serious bug in v2.3.2 - 2.3.6  where the `menu` property
279
+         * is being assigned rather than tested in a conditional, effectively rendering it useless.
280
+         * This 'hack' prevents this from happening.}}
281
+         *
282
+         * @see https://github.com/TGMPA/TGM-Plugin-Activation/blob/2.3.6/tgm-plugin-activation/class-tgm-plugin-activation.php#L1593
283
+         *
284
+         * @since 2.5.2
285
+         *
286
+         * @param string $name  Name of an inaccessible property.
287
+         * @param mixed  $value Value to assign to the property.
288
+         * @return void  Silently fail to set the property when this is tried from outside of this class context.
289
+         *               (Inside this class context, the __set() method if not used as there is direct access.)
290
+         */
291
+        public function __set( $name, $value ) {
292
+            return;
293
+        }
294
+
295
+        /**
296
+         * Magic method to get the value of a protected property outside of this class context.
297
+         *
298
+         * @since 2.5.2
299
+         *
300
+         * @param string $name Name of an inaccessible property.
301
+         * @return mixed The property value.
302
+         */
303
+        public function __get( $name ) {
304
+            return $this->{$name};
305
+        }
306
+
307
+        /**
308
+         * Initialise the interactions between this class and WordPress.
309
+         *
310
+         * Hooks in three new methods for the class: admin_menu, notices and styles.
311
+         *
312
+         * @since 2.0.0
313
+         *
314
+         * @see TGM_Plugin_Activation::admin_menu()
315
+         * @see TGM_Plugin_Activation::notices()
316
+         * @see TGM_Plugin_Activation::styles()
317
+         */
318
+        public function init() {
319
+            /**
320
+             * By default TGMPA only loads on the WP back-end and not in an Ajax call. Using this filter
321
+             * you can overrule that behaviour.
322
+             *
323
+             * @since 2.5.0
324
+             *
325
+             * @param bool $load Whether or not TGMPA should load.
326
+             *                   Defaults to the return of `is_admin() && ! defined( 'DOING_AJAX' )`.
327
+             */
328
+            if ( true !== apply_filters( 'tgmpa_load', ( is_admin() && ! defined( 'DOING_AJAX' ) ) ) ) {
329
+                return;
330
+            }
331
+
332
+            // Load class strings.
333
+            $this->strings = array(
334
+                'page_title'                      => __( 'Install Required Plugins', 'tgmpa' ),
335
+                'menu_title'                      => __( 'Install Plugins', 'tgmpa' ),
336
+                /* translators: %s: plugin name. */
337
+                'installing'                      => __( 'Installing Plugin: %s', 'tgmpa' ),
338
+                /* translators: %s: plugin name. */
339
+                'updating'                        => __( 'Updating Plugin: %s', 'tgmpa' ),
340
+                'oops'                            => __( 'Something went wrong with the plugin API.', 'tgmpa' ),
341
+                'notice_can_install_required'     => _n_noop(
342
+                    /* translators: 1: plugin name(s). */
343
+                    'This theme requires the following plugin: %1$s.',
344
+                    'This theme requires the following plugins: %1$s.',
345
+                    'tgmpa'
346
+                ),
347
+                'notice_can_install_recommended'  => _n_noop(
348
+                    /* translators: 1: plugin name(s). */
349
+                    'This theme recommends the following plugin: %1$s.',
350
+                    'This theme recommends the following plugins: %1$s.',
351
+                    'tgmpa'
352
+                ),
353
+                'notice_ask_to_update'            => _n_noop(
354
+                    /* translators: 1: plugin name(s). */
355
+                    'The following plugin needs to be updated to its latest version to ensure maximum compatibility with this theme: %1$s.',
356
+                    'The following plugins need to be updated to their latest version to ensure maximum compatibility with this theme: %1$s.',
357
+                    'tgmpa'
358
+                ),
359
+                'notice_ask_to_update_maybe'      => _n_noop(
360
+                    /* translators: 1: plugin name(s). */
361
+                    'There is an update available for: %1$s.',
362
+                    'There are updates available for the following plugins: %1$s.',
363
+                    'tgmpa'
364
+                ),
365
+                'notice_can_activate_required'    => _n_noop(
366
+                    /* translators: 1: plugin name(s). */
367
+                    'The following required plugin is currently inactive: %1$s.',
368
+                    'The following required plugins are currently inactive: %1$s.',
369
+                    'tgmpa'
370
+                ),
371
+                'notice_can_activate_recommended' => _n_noop(
372
+                    /* translators: 1: plugin name(s). */
373
+                    'The following recommended plugin is currently inactive: %1$s.',
374
+                    'The following recommended plugins are currently inactive: %1$s.',
375
+                    'tgmpa'
376
+                ),
377
+                'install_link'                    => _n_noop(
378
+                    'Begin installing plugin',
379
+                    'Begin installing plugins',
380
+                    'tgmpa'
381
+                ),
382
+                'update_link'                     => _n_noop(
383
+                    'Begin updating plugin',
384
+                    'Begin updating plugins',
385
+                    'tgmpa'
386
+                ),
387
+                'activate_link'                   => _n_noop(
388
+                    'Begin activating plugin',
389
+                    'Begin activating plugins',
390
+                    'tgmpa'
391
+                ),
392
+                'return'                          => __( 'Return to Required Plugins Installer', 'tgmpa' ),
393
+                'dashboard'                       => __( 'Return to the Dashboard', 'tgmpa' ),
394
+                'plugin_activated'                => __( 'Plugin activated successfully.', 'tgmpa' ),
395
+                'activated_successfully'          => __( 'The following plugin was activated successfully:', 'tgmpa' ),
396
+                /* translators: 1: plugin name. */
397
+                'plugin_already_active'           => __( 'No action taken. Plugin %1$s was already active.', 'tgmpa' ),
398
+                /* translators: 1: plugin name. */
399
+                'plugin_needs_higher_version'     => __( 'Plugin not activated. A higher version of %s is needed for this theme. Please update the plugin.', 'tgmpa' ),
400
+                /* translators: 1: dashboard link. */
401
+                'complete'                        => __( 'All plugins installed and activated successfully. %1$s', 'tgmpa' ),
402
+                'dismiss'                         => __( 'Dismiss this notice', 'tgmpa' ),
403
+                'notice_cannot_install_activate'  => __( 'There are one or more required or recommended plugins to install, update or activate.', 'tgmpa' ),
404
+                'contact_admin'                   => __( 'Please contact the administrator of this site for help.', 'tgmpa' ),
405
+            );
406
+
407
+            do_action( 'tgmpa_register' );
408
+
409
+            /* After this point, the plugins should be registered and the configuration set. */
410
+
411
+            // Proceed only if we have plugins to handle.
412
+            if ( empty( $this->plugins ) || ! is_array( $this->plugins ) ) {
413
+                return;
414
+            }
415
+
416
+            // Set up the menu and notices if we still have outstanding actions.
417
+            if ( true !== $this->is_tgmpa_complete() ) {
418
+                // Sort the plugins.
419
+                array_multisort( $this->sort_order, SORT_ASC, $this->plugins );
420
+
421
+                add_action( 'admin_menu', array( $this, 'admin_menu' ) );
422
+                add_action( 'admin_head', array( $this, 'dismiss' ) );
423
+
424
+                // Prevent the normal links from showing underneath a single install/update page.
425
+                add_filter( 'install_plugin_complete_actions', array( $this, 'actions' ) );
426
+                add_filter( 'update_plugin_complete_actions', array( $this, 'actions' ) );
427
+
428
+                if ( $this->has_notices ) {
429
+                    add_action( 'admin_notices', array( $this, 'notices' ) );
430
+                    add_action( 'admin_init', array( $this, 'admin_init' ), 1 );
431
+                    add_action( 'admin_enqueue_scripts', array( $this, 'thickbox' ) );
432
+                }
433
+            }
434
+
435
+            // If needed, filter plugin action links.
436
+            add_action( 'load-plugins.php', array( $this, 'add_plugin_action_link_filters' ), 1 );
437
+
438
+            // Make sure things get reset on switch theme.
439
+            add_action( 'switch_theme', array( $this, 'flush_plugins_cache' ) );
440
+
441
+            if ( $this->has_notices ) {
442
+                add_action( 'switch_theme', array( $this, 'update_dismiss' ) );
443
+            }
444
+
445
+            // Setup the force activation hook.
446
+            if ( true === $this->has_forced_activation ) {
447
+                add_action( 'admin_init', array( $this, 'force_activation' ) );
448
+            }
449
+
450
+            // Setup the force deactivation hook.
451
+            if ( true === $this->has_forced_deactivation ) {
452
+                add_action( 'switch_theme', array( $this, 'force_deactivation' ) );
453
+            }
454
+        }
455
+
456
+        /**
457
+         * Load translations.
458
+         *
459
+         * @since 2.6.0
460
+         *
461
+         * (@internal Uses `load_theme_textdomain()` rather than `load_plugin_textdomain()` to
462
+         * get round the different ways of handling the path and deprecated notices being thrown
463
+         * and such. For plugins, the actual file name will be corrected by a filter.}}
464
+         *
465
+         * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
466
+         * generator on the website.}}
467
+         */
468
+        public function load_textdomain() {
469
+            if ( is_textdomain_loaded( 'tgmpa' ) ) {
470
+                return;
471
+            }
472
+
473
+            if ( false !== strpos( __FILE__, WP_PLUGIN_DIR ) || false !== strpos( __FILE__, WPMU_PLUGIN_DIR ) ) {
474
+                // Plugin, we'll need to adjust the file name.
475
+                add_action( 'load_textdomain_mofile', array( $this, 'correct_plugin_mofile' ), 10, 2 );
476
+                load_theme_textdomain( 'tgmpa', dirname( __FILE__ ) . '/languages' );
477
+                remove_action( 'load_textdomain_mofile', array( $this, 'correct_plugin_mofile' ), 10 );
478
+            } else {
479
+                load_theme_textdomain( 'tgmpa', dirname( __FILE__ ) . '/languages' );
480
+            }
481
+        }
482
+
483
+        /**
484
+         * Correct the .mo file name for (must-use) plugins.
485
+         *
486
+         * Themese use `/path/{locale}.mo` while plugins use `/path/{text-domain}-{locale}.mo`.
487
+         *
488
+         * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
489
+         * generator on the website.}}
490
+         *
491
+         * @since 2.6.0
492
+         *
493
+         * @param string $mofile Full path to the target mofile.
494
+         * @param string $domain The domain for which a language file is being loaded.
495
+         * @return string $mofile
496
+         */
497
+        public function correct_plugin_mofile( $mofile, $domain ) {
498
+            // Exit early if not our domain (just in case).
499
+            if ( 'tgmpa' !== $domain ) {
500
+                return $mofile;
501
+            }
502
+            return preg_replace( '`/([a-z]{2}_[A-Z]{2}.mo)$`', '/tgmpa-$1', $mofile );
503
+        }
504
+
505
+        /**
506
+         * Potentially overload the fall-back translation file for the current language.
507
+         *
508
+         * WP, by default since WP 3.7, will load a local translation first and if none
509
+         * can be found, will try and find a translation in the /wp-content/languages/ directory.
510
+         * As this library is theme/plugin agnostic, translation files for TGMPA can exist both
511
+         * in the WP_LANG_DIR /plugins/ subdirectory as well as in the /themes/ subdirectory.
512
+         *
513
+         * This method makes sure both directories are checked.
514
+         *
515
+         * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
516
+         * generator on the website.}}
517
+         *
518
+         * @since 2.6.0
519
+         *
520
+         * @param string $mofile Full path to the target mofile.
521
+         * @param string $domain The domain for which a language file is being loaded.
522
+         * @return string $mofile
523
+         */
524
+        public function overload_textdomain_mofile( $mofile, $domain ) {
525
+            // Exit early if not our domain, not a WP_LANG_DIR load or if the file exists and is readable.
526
+            if ( 'tgmpa' !== $domain || false === strpos( $mofile, WP_LANG_DIR ) || @is_readable( $mofile ) ) {
527
+                return $mofile;
528
+            }
529
+
530
+            // Current fallback file is not valid, let's try the alternative option.
531
+            if ( false !== strpos( $mofile, '/themes/' ) ) {
532
+                return str_replace( '/themes/', '/plugins/', $mofile );
533
+            } elseif ( false !== strpos( $mofile, '/plugins/' ) ) {
534
+                return str_replace( '/plugins/', '/themes/', $mofile );
535
+            } else {
536
+                return $mofile;
537
+            }
538
+        }
539
+
540
+        /**
541
+         * Hook in plugin action link filters for the WP native plugins page.
542
+         *
543
+         * - Prevent activation of plugins which don't meet the minimum version requirements.
544
+         * - Prevent deactivation of force-activated plugins.
545
+         * - Add update notice if update available.
546
+         *
547
+         * @since 2.5.0
548
+         */
549
+        public function add_plugin_action_link_filters() {
550
+            foreach ( $this->plugins as $slug => $plugin ) {
551
+                if ( false === $this->can_plugin_activate( $slug ) ) {
552
+                    add_filter( 'plugin_action_links_' . $plugin['file_path'], array( $this, 'filter_plugin_action_links_activate' ), 20 );
553
+                }
554
+
555
+                if ( true === $plugin['force_activation'] ) {
556
+                    add_filter( 'plugin_action_links_' . $plugin['file_path'], array( $this, 'filter_plugin_action_links_deactivate' ), 20 );
557
+                }
558
+
559
+                if ( false !== $this->does_plugin_require_update( $slug ) ) {
560
+                    add_filter( 'plugin_action_links_' . $plugin['file_path'], array( $this, 'filter_plugin_action_links_update' ), 20 );
561
+                }
562
+            }
563
+        }
564
+
565
+        /**
566
+         * Remove the 'Activate' link on the WP native plugins page if the plugin does not meet the
567
+         * minimum version requirements.
568
+         *
569
+         * @since 2.5.0
570
+         *
571
+         * @param array $actions Action links.
572
+         * @return array
573
+         */
574
+        public function filter_plugin_action_links_activate( $actions ) {
575
+            unset( $actions['activate'] );
576
+
577
+            return $actions;
578
+        }
579
+
580
+        /**
581
+         * Remove the 'Deactivate' link on the WP native plugins page if the plugin has been set to force activate.
582
+         *
583
+         * @since 2.5.0
584
+         *
585
+         * @param array $actions Action links.
586
+         * @return array
587
+         */
588
+        public function filter_plugin_action_links_deactivate( $actions ) {
589
+            unset( $actions['deactivate'] );
590
+
591
+            return $actions;
592
+        }
593
+
594
+        /**
595
+         * Add a 'Requires update' link on the WP native plugins page if the plugin does not meet the
596
+         * minimum version requirements.
597
+         *
598
+         * @since 2.5.0
599
+         *
600
+         * @param array $actions Action links.
601
+         * @return array
602
+         */
603
+        public function filter_plugin_action_links_update( $actions ) {
604
+            $actions['update'] = sprintf(
605
+                '<a href="%1$s" title="%2$s" class="edit">%3$s</a>',
606
+                esc_url( $this->get_tgmpa_status_url( 'update' ) ),
607
+                esc_attr__( 'This plugin needs to be updated to be compatible with your theme.', 'tgmpa' ),
608
+                esc_html__( 'Update Required', 'tgmpa' )
609
+            );
610
+
611
+            return $actions;
612
+        }
613
+
614
+        /**
615
+         * Handles calls to show plugin information via links in the notices.
616
+         *
617
+         * We get the links in the admin notices to point to the TGMPA page, rather
618
+         * than the typical plugin-install.php file, so we can prepare everything
619
+         * beforehand.
620
+         *
621
+         * WP does not make it easy to show the plugin information in the thickbox -
622
+         * here we have to require a file that includes a function that does the
623
+         * main work of displaying it, enqueue some styles, set up some globals and
624
+         * finally call that function before exiting.
625
+         *
626
+         * Down right easy once you know how...
627
+         *
628
+         * Returns early if not the TGMPA page.
629
+         *
630
+         * @since 2.1.0
631
+         *
632
+         * @global string $tab Used as iframe div class names, helps with styling
633
+         * @global string $body_id Used as the iframe body ID, helps with styling
634
+         *
635
+         * @return null Returns early if not the TGMPA page.
636
+         */
637
+        public function admin_init() {
638
+            if ( ! $this->is_tgmpa_page() ) {
639
+                return;
640
+            }
641
+
642
+            if ( isset( $_REQUEST['tab'] ) && 'plugin-information' === $_REQUEST['tab'] ) {
643
+                // Needed for install_plugin_information().
644
+                require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
645
+
646
+                wp_enqueue_style( 'plugin-install' );
647
+
648
+                global $tab, $body_id;
649
+                $body_id = 'plugin-information';
650
+                // @codingStandardsIgnoreStart
651
+                $tab     = 'plugin-information';
652
+                // @codingStandardsIgnoreEnd
653
+
654
+                install_plugin_information();
655
+
656
+                exit;
657
+            }
658
+        }
659
+
660
+        /**
661
+         * Enqueue thickbox scripts/styles for plugin info.
662
+         *
663
+         * Thickbox is not automatically included on all admin pages, so we must
664
+         * manually enqueue it for those pages.
665
+         *
666
+         * Thickbox is only loaded if the user has not dismissed the admin
667
+         * notice or if there are any plugins left to install and activate.
668
+         *
669
+         * @since 2.1.0
670
+         */
671
+        public function thickbox() {
672
+            if ( ! get_user_meta( get_current_user_id(), 'tgmpa_dismissed_notice_' . $this->id, true ) ) {
673
+                add_thickbox();
674
+            }
675
+        }
676
+
677
+        /**
678
+         * Adds submenu page if there are plugin actions to take.
679
+         *
680
+         * This method adds the submenu page letting users know that a required
681
+         * plugin needs to be installed.
682
+         *
683
+         * This page disappears once the plugin has been installed and activated.
684
+         *
685
+         * @since 1.0.0
686
+         *
687
+         * @see TGM_Plugin_Activation::init()
688
+         * @see TGM_Plugin_Activation::install_plugins_page()
689
+         *
690
+         * @return null Return early if user lacks capability to install a plugin.
691
+         */
692
+        public function admin_menu() {
693
+            // Make sure privileges are correct to see the page.
694
+            if ( ! current_user_can( 'install_plugins' ) ) {
695
+                return;
696
+            }
697
+
698
+            $args = apply_filters(
699
+                'tgmpa_admin_menu_args',
700
+                array(
701
+                    'parent_slug' => $this->parent_slug,                     // Parent Menu slug.
702
+                    'page_title'  => $this->strings['page_title'],           // Page title.
703
+                    'menu_title'  => $this->strings['menu_title'],           // Menu title.
704
+                    'capability'  => $this->capability,                      // Capability.
705
+                    'menu_slug'   => $this->menu,                            // Menu slug.
706
+                    'function'    => array( $this, 'install_plugins_page' ), // Callback.
707
+                )
708
+            );
709
+
710
+            $this->add_admin_menu( $args );
711
+        }
712
+
713
+        /**
714
+         * Add the menu item.
715
+         *
716
+         * {@internal IMPORTANT! If this function changes, review the regex in the custom TGMPA
717
+         * generator on the website.}}
718
+         *
719
+         * @since 2.5.0
720
+         *
721
+         * @param array $args Menu item configuration.
722
+         */
723
+        protected function add_admin_menu( array $args ) {
724
+            if ( has_filter( 'tgmpa_admin_menu_use_add_theme_page' ) ) {
725
+                _deprecated_function( 'The "tgmpa_admin_menu_use_add_theme_page" filter', '2.5.0', esc_html__( 'Set the parent_slug config variable instead.', 'tgmpa' ) );
726
+            }
727
+
728
+            if ( 'themes.php' === $this->parent_slug ) {
729
+                $this->page_hook = call_user_func( 'add_theme_page', $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
730
+            } else {
731
+                $this->page_hook = call_user_func( 'add_submenu_page', $args['parent_slug'], $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
732
+            }
733
+        }
734
+
735
+        /**
736
+         * Echoes plugin installation form.
737
+         *
738
+         * This method is the callback for the admin_menu method function.
739
+         * This displays the admin page and form area where the user can select to install and activate the plugin.
740
+         * Aborts early if we're processing a plugin installation action.
741
+         *
742
+         * @since 1.0.0
743
+         *
744
+         * @return null Aborts early if we're processing a plugin installation action.
745
+         */
746
+        public function install_plugins_page() {
747
+            // Store new instance of plugin table in object.
748
+            $plugin_table = new TGMPA_List_Table;
749
+
750
+            // Return early if processing a plugin installation action.
751
+            if ( ( ( 'tgmpa-bulk-install' === $plugin_table->current_action() || 'tgmpa-bulk-update' === $plugin_table->current_action() ) && $plugin_table->process_bulk_actions() ) || $this->do_plugin_install() ) {
752
+                return;
753
+            }
754
+
755
+            // Force refresh of available plugin information so we'll know about manual updates/deletes.
756
+            wp_clean_plugins_cache( false );
757
+
758
+            ?>
759 759
 			<div class="tgmpa wrap">
760 760
 				<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
761 761
 				<?php $plugin_table->prepare_items(); ?>
762 762
 
763 763
 				<?php
764
-				if ( ! empty( $this->message ) && is_string( $this->message ) ) {
765
-					echo wp_kses_post( $this->message );
766
-				}
767
-				?>
764
+                if ( ! empty( $this->message ) && is_string( $this->message ) ) {
765
+                    echo wp_kses_post( $this->message );
766
+                }
767
+                ?>
768 768
 				<?php $plugin_table->views(); ?>
769 769
 
770 770
 				<form id="tgmpa-plugins" action="" method="post">
@@ -774,1381 +774,1381 @@  discard block
 block discarded – undo
774 774
 				</form>
775 775
 			</div>
776 776
 			<?php
777
-		}
778
-
779
-		/**
780
-		 * Installs, updates or activates a plugin depending on the action link clicked by the user.
781
-		 *
782
-		 * Checks the $_GET variable to see which actions have been
783
-		 * passed and responds with the appropriate method.
784
-		 *
785
-		 * Uses WP_Filesystem to process and handle the plugin installation
786
-		 * method.
787
-		 *
788
-		 * @since 1.0.0
789
-		 *
790
-		 * @uses WP_Filesystem
791
-		 * @uses WP_Error
792
-		 * @uses WP_Upgrader
793
-		 * @uses Plugin_Upgrader
794
-		 * @uses Plugin_Installer_Skin
795
-		 * @uses Plugin_Upgrader_Skin
796
-		 *
797
-		 * @return boolean True on success, false on failure.
798
-		 */
799
-		protected function do_plugin_install() {
800
-			if ( empty( $_GET['plugin'] ) ) {
801
-				return false;
802
-			}
803
-
804
-			// All plugin information will be stored in an array for processing.
805
-			$slug = $this->sanitize_key( urldecode( $_GET['plugin'] ) );
806
-
807
-			if ( ! isset( $this->plugins[ $slug ] ) ) {
808
-				return false;
809
-			}
810
-
811
-			// Was an install or upgrade action link clicked?
812
-			if ( ( isset( $_GET['tgmpa-install'] ) && 'install-plugin' === $_GET['tgmpa-install'] ) || ( isset( $_GET['tgmpa-update'] ) && 'update-plugin' === $_GET['tgmpa-update'] ) ) {
813
-
814
-				$install_type = 'install';
815
-				if ( isset( $_GET['tgmpa-update'] ) && 'update-plugin' === $_GET['tgmpa-update'] ) {
816
-					$install_type = 'update';
817
-				}
818
-
819
-				check_admin_referer( 'tgmpa-' . $install_type, 'tgmpa-nonce' );
820
-
821
-				// Pass necessary information via URL if WP_Filesystem is needed.
822
-				$url = wp_nonce_url(
823
-					add_query_arg(
824
-						array(
825
-							'plugin'                 => urlencode( $slug ),
826
-							'tgmpa-' . $install_type => $install_type . '-plugin',
827
-						),
828
-						$this->get_tgmpa_url()
829
-					),
830
-					'tgmpa-' . $install_type,
831
-					'tgmpa-nonce'
832
-				);
833
-
834
-				$method = ''; // Leave blank so WP_Filesystem can populate it as necessary.
835
-
836
-				if ( false === ( $creds = request_filesystem_credentials( esc_url_raw( $url ), $method, false, false, array() ) ) ) {
837
-					return true;
838
-				}
839
-
840
-				if ( ! WP_Filesystem( $creds ) ) {
841
-					request_filesystem_credentials( esc_url_raw( $url ), $method, true, false, array() ); // Setup WP_Filesystem.
842
-					return true;
843
-				}
844
-
845
-				/* If we arrive here, we have the filesystem. */
846
-
847
-				// Prep variables for Plugin_Installer_Skin class.
848
-				$extra         = array();
849
-				$extra['slug'] = $slug; // Needed for potentially renaming of directory name.
850
-				$source        = $this->get_download_url( $slug );
851
-				$api           = ( 'repo' === $this->plugins[ $slug ]['source_type'] ) ? $this->get_plugins_api( $slug ) : null;
852
-				$api           = ( false !== $api ) ? $api : null;
853
-
854
-				$url = add_query_arg(
855
-					array(
856
-						'action' => $install_type . '-plugin',
857
-						'plugin' => urlencode( $slug ),
858
-					),
859
-					'update.php'
860
-				);
861
-
862
-				if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
863
-					require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
864
-				}
865
-
866
-				$title     = ( 'update' === $install_type ) ? $this->strings['updating'] : $this->strings['installing'];
867
-				$skin_args = array(
868
-					'type'   => ( 'bundled' !== $this->plugins[ $slug ]['source_type'] ) ? 'web' : 'upload',
869
-					'title'  => sprintf( $title, $this->plugins[ $slug ]['name'] ),
870
-					'url'    => esc_url_raw( $url ),
871
-					'nonce'  => $install_type . '-plugin_' . $slug,
872
-					'plugin' => '',
873
-					'api'    => $api,
874
-					'extra'  => $extra,
875
-				);
876
-				unset( $title );
877
-
878
-				if ( 'update' === $install_type ) {
879
-					$skin_args['plugin'] = $this->plugins[ $slug ]['file_path'];
880
-					$skin                = new Plugin_Upgrader_Skin( $skin_args );
881
-				} else {
882
-					$skin = new Plugin_Installer_Skin( $skin_args );
883
-				}
884
-
885
-				// Create a new instance of Plugin_Upgrader.
886
-				$upgrader = new Plugin_Upgrader( $skin );
887
-
888
-				// Perform the action and install the plugin from the $source urldecode().
889
-				add_filter( 'upgrader_source_selection', array( $this, 'maybe_adjust_source_dir' ), 1, 3 );
890
-
891
-				if ( 'update' === $install_type ) {
892
-					// Inject our info into the update transient.
893
-					$to_inject                    = array( $slug => $this->plugins[ $slug ] );
894
-					$to_inject[ $slug ]['source'] = $source;
895
-					$this->inject_update_info( $to_inject );
896
-
897
-					$upgrader->upgrade( $this->plugins[ $slug ]['file_path'] );
898
-				} else {
899
-					$upgrader->install( $source );
900
-				}
901
-
902
-				remove_filter( 'upgrader_source_selection', array( $this, 'maybe_adjust_source_dir' ), 1 );
903
-
904
-				// Make sure we have the correct file path now the plugin is installed/updated.
905
-				$this->populate_file_path( $slug );
906
-
907
-				// Only activate plugins if the config option is set to true and the plugin isn't
908
-				// already active (upgrade).
909
-				if ( $this->is_automatic && ! $this->is_plugin_active( $slug ) ) {
910
-					$plugin_activate = $upgrader->plugin_info(); // Grab the plugin info from the Plugin_Upgrader method.
911
-					if ( false === $this->activate_single_plugin( $plugin_activate, $slug, true ) ) {
912
-						return true; // Finish execution of the function early as we encountered an error.
913
-					}
914
-				}
915
-
916
-				$this->show_tgmpa_version();
917
-
918
-				// Display message based on if all plugins are now active or not.
919
-				if ( $this->is_tgmpa_complete() ) {
920
-					echo '<p>', sprintf( esc_html( $this->strings['complete'] ), '<a href="' . esc_url( self_admin_url() ) . '">' . esc_html__( 'Return to the Dashboard', 'tgmpa' ) . '</a>' ), '</p>';
921
-					echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>';
922
-				} else {
923
-					echo '<p><a href="', esc_url( $this->get_tgmpa_url() ), '" target="_parent">', esc_html( $this->strings['return'] ), '</a></p>';
924
-				}
925
-
926
-				return true;
927
-			} elseif ( isset( $this->plugins[ $slug ]['file_path'], $_GET['tgmpa-activate'] ) && 'activate-plugin' === $_GET['tgmpa-activate'] ) {
928
-				// Activate action link was clicked.
929
-				check_admin_referer( 'tgmpa-activate', 'tgmpa-nonce' );
930
-
931
-				if ( false === $this->activate_single_plugin( $this->plugins[ $slug ]['file_path'], $slug ) ) {
932
-					return true; // Finish execution of the function early as we encountered an error.
933
-				}
934
-			}
935
-
936
-			return false;
937
-		}
938
-
939
-		/**
940
-		 * Inject information into the 'update_plugins' site transient as WP checks that before running an update.
941
-		 *
942
-		 * @since 2.5.0
943
-		 *
944
-		 * @param array $plugins The plugin information for the plugins which are to be updated.
945
-		 */
946
-		public function inject_update_info( $plugins ) {
947
-			$repo_updates = get_site_transient( 'update_plugins' );
948
-
949
-			if ( ! is_object( $repo_updates ) ) {
950
-				$repo_updates = new stdClass;
951
-			}
952
-
953
-			foreach ( $plugins as $slug => $plugin ) {
954
-				$file_path = $plugin['file_path'];
955
-
956
-				if ( empty( $repo_updates->response[ $file_path ] ) ) {
957
-					$repo_updates->response[ $file_path ] = new stdClass;
958
-				}
959
-
960
-				// We only really need to set package, but let's do all we can in case WP changes something.
961
-				$repo_updates->response[ $file_path ]->slug        = $slug;
962
-				$repo_updates->response[ $file_path ]->plugin      = $file_path;
963
-				$repo_updates->response[ $file_path ]->new_version = $plugin['version'];
964
-				$repo_updates->response[ $file_path ]->package     = $plugin['source'];
965
-				if ( empty( $repo_updates->response[ $file_path ]->url ) && ! empty( $plugin['external_url'] ) ) {
966
-					$repo_updates->response[ $file_path ]->url = $plugin['external_url'];
967
-				}
968
-			}
969
-
970
-			set_site_transient( 'update_plugins', $repo_updates );
971
-		}
972
-
973
-		/**
974
-		 * Adjust the plugin directory name if necessary.
975
-		 *
976
-		 * The final destination directory of a plugin is based on the subdirectory name found in the
977
-		 * (un)zipped source. In some cases - most notably GitHub repository plugin downloads -, this
978
-		 * subdirectory name is not the same as the expected slug and the plugin will not be recognized
979
-		 * as installed. This is fixed by adjusting the temporary unzipped source subdirectory name to
980
-		 * the expected plugin slug.
981
-		 *
982
-		 * @since 2.5.0
983
-		 *
984
-		 * @param string       $source        Path to upgrade/zip-file-name.tmp/subdirectory/.
985
-		 * @param string       $remote_source Path to upgrade/zip-file-name.tmp.
986
-		 * @param \WP_Upgrader $upgrader      Instance of the upgrader which installs the plugin.
987
-		 * @return string $source
988
-		 */
989
-		public function maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
990
-			if ( ! $this->is_tgmpa_page() || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
991
-				return $source;
992
-			}
993
-
994
-			// Check for single file plugins.
995
-			$source_files = array_keys( $GLOBALS['wp_filesystem']->dirlist( $remote_source ) );
996
-			if ( 1 === count( $source_files ) && false === $GLOBALS['wp_filesystem']->is_dir( $source ) ) {
997
-				return $source;
998
-			}
999
-
1000
-			// Multi-file plugin, let's see if the directory is correctly named.
1001
-			$desired_slug = '';
1002
-
1003
-			// Figure out what the slug is supposed to be.
1004
-			if ( false === $upgrader->bulk && ! empty( $upgrader->skin->options['extra']['slug'] ) ) {
1005
-				$desired_slug = $upgrader->skin->options['extra']['slug'];
1006
-			} else {
1007
-				// Bulk installer contains less info, so fall back on the info registered here.
1008
-				foreach ( $this->plugins as $slug => $plugin ) {
1009
-					if ( ! empty( $upgrader->skin->plugin_names[ $upgrader->skin->i ] ) && $plugin['name'] === $upgrader->skin->plugin_names[ $upgrader->skin->i ] ) {
1010
-						$desired_slug = $slug;
1011
-						break;
1012
-					}
1013
-				}
1014
-				unset( $slug, $plugin );
1015
-			}
1016
-
1017
-			if ( ! empty( $desired_slug ) ) {
1018
-				$subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
1019
-
1020
-				if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
1021
-					$from_path = untrailingslashit( $source );
1022
-					$to_path   = trailingslashit( $remote_source ) . $desired_slug;
1023
-
1024
-					if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
1025
-						return trailingslashit( $to_path );
1026
-					} else {
1027
-						return new WP_Error( 'rename_failed', esc_html__( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'tgmpa' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'tgmpa' ), array( 'found' => $subdir_name, 'expected' => $desired_slug ) );
1028
-					}
1029
-				} elseif ( empty( $subdir_name ) ) {
1030
-					return new WP_Error( 'packaged_wrong', esc_html__( 'The remote plugin package consists of more than one file, but the files are not packaged in a folder.', 'tgmpa' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'tgmpa' ), array( 'found' => $subdir_name, 'expected' => $desired_slug ) );
1031
-				}
1032
-			}
1033
-
1034
-			return $source;
1035
-		}
1036
-
1037
-		/**
1038
-		 * Activate a single plugin and send feedback about the result to the screen.
1039
-		 *
1040
-		 * @since 2.5.0
1041
-		 *
1042
-		 * @param string $file_path Path within wp-plugins/ to main plugin file.
1043
-		 * @param string $slug      Plugin slug.
1044
-		 * @param bool   $automatic Whether this is an automatic activation after an install. Defaults to false.
1045
-		 *                          This determines the styling of the output messages.
1046
-		 * @return bool False if an error was encountered, true otherwise.
1047
-		 */
1048
-		protected function activate_single_plugin( $file_path, $slug, $automatic = false ) {
1049
-			if ( $this->can_plugin_activate( $slug ) ) {
1050
-				$activate = activate_plugin( $file_path );
1051
-
1052
-				if ( is_wp_error( $activate ) ) {
1053
-					echo '<div id="message" class="error"><p>', wp_kses_post( $activate->get_error_message() ), '</p></div>',
1054
-						'<p><a href="', esc_url( $this->get_tgmpa_url() ), '" target="_parent">', esc_html( $this->strings['return'] ), '</a></p>';
1055
-
1056
-					return false; // End it here if there is an error with activation.
1057
-				} else {
1058
-					if ( ! $automatic ) {
1059
-						// Make sure message doesn't display again if bulk activation is performed
1060
-						// immediately after a single activation.
1061
-						if ( ! isset( $_POST['action'] ) ) { // WPCS: CSRF OK.
1062
-							echo '<div id="message" class="updated"><p>', esc_html( $this->strings['activated_successfully'] ), ' <strong>', esc_html( $this->plugins[ $slug ]['name'] ), '.</strong></p></div>';
1063
-						}
1064
-					} else {
1065
-						// Simpler message layout for use on the plugin install page.
1066
-						echo '<p>', esc_html( $this->strings['plugin_activated'] ), '</p>';
1067
-					}
1068
-				}
1069
-			} elseif ( $this->is_plugin_active( $slug ) ) {
1070
-				// No simpler message format provided as this message should never be encountered
1071
-				// on the plugin install page.
1072
-				echo '<div id="message" class="error"><p>',
1073
-					sprintf(
1074
-						esc_html( $this->strings['plugin_already_active'] ),
1075
-						'<strong>' . esc_html( $this->plugins[ $slug ]['name'] ) . '</strong>'
1076
-					),
1077
-					'</p></div>';
1078
-			} elseif ( $this->does_plugin_require_update( $slug ) ) {
1079
-				if ( ! $automatic ) {
1080
-					// Make sure message doesn't display again if bulk activation is performed
1081
-					// immediately after a single activation.
1082
-					if ( ! isset( $_POST['action'] ) ) { // WPCS: CSRF OK.
1083
-						echo '<div id="message" class="error"><p>',
1084
-							sprintf(
1085
-								esc_html( $this->strings['plugin_needs_higher_version'] ),
1086
-								'<strong>' . esc_html( $this->plugins[ $slug ]['name'] ) . '</strong>'
1087
-							),
1088
-							'</p></div>';
1089
-					}
1090
-				} else {
1091
-					// Simpler message layout for use on the plugin install page.
1092
-					echo '<p>', sprintf( esc_html( $this->strings['plugin_needs_higher_version'] ), esc_html( $this->plugins[ $slug ]['name'] ) ), '</p>';
1093
-				}
1094
-			}
1095
-
1096
-			return true;
1097
-		}
1098
-
1099
-		/**
1100
-		 * Echoes required plugin notice.
1101
-		 *
1102
-		 * Outputs a message telling users that a specific plugin is required for
1103
-		 * their theme. If appropriate, it includes a link to the form page where
1104
-		 * users can install and activate the plugin.
1105
-		 *
1106
-		 * Returns early if we're on the Install page.
1107
-		 *
1108
-		 * @since 1.0.0
1109
-		 *
1110
-		 * @global object $current_screen
1111
-		 *
1112
-		 * @return null Returns early if we're on the Install page.
1113
-		 */
1114
-		public function notices() {
1115
-			// Remove nag on the install page / Return early if the nag message has been dismissed or user < author.
1116
-			if ( ( $this->is_tgmpa_page() || $this->is_core_update_page() ) || get_user_meta( get_current_user_id(), 'tgmpa_dismissed_notice_' . $this->id, true ) || ! current_user_can( apply_filters( 'tgmpa_show_admin_notice_capability', 'publish_posts' ) ) ) {
1117
-				return;
1118
-			}
1119
-
1120
-			// Store for the plugin slugs by message type.
1121
-			$message = array();
1122
-
1123
-			// Initialize counters used to determine plurality of action link texts.
1124
-			$install_link_count          = 0;
1125
-			$update_link_count           = 0;
1126
-			$activate_link_count         = 0;
1127
-			$total_required_action_count = 0;
1128
-
1129
-			foreach ( $this->plugins as $slug => $plugin ) {
1130
-				if ( $this->is_plugin_active( $slug ) && false === $this->does_plugin_have_update( $slug ) ) {
1131
-					continue;
1132
-				}
1133
-
1134
-				if ( ! $this->is_plugin_installed( $slug ) ) {
1135
-					if ( current_user_can( 'install_plugins' ) ) {
1136
-						$install_link_count++;
1137
-
1138
-						if ( true === $plugin['required'] ) {
1139
-							$message['notice_can_install_required'][] = $slug;
1140
-						} else {
1141
-							$message['notice_can_install_recommended'][] = $slug;
1142
-						}
1143
-					}
1144
-					if ( true === $plugin['required'] ) {
1145
-						$total_required_action_count++;
1146
-					}
1147
-				} else {
1148
-					if ( ! $this->is_plugin_active( $slug ) && $this->can_plugin_activate( $slug ) ) {
1149
-						if ( current_user_can( 'activate_plugins' ) ) {
1150
-							$activate_link_count++;
1151
-
1152
-							if ( true === $plugin['required'] ) {
1153
-								$message['notice_can_activate_required'][] = $slug;
1154
-							} else {
1155
-								$message['notice_can_activate_recommended'][] = $slug;
1156
-							}
1157
-						}
1158
-						if ( true === $plugin['required'] ) {
1159
-							$total_required_action_count++;
1160
-						}
1161
-					}
1162
-
1163
-					if ( $this->does_plugin_require_update( $slug ) || false !== $this->does_plugin_have_update( $slug ) ) {
1164
-
1165
-						if ( current_user_can( 'update_plugins' ) ) {
1166
-							$update_link_count++;
1167
-
1168
-							if ( $this->does_plugin_require_update( $slug ) ) {
1169
-								$message['notice_ask_to_update'][] = $slug;
1170
-							} elseif ( false !== $this->does_plugin_have_update( $slug ) ) {
1171
-								$message['notice_ask_to_update_maybe'][] = $slug;
1172
-							}
1173
-						}
1174
-						if ( true === $plugin['required'] ) {
1175
-							$total_required_action_count++;
1176
-						}
1177
-					}
1178
-				}
1179
-			}
1180
-			unset( $slug, $plugin );
1181
-
1182
-			// If we have notices to display, we move forward.
1183
-			if ( ! empty( $message ) || $total_required_action_count > 0 ) {
1184
-				krsort( $message ); // Sort messages.
1185
-				$rendered = '';
1186
-
1187
-				// As add_settings_error() wraps the final message in a <p> and as the final message can't be
1188
-				// filtered, using <p>'s in our html would render invalid html output.
1189
-				$line_template = '<span style="display: block; margin: 0.5em 0.5em 0 0; clear: both;">%s</span>' . "\n";
1190
-
1191
-				if ( ! current_user_can( 'activate_plugins' ) && ! current_user_can( 'install_plugins' ) && ! current_user_can( 'update_plugins' ) ) {
1192
-					$rendered  = esc_html( $this->strings['notice_cannot_install_activate'] ) . ' ' . esc_html( $this->strings['contact_admin'] );
1193
-					$rendered .= $this->create_user_action_links_for_notice( 0, 0, 0, $line_template );
1194
-				} else {
1195
-
1196
-					// If dismissable is false and a message is set, output it now.
1197
-					if ( ! $this->dismissable && ! empty( $this->dismiss_msg ) ) {
1198
-						$rendered .= sprintf( $line_template, wp_kses_post( $this->dismiss_msg ) );
1199
-					}
1200
-
1201
-					// Render the individual message lines for the notice.
1202
-					foreach ( $message as $type => $plugin_group ) {
1203
-						$linked_plugins = array();
1204
-
1205
-						// Get the external info link for a plugin if one is available.
1206
-						foreach ( $plugin_group as $plugin_slug ) {
1207
-							$linked_plugins[] = $this->get_info_link( $plugin_slug );
1208
-						}
1209
-						unset( $plugin_slug );
1210
-
1211
-						$count          = count( $plugin_group );
1212
-						$linked_plugins = array_map( array( 'TGMPA_Utils', 'wrap_in_em' ), $linked_plugins );
1213
-						$last_plugin    = array_pop( $linked_plugins ); // Pop off last name to prep for readability.
1214
-						$imploded       = empty( $linked_plugins ) ? $last_plugin : ( implode( ', ', $linked_plugins ) . ' ' . esc_html_x( 'and', 'plugin A *and* plugin B', 'tgmpa' ) . ' ' . $last_plugin );
1215
-
1216
-						$rendered .= sprintf(
1217
-							$line_template,
1218
-							sprintf(
1219
-								translate_nooped_plural( $this->strings[ $type ], $count, 'tgmpa' ),
1220
-								$imploded,
1221
-								$count
1222
-							)
1223
-						);
1224
-
1225
-					}
1226
-					unset( $type, $plugin_group, $linked_plugins, $count, $last_plugin, $imploded );
1227
-
1228
-					$rendered .= $this->create_user_action_links_for_notice( $install_link_count, $update_link_count, $activate_link_count, $line_template );
1229
-				}
1230
-
1231
-				// Register the nag messages and prepare them to be processed.
1232
-				add_settings_error( 'tgmpa', 'tgmpa', $rendered, $this->get_admin_notice_class() );
1233
-			}
1234
-
1235
-			// Admin options pages already output settings_errors, so this is to avoid duplication.
1236
-			if ( 'options-general' !== $GLOBALS['current_screen']->parent_base ) {
1237
-				$this->display_settings_errors();
1238
-			}
1239
-		}
1240
-
1241
-		/**
1242
-		 * Generate the user action links for the admin notice.
1243
-		 *
1244
-		 * @since 2.6.0
1245
-		 *
1246
-		 * @param int $install_count  Number of plugins to install.
1247
-		 * @param int $update_count   Number of plugins to update.
1248
-		 * @param int $activate_count Number of plugins to activate.
1249
-		 * @param int $line_template  Template for the HTML tag to output a line.
1250
-		 * @return string Action links.
1251
-		 */
1252
-		protected function create_user_action_links_for_notice( $install_count, $update_count, $activate_count, $line_template ) {
1253
-			// Setup action links.
1254
-			$action_links = array(
1255
-				'install'  => '',
1256
-				'update'   => '',
1257
-				'activate' => '',
1258
-				'dismiss'  => $this->dismissable ? '<a href="' . esc_url( wp_nonce_url( add_query_arg( 'tgmpa-dismiss', 'dismiss_admin_notices' ), 'tgmpa-dismiss-' . get_current_user_id() ) ) . '" class="dismiss-notice" target="_parent">' . esc_html( $this->strings['dismiss'] ) . '</a>' : '',
1259
-			);
1260
-
1261
-			$link_template = '<a href="%2$s">%1$s</a>';
1262
-
1263
-			if ( current_user_can( 'install_plugins' ) ) {
1264
-				if ( $install_count > 0 ) {
1265
-					$action_links['install'] = sprintf(
1266
-						$link_template,
1267
-						translate_nooped_plural( $this->strings['install_link'], $install_count, 'tgmpa' ),
1268
-						esc_url( $this->get_tgmpa_status_url( 'install' ) )
1269
-					);
1270
-				}
1271
-				if ( $update_count > 0 ) {
1272
-					$action_links['update'] = sprintf(
1273
-						$link_template,
1274
-						translate_nooped_plural( $this->strings['update_link'], $update_count, 'tgmpa' ),
1275
-						esc_url( $this->get_tgmpa_status_url( 'update' ) )
1276
-					);
1277
-				}
1278
-			}
1279
-
1280
-			if ( current_user_can( 'activate_plugins' ) && $activate_count > 0 ) {
1281
-				$action_links['activate'] = sprintf(
1282
-					$link_template,
1283
-					translate_nooped_plural( $this->strings['activate_link'], $activate_count, 'tgmpa' ),
1284
-					esc_url( $this->get_tgmpa_status_url( 'activate' ) )
1285
-				);
1286
-			}
1287
-
1288
-			$action_links = apply_filters( 'tgmpa_notice_action_links', $action_links );
1289
-
1290
-			$action_links = array_filter( (array) $action_links ); // Remove any empty array items.
1291
-
1292
-			if ( ! empty( $action_links ) ) {
1293
-				$action_links = sprintf( $line_template, implode( ' | ', $action_links ) );
1294
-				return apply_filters( 'tgmpa_notice_rendered_action_links', $action_links );
1295
-			} else {
1296
-				return '';
1297
-			}
1298
-		}
1299
-
1300
-		/**
1301
-		 * Get admin notice class.
1302
-		 *
1303
-		 * Work around all the changes to the various admin notice classes between WP 4.4 and 3.7
1304
-		 * (lowest supported version by TGMPA).
1305
-		 *
1306
-		 * @since 2.6.0
1307
-		 *
1308
-		 * @return string
1309
-		 */
1310
-		protected function get_admin_notice_class() {
1311
-			if ( ! empty( $this->strings['nag_type'] ) ) {
1312
-				return sanitize_html_class( strtolower( $this->strings['nag_type'] ) );
1313
-			} else {
1314
-				if ( version_compare( $this->wp_version, '4.2', '>=' ) ) {
1315
-					return 'notice-warning';
1316
-				} elseif ( version_compare( $this->wp_version, '4.1', '>=' ) ) {
1317
-					return 'notice';
1318
-				} else {
1319
-					return 'updated';
1320
-				}
1321
-			}
1322
-		}
1323
-
1324
-		/**
1325
-		 * Display settings errors and remove those which have been displayed to avoid duplicate messages showing
1326
-		 *
1327
-		 * @since 2.5.0
1328
-		 */
1329
-		protected function display_settings_errors() {
1330
-			global $wp_settings_errors;
1331
-
1332
-			settings_errors( 'tgmpa' );
1333
-
1334
-			foreach ( (array) $wp_settings_errors as $key => $details ) {
1335
-				if ( 'tgmpa' === $details['setting'] ) {
1336
-					unset( $wp_settings_errors[ $key ] );
1337
-					break;
1338
-				}
1339
-			}
1340
-		}
1341
-
1342
-		/**
1343
-		 * Register dismissal of admin notices.
1344
-		 *
1345
-		 * Acts on the dismiss link in the admin nag messages.
1346
-		 * If clicked, the admin notice disappears and will no longer be visible to this user.
1347
-		 *
1348
-		 * @since 2.1.0
1349
-		 */
1350
-		public function dismiss() {
1351
-			if ( isset( $_GET['tgmpa-dismiss'] ) && check_admin_referer( 'tgmpa-dismiss-' . get_current_user_id() ) ) {
1352
-				update_user_meta( get_current_user_id(), 'tgmpa_dismissed_notice_' . $this->id, 1 );
1353
-			}
1354
-		}
1355
-
1356
-		/**
1357
-		 * Add individual plugin to our collection of plugins.
1358
-		 *
1359
-		 * If the required keys are not set or the plugin has already
1360
-		 * been registered, the plugin is not added.
1361
-		 *
1362
-		 * @since 2.0.0
1363
-		 *
1364
-		 * @param array|null $plugin Array of plugin arguments or null if invalid argument.
1365
-		 * @return null Return early if incorrect argument.
1366
-		 */
1367
-		public function register( $plugin ) {
1368
-			if ( empty( $plugin['slug'] ) || empty( $plugin['name'] ) ) {
1369
-				return;
1370
-			}
1371
-
1372
-			if ( empty( $plugin['slug'] ) || ! is_string( $plugin['slug'] ) || isset( $this->plugins[ $plugin['slug'] ] ) ) {
1373
-				return;
1374
-			}
1375
-
1376
-			$defaults = array(
1377
-				'name'               => '',      // String
1378
-				'slug'               => '',      // String
1379
-				'source'             => 'repo',  // String
1380
-				'required'           => false,   // Boolean
1381
-				'version'            => '',      // String
1382
-				'force_activation'   => false,   // Boolean
1383
-				'force_deactivation' => false,   // Boolean
1384
-				'external_url'       => '',      // String
1385
-				'is_callable'        => '',      // String|Array.
1386
-			);
1387
-
1388
-			// Prepare the received data.
1389
-			$plugin = wp_parse_args( $plugin, $defaults );
1390
-
1391
-			// Standardize the received slug.
1392
-			$plugin['slug'] = $this->sanitize_key( $plugin['slug'] );
1393
-
1394
-			// Forgive users for using string versions of booleans or floats for version number.
1395
-			$plugin['version']            = (string) $plugin['version'];
1396
-			$plugin['source']             = empty( $plugin['source'] ) ? 'repo' : $plugin['source'];
1397
-			$plugin['required']           = TGMPA_Utils::validate_bool( $plugin['required'] );
1398
-			$plugin['force_activation']   = TGMPA_Utils::validate_bool( $plugin['force_activation'] );
1399
-			$plugin['force_deactivation'] = TGMPA_Utils::validate_bool( $plugin['force_deactivation'] );
1400
-
1401
-			// Enrich the received data.
1402
-			$plugin['file_path']   = $this->_get_plugin_basename_from_slug( $plugin['slug'] );
1403
-			$plugin['source_type'] = $this->get_plugin_source_type( $plugin['source'] );
1404
-
1405
-			// Set the class properties.
1406
-			$this->plugins[ $plugin['slug'] ]    = $plugin;
1407
-			$this->sort_order[ $plugin['slug'] ] = $plugin['name'];
1408
-
1409
-			// Should we add the force activation hook ?
1410
-			if ( true === $plugin['force_activation'] ) {
1411
-				$this->has_forced_activation = true;
1412
-			}
1413
-
1414
-			// Should we add the force deactivation hook ?
1415
-			if ( true === $plugin['force_deactivation'] ) {
1416
-				$this->has_forced_deactivation = true;
1417
-			}
1418
-		}
1419
-
1420
-		/**
1421
-		 * Determine what type of source the plugin comes from.
1422
-		 *
1423
-		 * @since 2.5.0
1424
-		 *
1425
-		 * @param string $source The source of the plugin as provided, either empty (= WP repo), a file path
1426
-		 *                       (= bundled) or an external URL.
1427
-		 * @return string 'repo', 'external', or 'bundled'
1428
-		 */
1429
-		protected function get_plugin_source_type( $source ) {
1430
-			if ( 'repo' === $source || preg_match( self::WP_REPO_REGEX, $source ) ) {
1431
-				return 'repo';
1432
-			} elseif ( preg_match( self::IS_URL_REGEX, $source ) ) {
1433
-				return 'external';
1434
-			} else {
1435
-				return 'bundled';
1436
-			}
1437
-		}
1438
-
1439
-		/**
1440
-		 * Sanitizes a string key.
1441
-		 *
1442
-		 * Near duplicate of WP Core `sanitize_key()`. The difference is that uppercase characters *are*
1443
-		 * allowed, so as not to break upgrade paths from non-standard bundled plugins using uppercase
1444
-		 * characters in the plugin directory path/slug. Silly them.
1445
-		 *
1446
-		 * @see https://developer.wordpress.org/reference/hooks/sanitize_key/
1447
-		 *
1448
-		 * @since 2.5.0
1449
-		 *
1450
-		 * @param string $key String key.
1451
-		 * @return string Sanitized key
1452
-		 */
1453
-		public function sanitize_key( $key ) {
1454
-			$raw_key = $key;
1455
-			$key     = preg_replace( '`[^A-Za-z0-9_-]`', '', $key );
1456
-
1457
-			/**
1458
-			 * Filter a sanitized key string.
1459
-			 *
1460
-			 * @since 2.5.0
1461
-			 *
1462
-			 * @param string $key     Sanitized key.
1463
-			 * @param string $raw_key The key prior to sanitization.
1464
-			 */
1465
-			return apply_filters( 'tgmpa_sanitize_key', $key, $raw_key );
1466
-		}
1467
-
1468
-		/**
1469
-		 * Amend default configuration settings.
1470
-		 *
1471
-		 * @since 2.0.0
1472
-		 *
1473
-		 * @param array $config Array of config options to pass as class properties.
1474
-		 */
1475
-		public function config( $config ) {
1476
-			$keys = array(
1477
-				'id',
1478
-				'default_path',
1479
-				'has_notices',
1480
-				'dismissable',
1481
-				'dismiss_msg',
1482
-				'menu',
1483
-				'parent_slug',
1484
-				'capability',
1485
-				'is_automatic',
1486
-				'message',
1487
-				'strings',
1488
-			);
1489
-
1490
-			foreach ( $keys as $key ) {
1491
-				if ( isset( $config[ $key ] ) ) {
1492
-					if ( is_array( $config[ $key ] ) ) {
1493
-						$this->$key = array_merge( $this->$key, $config[ $key ] );
1494
-					} else {
1495
-						$this->$key = $config[ $key ];
1496
-					}
1497
-				}
1498
-			}
1499
-		}
1500
-
1501
-		/**
1502
-		 * Amend action link after plugin installation.
1503
-		 *
1504
-		 * @since 2.0.0
1505
-		 *
1506
-		 * @param array $install_actions Existing array of actions.
1507
-		 * @return false|array Amended array of actions.
1508
-		 */
1509
-		public function actions( $install_actions ) {
1510
-			// Remove action links on the TGMPA install page.
1511
-			if ( $this->is_tgmpa_page() ) {
1512
-				return false;
1513
-			}
1514
-
1515
-			return $install_actions;
1516
-		}
1517
-
1518
-		/**
1519
-		 * Flushes the plugins cache on theme switch to prevent stale entries
1520
-		 * from remaining in the plugin table.
1521
-		 *
1522
-		 * @since 2.4.0
1523
-		 *
1524
-		 * @param bool $clear_update_cache Optional. Whether to clear the Plugin updates cache.
1525
-		 *                                 Parameter added in v2.5.0.
1526
-		 */
1527
-		public function flush_plugins_cache( $clear_update_cache = true ) {
1528
-			wp_clean_plugins_cache( $clear_update_cache );
1529
-		}
1530
-
1531
-		/**
1532
-		 * Set file_path key for each installed plugin.
1533
-		 *
1534
-		 * @since 2.1.0
1535
-		 *
1536
-		 * @param string $plugin_slug Optional. If set, only (re-)populates the file path for that specific plugin.
1537
-		 *                            Parameter added in v2.5.0.
1538
-		 */
1539
-		public function populate_file_path( $plugin_slug = '' ) {
1540
-			if ( ! empty( $plugin_slug ) && is_string( $plugin_slug ) && isset( $this->plugins[ $plugin_slug ] ) ) {
1541
-				$this->plugins[ $plugin_slug ]['file_path'] = $this->_get_plugin_basename_from_slug( $plugin_slug );
1542
-			} else {
1543
-				// Add file_path key for all plugins.
1544
-				foreach ( $this->plugins as $slug => $values ) {
1545
-					$this->plugins[ $slug ]['file_path'] = $this->_get_plugin_basename_from_slug( $slug );
1546
-				}
1547
-			}
1548
-		}
1549
-
1550
-		/**
1551
-		 * Helper function to extract the file path of the plugin file from the
1552
-		 * plugin slug, if the plugin is installed.
1553
-		 *
1554
-		 * @since 2.0.0
1555
-		 *
1556
-		 * @param string $slug Plugin slug (typically folder name) as provided by the developer.
1557
-		 * @return string Either file path for plugin if installed, or just the plugin slug.
1558
-		 */
1559
-		protected function _get_plugin_basename_from_slug( $slug ) {
1560
-			$keys = array_keys( $this->get_plugins() );
1561
-
1562
-			foreach ( $keys as $key ) {
1563
-				if ( preg_match( '|^' . $slug . '/|', $key ) ) {
1564
-					return $key;
1565
-				}
1566
-			}
1567
-
1568
-			return $slug;
1569
-		}
1570
-
1571
-		/**
1572
-		 * Retrieve plugin data, given the plugin name.
1573
-		 *
1574
-		 * Loops through the registered plugins looking for $name. If it finds it,
1575
-		 * it returns the $data from that plugin. Otherwise, returns false.
1576
-		 *
1577
-		 * @since 2.1.0
1578
-		 *
1579
-		 * @param string $name Name of the plugin, as it was registered.
1580
-		 * @param string $data Optional. Array key of plugin data to return. Default is slug.
1581
-		 * @return string|boolean Plugin slug if found, false otherwise.
1582
-		 */
1583
-		public function _get_plugin_data_from_name( $name, $data = 'slug' ) {
1584
-			foreach ( $this->plugins as $values ) {
1585
-				if ( $name === $values['name'] && isset( $values[ $data ] ) ) {
1586
-					return $values[ $data ];
1587
-				}
1588
-			}
1589
-
1590
-			return false;
1591
-		}
1592
-
1593
-		/**
1594
-		 * Retrieve the download URL for a package.
1595
-		 *
1596
-		 * @since 2.5.0
1597
-		 *
1598
-		 * @param string $slug Plugin slug.
1599
-		 * @return string Plugin download URL or path to local file or empty string if undetermined.
1600
-		 */
1601
-		public function get_download_url( $slug ) {
1602
-			$dl_source = '';
1603
-
1604
-			switch ( $this->plugins[ $slug ]['source_type'] ) {
1605
-				case 'repo':
1606
-					return $this->get_wp_repo_download_url( $slug );
1607
-				case 'external':
1608
-					return $this->plugins[ $slug ]['source'];
1609
-				case 'bundled':
1610
-					return $this->default_path . $this->plugins[ $slug ]['source'];
1611
-			}
1612
-
1613
-			return $dl_source; // Should never happen.
1614
-		}
1615
-
1616
-		/**
1617
-		 * Retrieve the download URL for a WP repo package.
1618
-		 *
1619
-		 * @since 2.5.0
1620
-		 *
1621
-		 * @param string $slug Plugin slug.
1622
-		 * @return string Plugin download URL.
1623
-		 */
1624
-		protected function get_wp_repo_download_url( $slug ) {
1625
-			$source = '';
1626
-			$api    = $this->get_plugins_api( $slug );
1627
-
1628
-			if ( false !== $api && isset( $api->download_link ) ) {
1629
-				$source = $api->download_link;
1630
-			}
1631
-
1632
-			return $source;
1633
-		}
1634
-
1635
-		/**
1636
-		 * Try to grab information from WordPress API.
1637
-		 *
1638
-		 * @since 2.5.0
1639
-		 *
1640
-		 * @param string $slug Plugin slug.
1641
-		 * @return object Plugins_api response object on success, WP_Error on failure.
1642
-		 */
1643
-		protected function get_plugins_api( $slug ) {
1644
-			static $api = array(); // Cache received responses.
1645
-
1646
-			if ( ! isset( $api[ $slug ] ) ) {
1647
-				if ( ! function_exists( 'plugins_api' ) ) {
1648
-					require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
1649
-				}
1650
-
1651
-				$response = plugins_api( 'plugin_information', array( 'slug' => $slug, 'fields' => array( 'sections' => false ) ) );
1652
-
1653
-				$api[ $slug ] = false;
1654
-
1655
-				if ( is_wp_error( $response ) ) {
1656
-					wp_die( esc_html( $this->strings['oops'] ) );
1657
-				} else {
1658
-					$api[ $slug ] = $response;
1659
-				}
1660
-			}
1661
-
1662
-			return $api[ $slug ];
1663
-		}
1664
-
1665
-		/**
1666
-		 * Retrieve a link to a plugin information page.
1667
-		 *
1668
-		 * @since 2.5.0
1669
-		 *
1670
-		 * @param string $slug Plugin slug.
1671
-		 * @return string Fully formed html link to a plugin information page if available
1672
-		 *                or the plugin name if not.
1673
-		 */
1674
-		public function get_info_link( $slug ) {
1675
-			if ( ! empty( $this->plugins[ $slug ]['external_url'] ) && preg_match( self::IS_URL_REGEX, $this->plugins[ $slug ]['external_url'] ) ) {
1676
-				$link = sprintf(
1677
-					'<a href="%1$s" target="_blank">%2$s</a>',
1678
-					esc_url( $this->plugins[ $slug ]['external_url'] ),
1679
-					esc_html( $this->plugins[ $slug ]['name'] )
1680
-				);
1681
-			} elseif ( 'repo' === $this->plugins[ $slug ]['source_type'] ) {
1682
-				$url = add_query_arg(
1683
-					array(
1684
-						'tab'       => 'plugin-information',
1685
-						'plugin'    => urlencode( $slug ),
1686
-						'TB_iframe' => 'true',
1687
-						'width'     => '640',
1688
-						'height'    => '500',
1689
-					),
1690
-					self_admin_url( 'plugin-install.php' )
1691
-				);
1692
-
1693
-				$link = sprintf(
1694
-					'<a href="%1$s" class="thickbox">%2$s</a>',
1695
-					esc_url( $url ),
1696
-					esc_html( $this->plugins[ $slug ]['name'] )
1697
-				);
1698
-			} else {
1699
-				$link = esc_html( $this->plugins[ $slug ]['name'] ); // No hyperlink.
1700
-			}
1701
-
1702
-			return $link;
1703
-		}
1704
-
1705
-		/**
1706
-		 * Determine if we're on the TGMPA Install page.
1707
-		 *
1708
-		 * @since 2.1.0
1709
-		 *
1710
-		 * @return boolean True when on the TGMPA page, false otherwise.
1711
-		 */
1712
-		protected function is_tgmpa_page() {
1713
-			return isset( $_GET['page'] ) && $this->menu === $_GET['page'];
1714
-		}
1715
-
1716
-		/**
1717
-		 * Determine if we're on a WP Core installation/upgrade page.
1718
-		 *
1719
-		 * @since 2.6.0
1720
-		 *
1721
-		 * @return boolean True when on a WP Core installation/upgrade page, false otherwise.
1722
-		 */
1723
-		protected function is_core_update_page() {
1724
-			// Current screen is not always available, most notably on the customizer screen.
1725
-			if ( ! function_exists( 'get_current_screen' ) ) {
1726
-				return false;
1727
-			}
1728
-
1729
-			$screen = get_current_screen();
1730
-
1731
-			if ( 'update-core' === $screen->base ) {
1732
-				// Core update screen.
1733
-				return true;
1734
-			} elseif ( 'plugins' === $screen->base && ! empty( $_POST['action'] ) ) { // WPCS: CSRF ok.
1735
-				// Plugins bulk update screen.
1736
-				return true;
1737
-			} elseif ( 'update' === $screen->base && ! empty( $_POST['action'] ) ) { // WPCS: CSRF ok.
1738
-				// Individual updates (ajax call).
1739
-				return true;
1740
-			}
1741
-
1742
-			return false;
1743
-		}
1744
-
1745
-		/**
1746
-		 * Retrieve the URL to the TGMPA Install page.
1747
-		 *
1748
-		 * I.e. depending on the config settings passed something along the lines of:
1749
-		 * http://example.com/wp-admin/themes.php?page=tgmpa-install-plugins
1750
-		 *
1751
-		 * @since 2.5.0
1752
-		 *
1753
-		 * @return string Properly encoded URL (not escaped).
1754
-		 */
1755
-		public function get_tgmpa_url() {
1756
-			static $url;
1757
-
1758
-			if ( ! isset( $url ) ) {
1759
-				$parent = $this->parent_slug;
1760
-				if ( false === strpos( $parent, '.php' ) ) {
1761
-					$parent = 'admin.php';
1762
-				}
1763
-				$url = add_query_arg(
1764
-					array(
1765
-						'page' => urlencode( $this->menu ),
1766
-					),
1767
-					self_admin_url( $parent )
1768
-				);
1769
-			}
1770
-
1771
-			return $url;
1772
-		}
1773
-
1774
-		/**
1775
-		 * Retrieve the URL to the TGMPA Install page for a specific plugin status (view).
1776
-		 *
1777
-		 * I.e. depending on the config settings passed something along the lines of:
1778
-		 * http://example.com/wp-admin/themes.php?page=tgmpa-install-plugins&plugin_status=install
1779
-		 *
1780
-		 * @since 2.5.0
1781
-		 *
1782
-		 * @param string $status Plugin status - either 'install', 'update' or 'activate'.
1783
-		 * @return string Properly encoded URL (not escaped).
1784
-		 */
1785
-		public function get_tgmpa_status_url( $status ) {
1786
-			return add_query_arg(
1787
-				array(
1788
-					'plugin_status' => urlencode( $status ),
1789
-				),
1790
-				$this->get_tgmpa_url()
1791
-			);
1792
-		}
1793
-
1794
-		/**
1795
-		 * Determine whether there are open actions for plugins registered with TGMPA.
1796
-		 *
1797
-		 * @since 2.5.0
1798
-		 *
1799
-		 * @return bool True if complete, i.e. no outstanding actions. False otherwise.
1800
-		 */
1801
-		public function is_tgmpa_complete() {
1802
-			$complete = true;
1803
-			foreach ( $this->plugins as $slug => $plugin ) {
1804
-				if ( ! $this->is_plugin_active( $slug ) || false !== $this->does_plugin_have_update( $slug ) ) {
1805
-					$complete = false;
1806
-					break;
1807
-				}
1808
-			}
1809
-
1810
-			return $complete;
1811
-		}
1812
-
1813
-		/**
1814
-		 * Check if a plugin is installed. Does not take must-use plugins into account.
1815
-		 *
1816
-		 * @since 2.5.0
1817
-		 *
1818
-		 * @param string $slug Plugin slug.
1819
-		 * @return bool True if installed, false otherwise.
1820
-		 */
1821
-		public function is_plugin_installed( $slug ) {
1822
-			$installed_plugins = $this->get_plugins(); // Retrieve a list of all installed plugins (WP cached).
1823
-
1824
-			return ( ! empty( $installed_plugins[ $this->plugins[ $slug ]['file_path'] ] ) );
1825
-		}
1826
-
1827
-		/**
1828
-		 * Check if a plugin is active.
1829
-		 *
1830
-		 * @since 2.5.0
1831
-		 *
1832
-		 * @param string $slug Plugin slug.
1833
-		 * @return bool True if active, false otherwise.
1834
-		 */
1835
-		public function is_plugin_active( $slug ) {
1836
-			return ( ( ! empty( $this->plugins[ $slug ]['is_callable'] ) && is_callable( $this->plugins[ $slug ]['is_callable'] ) ) || is_plugin_active( $this->plugins[ $slug ]['file_path'] ) );
1837
-		}
1838
-
1839
-		/**
1840
-		 * Check if a plugin can be updated, i.e. if we have information on the minimum WP version required
1841
-		 * available, check whether the current install meets them.
1842
-		 *
1843
-		 * @since 2.5.0
1844
-		 *
1845
-		 * @param string $slug Plugin slug.
1846
-		 * @return bool True if OK to update, false otherwise.
1847
-		 */
1848
-		public function can_plugin_update( $slug ) {
1849
-			// We currently can't get reliable info on non-WP-repo plugins - issue #380.
1850
-			if ( 'repo' !== $this->plugins[ $slug ]['source_type'] ) {
1851
-				return true;
1852
-			}
1853
-
1854
-			$api = $this->get_plugins_api( $slug );
1855
-
1856
-			if ( false !== $api && isset( $api->requires ) ) {
1857
-				return version_compare( $this->wp_version, $api->requires, '>=' );
1858
-			}
1859
-
1860
-			// No usable info received from the plugins API, presume we can update.
1861
-			return true;
1862
-		}
1863
-
1864
-		/**
1865
-		 * Check to see if the plugin is 'updatetable', i.e. installed, with an update available
1866
-		 * and no WP version requirements blocking it.
1867
-		 *
1868
-		 * @since 2.6.0
1869
-		 *
1870
-		 * @param string $slug Plugin slug.
1871
-		 * @return bool True if OK to proceed with update, false otherwise.
1872
-		 */
1873
-		public function is_plugin_updatetable( $slug ) {
1874
-			if ( ! $this->is_plugin_installed( $slug ) ) {
1875
-				return false;
1876
-			} else {
1877
-				return ( false !== $this->does_plugin_have_update( $slug ) && $this->can_plugin_update( $slug ) );
1878
-			}
1879
-		}
1880
-
1881
-		/**
1882
-		 * Check if a plugin can be activated, i.e. is not currently active and meets the minimum
1883
-		 * plugin version requirements set in TGMPA (if any).
1884
-		 *
1885
-		 * @since 2.5.0
1886
-		 *
1887
-		 * @param string $slug Plugin slug.
1888
-		 * @return bool True if OK to activate, false otherwise.
1889
-		 */
1890
-		public function can_plugin_activate( $slug ) {
1891
-			return ( ! $this->is_plugin_active( $slug ) && ! $this->does_plugin_require_update( $slug ) );
1892
-		}
1893
-
1894
-		/**
1895
-		 * Retrieve the version number of an installed plugin.
1896
-		 *
1897
-		 * @since 2.5.0
1898
-		 *
1899
-		 * @param string $slug Plugin slug.
1900
-		 * @return string Version number as string or an empty string if the plugin is not installed
1901
-		 *                or version unknown (plugins which don't comply with the plugin header standard).
1902
-		 */
1903
-		public function get_installed_version( $slug ) {
1904
-			$installed_plugins = $this->get_plugins(); // Retrieve a list of all installed plugins (WP cached).
1905
-
1906
-			if ( ! empty( $installed_plugins[ $this->plugins[ $slug ]['file_path'] ]['Version'] ) ) {
1907
-				return $installed_plugins[ $this->plugins[ $slug ]['file_path'] ]['Version'];
1908
-			}
1909
-
1910
-			return '';
1911
-		}
1912
-
1913
-		/**
1914
-		 * Check whether a plugin complies with the minimum version requirements.
1915
-		 *
1916
-		 * @since 2.5.0
1917
-		 *
1918
-		 * @param string $slug Plugin slug.
1919
-		 * @return bool True when a plugin needs to be updated, otherwise false.
1920
-		 */
1921
-		public function does_plugin_require_update( $slug ) {
1922
-			$installed_version = $this->get_installed_version( $slug );
1923
-			$minimum_version   = $this->plugins[ $slug ]['version'];
1924
-
1925
-			return version_compare( $minimum_version, $installed_version, '>' );
1926
-		}
1927
-
1928
-		/**
1929
-		 * Check whether there is an update available for a plugin.
1930
-		 *
1931
-		 * @since 2.5.0
1932
-		 *
1933
-		 * @param string $slug Plugin slug.
1934
-		 * @return false|string Version number string of the available update or false if no update available.
1935
-		 */
1936
-		public function does_plugin_have_update( $slug ) {
1937
-			// Presume bundled and external plugins will point to a package which meets the minimum required version.
1938
-			if ( 'repo' !== $this->plugins[ $slug ]['source_type'] ) {
1939
-				if ( $this->does_plugin_require_update( $slug ) ) {
1940
-					return $this->plugins[ $slug ]['version'];
1941
-				}
1942
-
1943
-				return false;
1944
-			}
1945
-
1946
-			$repo_updates = get_site_transient( 'update_plugins' );
1947
-
1948
-			if ( isset( $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->new_version ) ) {
1949
-				return $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->new_version;
1950
-			}
1951
-
1952
-			return false;
1953
-		}
1954
-
1955
-		/**
1956
-		 * Retrieve potential upgrade notice for a plugin.
1957
-		 *
1958
-		 * @since 2.5.0
1959
-		 *
1960
-		 * @param string $slug Plugin slug.
1961
-		 * @return string The upgrade notice or an empty string if no message was available or provided.
1962
-		 */
1963
-		public function get_upgrade_notice( $slug ) {
1964
-			// We currently can't get reliable info on non-WP-repo plugins - issue #380.
1965
-			if ( 'repo' !== $this->plugins[ $slug ]['source_type'] ) {
1966
-				return '';
1967
-			}
1968
-
1969
-			$repo_updates = get_site_transient( 'update_plugins' );
1970
-
1971
-			if ( ! empty( $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->upgrade_notice ) ) {
1972
-				return $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->upgrade_notice;
1973
-			}
1974
-
1975
-			return '';
1976
-		}
1977
-
1978
-		/**
1979
-		 * Wrapper around the core WP get_plugins function, making sure it's actually available.
1980
-		 *
1981
-		 * @since 2.5.0
1982
-		 *
1983
-		 * @param string $plugin_folder Optional. Relative path to single plugin folder.
1984
-		 * @return array Array of installed plugins with plugin information.
1985
-		 */
1986
-		public function get_plugins( $plugin_folder = '' ) {
1987
-			if ( ! function_exists( 'get_plugins' ) ) {
1988
-				require_once ABSPATH . 'wp-admin/includes/plugin.php';
1989
-			}
1990
-
1991
-			return get_plugins( $plugin_folder );
1992
-		}
1993
-
1994
-		/**
1995
-		 * Delete dismissable nag option when theme is switched.
1996
-		 *
1997
-		 * This ensures that the user(s) is/are again reminded via nag of required
1998
-		 * and/or recommended plugins if they re-activate the theme.
1999
-		 *
2000
-		 * @since 2.1.1
2001
-		 */
2002
-		public function update_dismiss() {
2003
-			delete_metadata( 'user', null, 'tgmpa_dismissed_notice_' . $this->id, null, true );
2004
-		}
2005
-
2006
-		/**
2007
-		 * Forces plugin activation if the parameter 'force_activation' is
2008
-		 * set to true.
2009
-		 *
2010
-		 * This allows theme authors to specify certain plugins that must be
2011
-		 * active at all times while using the current theme.
2012
-		 *
2013
-		 * Please take special care when using this parameter as it has the
2014
-		 * potential to be harmful if not used correctly. Setting this parameter
2015
-		 * to true will not allow the specified plugin to be deactivated unless
2016
-		 * the user switches themes.
2017
-		 *
2018
-		 * @since 2.2.0
2019
-		 */
2020
-		public function force_activation() {
2021
-			foreach ( $this->plugins as $slug => $plugin ) {
2022
-				if ( true === $plugin['force_activation'] ) {
2023
-					if ( ! $this->is_plugin_installed( $slug ) ) {
2024
-						// Oops, plugin isn't there so iterate to next condition.
2025
-						continue;
2026
-					} elseif ( $this->can_plugin_activate( $slug ) ) {
2027
-						// There we go, activate the plugin.
2028
-						activate_plugin( $plugin['file_path'] );
2029
-					}
2030
-				}
2031
-			}
2032
-		}
2033
-
2034
-		/**
2035
-		 * Forces plugin deactivation if the parameter 'force_deactivation'
2036
-		 * is set to true and adds the plugin to the 'recently active' plugins list.
2037
-		 *
2038
-		 * This allows theme authors to specify certain plugins that must be
2039
-		 * deactivated upon switching from the current theme to another.
2040
-		 *
2041
-		 * Please take special care when using this parameter as it has the
2042
-		 * potential to be harmful if not used correctly.
2043
-		 *
2044
-		 * @since 2.2.0
2045
-		 */
2046
-		public function force_deactivation() {
2047
-			$deactivated = array();
2048
-
2049
-			foreach ( $this->plugins as $slug => $plugin ) {
2050
-				/*
777
+        }
778
+
779
+        /**
780
+         * Installs, updates or activates a plugin depending on the action link clicked by the user.
781
+         *
782
+         * Checks the $_GET variable to see which actions have been
783
+         * passed and responds with the appropriate method.
784
+         *
785
+         * Uses WP_Filesystem to process and handle the plugin installation
786
+         * method.
787
+         *
788
+         * @since 1.0.0
789
+         *
790
+         * @uses WP_Filesystem
791
+         * @uses WP_Error
792
+         * @uses WP_Upgrader
793
+         * @uses Plugin_Upgrader
794
+         * @uses Plugin_Installer_Skin
795
+         * @uses Plugin_Upgrader_Skin
796
+         *
797
+         * @return boolean True on success, false on failure.
798
+         */
799
+        protected function do_plugin_install() {
800
+            if ( empty( $_GET['plugin'] ) ) {
801
+                return false;
802
+            }
803
+
804
+            // All plugin information will be stored in an array for processing.
805
+            $slug = $this->sanitize_key( urldecode( $_GET['plugin'] ) );
806
+
807
+            if ( ! isset( $this->plugins[ $slug ] ) ) {
808
+                return false;
809
+            }
810
+
811
+            // Was an install or upgrade action link clicked?
812
+            if ( ( isset( $_GET['tgmpa-install'] ) && 'install-plugin' === $_GET['tgmpa-install'] ) || ( isset( $_GET['tgmpa-update'] ) && 'update-plugin' === $_GET['tgmpa-update'] ) ) {
813
+
814
+                $install_type = 'install';
815
+                if ( isset( $_GET['tgmpa-update'] ) && 'update-plugin' === $_GET['tgmpa-update'] ) {
816
+                    $install_type = 'update';
817
+                }
818
+
819
+                check_admin_referer( 'tgmpa-' . $install_type, 'tgmpa-nonce' );
820
+
821
+                // Pass necessary information via URL if WP_Filesystem is needed.
822
+                $url = wp_nonce_url(
823
+                    add_query_arg(
824
+                        array(
825
+                            'plugin'                 => urlencode( $slug ),
826
+                            'tgmpa-' . $install_type => $install_type . '-plugin',
827
+                        ),
828
+                        $this->get_tgmpa_url()
829
+                    ),
830
+                    'tgmpa-' . $install_type,
831
+                    'tgmpa-nonce'
832
+                );
833
+
834
+                $method = ''; // Leave blank so WP_Filesystem can populate it as necessary.
835
+
836
+                if ( false === ( $creds = request_filesystem_credentials( esc_url_raw( $url ), $method, false, false, array() ) ) ) {
837
+                    return true;
838
+                }
839
+
840
+                if ( ! WP_Filesystem( $creds ) ) {
841
+                    request_filesystem_credentials( esc_url_raw( $url ), $method, true, false, array() ); // Setup WP_Filesystem.
842
+                    return true;
843
+                }
844
+
845
+                /* If we arrive here, we have the filesystem. */
846
+
847
+                // Prep variables for Plugin_Installer_Skin class.
848
+                $extra         = array();
849
+                $extra['slug'] = $slug; // Needed for potentially renaming of directory name.
850
+                $source        = $this->get_download_url( $slug );
851
+                $api           = ( 'repo' === $this->plugins[ $slug ]['source_type'] ) ? $this->get_plugins_api( $slug ) : null;
852
+                $api           = ( false !== $api ) ? $api : null;
853
+
854
+                $url = add_query_arg(
855
+                    array(
856
+                        'action' => $install_type . '-plugin',
857
+                        'plugin' => urlencode( $slug ),
858
+                    ),
859
+                    'update.php'
860
+                );
861
+
862
+                if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
863
+                    require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
864
+                }
865
+
866
+                $title     = ( 'update' === $install_type ) ? $this->strings['updating'] : $this->strings['installing'];
867
+                $skin_args = array(
868
+                    'type'   => ( 'bundled' !== $this->plugins[ $slug ]['source_type'] ) ? 'web' : 'upload',
869
+                    'title'  => sprintf( $title, $this->plugins[ $slug ]['name'] ),
870
+                    'url'    => esc_url_raw( $url ),
871
+                    'nonce'  => $install_type . '-plugin_' . $slug,
872
+                    'plugin' => '',
873
+                    'api'    => $api,
874
+                    'extra'  => $extra,
875
+                );
876
+                unset( $title );
877
+
878
+                if ( 'update' === $install_type ) {
879
+                    $skin_args['plugin'] = $this->plugins[ $slug ]['file_path'];
880
+                    $skin                = new Plugin_Upgrader_Skin( $skin_args );
881
+                } else {
882
+                    $skin = new Plugin_Installer_Skin( $skin_args );
883
+                }
884
+
885
+                // Create a new instance of Plugin_Upgrader.
886
+                $upgrader = new Plugin_Upgrader( $skin );
887
+
888
+                // Perform the action and install the plugin from the $source urldecode().
889
+                add_filter( 'upgrader_source_selection', array( $this, 'maybe_adjust_source_dir' ), 1, 3 );
890
+
891
+                if ( 'update' === $install_type ) {
892
+                    // Inject our info into the update transient.
893
+                    $to_inject                    = array( $slug => $this->plugins[ $slug ] );
894
+                    $to_inject[ $slug ]['source'] = $source;
895
+                    $this->inject_update_info( $to_inject );
896
+
897
+                    $upgrader->upgrade( $this->plugins[ $slug ]['file_path'] );
898
+                } else {
899
+                    $upgrader->install( $source );
900
+                }
901
+
902
+                remove_filter( 'upgrader_source_selection', array( $this, 'maybe_adjust_source_dir' ), 1 );
903
+
904
+                // Make sure we have the correct file path now the plugin is installed/updated.
905
+                $this->populate_file_path( $slug );
906
+
907
+                // Only activate plugins if the config option is set to true and the plugin isn't
908
+                // already active (upgrade).
909
+                if ( $this->is_automatic && ! $this->is_plugin_active( $slug ) ) {
910
+                    $plugin_activate = $upgrader->plugin_info(); // Grab the plugin info from the Plugin_Upgrader method.
911
+                    if ( false === $this->activate_single_plugin( $plugin_activate, $slug, true ) ) {
912
+                        return true; // Finish execution of the function early as we encountered an error.
913
+                    }
914
+                }
915
+
916
+                $this->show_tgmpa_version();
917
+
918
+                // Display message based on if all plugins are now active or not.
919
+                if ( $this->is_tgmpa_complete() ) {
920
+                    echo '<p>', sprintf( esc_html( $this->strings['complete'] ), '<a href="' . esc_url( self_admin_url() ) . '">' . esc_html__( 'Return to the Dashboard', 'tgmpa' ) . '</a>' ), '</p>';
921
+                    echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>';
922
+                } else {
923
+                    echo '<p><a href="', esc_url( $this->get_tgmpa_url() ), '" target="_parent">', esc_html( $this->strings['return'] ), '</a></p>';
924
+                }
925
+
926
+                return true;
927
+            } elseif ( isset( $this->plugins[ $slug ]['file_path'], $_GET['tgmpa-activate'] ) && 'activate-plugin' === $_GET['tgmpa-activate'] ) {
928
+                // Activate action link was clicked.
929
+                check_admin_referer( 'tgmpa-activate', 'tgmpa-nonce' );
930
+
931
+                if ( false === $this->activate_single_plugin( $this->plugins[ $slug ]['file_path'], $slug ) ) {
932
+                    return true; // Finish execution of the function early as we encountered an error.
933
+                }
934
+            }
935
+
936
+            return false;
937
+        }
938
+
939
+        /**
940
+         * Inject information into the 'update_plugins' site transient as WP checks that before running an update.
941
+         *
942
+         * @since 2.5.0
943
+         *
944
+         * @param array $plugins The plugin information for the plugins which are to be updated.
945
+         */
946
+        public function inject_update_info( $plugins ) {
947
+            $repo_updates = get_site_transient( 'update_plugins' );
948
+
949
+            if ( ! is_object( $repo_updates ) ) {
950
+                $repo_updates = new stdClass;
951
+            }
952
+
953
+            foreach ( $plugins as $slug => $plugin ) {
954
+                $file_path = $plugin['file_path'];
955
+
956
+                if ( empty( $repo_updates->response[ $file_path ] ) ) {
957
+                    $repo_updates->response[ $file_path ] = new stdClass;
958
+                }
959
+
960
+                // We only really need to set package, but let's do all we can in case WP changes something.
961
+                $repo_updates->response[ $file_path ]->slug        = $slug;
962
+                $repo_updates->response[ $file_path ]->plugin      = $file_path;
963
+                $repo_updates->response[ $file_path ]->new_version = $plugin['version'];
964
+                $repo_updates->response[ $file_path ]->package     = $plugin['source'];
965
+                if ( empty( $repo_updates->response[ $file_path ]->url ) && ! empty( $plugin['external_url'] ) ) {
966
+                    $repo_updates->response[ $file_path ]->url = $plugin['external_url'];
967
+                }
968
+            }
969
+
970
+            set_site_transient( 'update_plugins', $repo_updates );
971
+        }
972
+
973
+        /**
974
+         * Adjust the plugin directory name if necessary.
975
+         *
976
+         * The final destination directory of a plugin is based on the subdirectory name found in the
977
+         * (un)zipped source. In some cases - most notably GitHub repository plugin downloads -, this
978
+         * subdirectory name is not the same as the expected slug and the plugin will not be recognized
979
+         * as installed. This is fixed by adjusting the temporary unzipped source subdirectory name to
980
+         * the expected plugin slug.
981
+         *
982
+         * @since 2.5.0
983
+         *
984
+         * @param string       $source        Path to upgrade/zip-file-name.tmp/subdirectory/.
985
+         * @param string       $remote_source Path to upgrade/zip-file-name.tmp.
986
+         * @param \WP_Upgrader $upgrader      Instance of the upgrader which installs the plugin.
987
+         * @return string $source
988
+         */
989
+        public function maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
990
+            if ( ! $this->is_tgmpa_page() || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
991
+                return $source;
992
+            }
993
+
994
+            // Check for single file plugins.
995
+            $source_files = array_keys( $GLOBALS['wp_filesystem']->dirlist( $remote_source ) );
996
+            if ( 1 === count( $source_files ) && false === $GLOBALS['wp_filesystem']->is_dir( $source ) ) {
997
+                return $source;
998
+            }
999
+
1000
+            // Multi-file plugin, let's see if the directory is correctly named.
1001
+            $desired_slug = '';
1002
+
1003
+            // Figure out what the slug is supposed to be.
1004
+            if ( false === $upgrader->bulk && ! empty( $upgrader->skin->options['extra']['slug'] ) ) {
1005
+                $desired_slug = $upgrader->skin->options['extra']['slug'];
1006
+            } else {
1007
+                // Bulk installer contains less info, so fall back on the info registered here.
1008
+                foreach ( $this->plugins as $slug => $plugin ) {
1009
+                    if ( ! empty( $upgrader->skin->plugin_names[ $upgrader->skin->i ] ) && $plugin['name'] === $upgrader->skin->plugin_names[ $upgrader->skin->i ] ) {
1010
+                        $desired_slug = $slug;
1011
+                        break;
1012
+                    }
1013
+                }
1014
+                unset( $slug, $plugin );
1015
+            }
1016
+
1017
+            if ( ! empty( $desired_slug ) ) {
1018
+                $subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
1019
+
1020
+                if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
1021
+                    $from_path = untrailingslashit( $source );
1022
+                    $to_path   = trailingslashit( $remote_source ) . $desired_slug;
1023
+
1024
+                    if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
1025
+                        return trailingslashit( $to_path );
1026
+                    } else {
1027
+                        return new WP_Error( 'rename_failed', esc_html__( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'tgmpa' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'tgmpa' ), array( 'found' => $subdir_name, 'expected' => $desired_slug ) );
1028
+                    }
1029
+                } elseif ( empty( $subdir_name ) ) {
1030
+                    return new WP_Error( 'packaged_wrong', esc_html__( 'The remote plugin package consists of more than one file, but the files are not packaged in a folder.', 'tgmpa' ) . ' ' . esc_html__( 'Please contact the plugin provider and ask them to package their plugin according to the WordPress guidelines.', 'tgmpa' ), array( 'found' => $subdir_name, 'expected' => $desired_slug ) );
1031
+                }
1032
+            }
1033
+
1034
+            return $source;
1035
+        }
1036
+
1037
+        /**
1038
+         * Activate a single plugin and send feedback about the result to the screen.
1039
+         *
1040
+         * @since 2.5.0
1041
+         *
1042
+         * @param string $file_path Path within wp-plugins/ to main plugin file.
1043
+         * @param string $slug      Plugin slug.
1044
+         * @param bool   $automatic Whether this is an automatic activation after an install. Defaults to false.
1045
+         *                          This determines the styling of the output messages.
1046
+         * @return bool False if an error was encountered, true otherwise.
1047
+         */
1048
+        protected function activate_single_plugin( $file_path, $slug, $automatic = false ) {
1049
+            if ( $this->can_plugin_activate( $slug ) ) {
1050
+                $activate = activate_plugin( $file_path );
1051
+
1052
+                if ( is_wp_error( $activate ) ) {
1053
+                    echo '<div id="message" class="error"><p>', wp_kses_post( $activate->get_error_message() ), '</p></div>',
1054
+                        '<p><a href="', esc_url( $this->get_tgmpa_url() ), '" target="_parent">', esc_html( $this->strings['return'] ), '</a></p>';
1055
+
1056
+                    return false; // End it here if there is an error with activation.
1057
+                } else {
1058
+                    if ( ! $automatic ) {
1059
+                        // Make sure message doesn't display again if bulk activation is performed
1060
+                        // immediately after a single activation.
1061
+                        if ( ! isset( $_POST['action'] ) ) { // WPCS: CSRF OK.
1062
+                            echo '<div id="message" class="updated"><p>', esc_html( $this->strings['activated_successfully'] ), ' <strong>', esc_html( $this->plugins[ $slug ]['name'] ), '.</strong></p></div>';
1063
+                        }
1064
+                    } else {
1065
+                        // Simpler message layout for use on the plugin install page.
1066
+                        echo '<p>', esc_html( $this->strings['plugin_activated'] ), '</p>';
1067
+                    }
1068
+                }
1069
+            } elseif ( $this->is_plugin_active( $slug ) ) {
1070
+                // No simpler message format provided as this message should never be encountered
1071
+                // on the plugin install page.
1072
+                echo '<div id="message" class="error"><p>',
1073
+                    sprintf(
1074
+                        esc_html( $this->strings['plugin_already_active'] ),
1075
+                        '<strong>' . esc_html( $this->plugins[ $slug ]['name'] ) . '</strong>'
1076
+                    ),
1077
+                    '</p></div>';
1078
+            } elseif ( $this->does_plugin_require_update( $slug ) ) {
1079
+                if ( ! $automatic ) {
1080
+                    // Make sure message doesn't display again if bulk activation is performed
1081
+                    // immediately after a single activation.
1082
+                    if ( ! isset( $_POST['action'] ) ) { // WPCS: CSRF OK.
1083
+                        echo '<div id="message" class="error"><p>',
1084
+                            sprintf(
1085
+                                esc_html( $this->strings['plugin_needs_higher_version'] ),
1086
+                                '<strong>' . esc_html( $this->plugins[ $slug ]['name'] ) . '</strong>'
1087
+                            ),
1088
+                            '</p></div>';
1089
+                    }
1090
+                } else {
1091
+                    // Simpler message layout for use on the plugin install page.
1092
+                    echo '<p>', sprintf( esc_html( $this->strings['plugin_needs_higher_version'] ), esc_html( $this->plugins[ $slug ]['name'] ) ), '</p>';
1093
+                }
1094
+            }
1095
+
1096
+            return true;
1097
+        }
1098
+
1099
+        /**
1100
+         * Echoes required plugin notice.
1101
+         *
1102
+         * Outputs a message telling users that a specific plugin is required for
1103
+         * their theme. If appropriate, it includes a link to the form page where
1104
+         * users can install and activate the plugin.
1105
+         *
1106
+         * Returns early if we're on the Install page.
1107
+         *
1108
+         * @since 1.0.0
1109
+         *
1110
+         * @global object $current_screen
1111
+         *
1112
+         * @return null Returns early if we're on the Install page.
1113
+         */
1114
+        public function notices() {
1115
+            // Remove nag on the install page / Return early if the nag message has been dismissed or user < author.
1116
+            if ( ( $this->is_tgmpa_page() || $this->is_core_update_page() ) || get_user_meta( get_current_user_id(), 'tgmpa_dismissed_notice_' . $this->id, true ) || ! current_user_can( apply_filters( 'tgmpa_show_admin_notice_capability', 'publish_posts' ) ) ) {
1117
+                return;
1118
+            }
1119
+
1120
+            // Store for the plugin slugs by message type.
1121
+            $message = array();
1122
+
1123
+            // Initialize counters used to determine plurality of action link texts.
1124
+            $install_link_count          = 0;
1125
+            $update_link_count           = 0;
1126
+            $activate_link_count         = 0;
1127
+            $total_required_action_count = 0;
1128
+
1129
+            foreach ( $this->plugins as $slug => $plugin ) {
1130
+                if ( $this->is_plugin_active( $slug ) && false === $this->does_plugin_have_update( $slug ) ) {
1131
+                    continue;
1132
+                }
1133
+
1134
+                if ( ! $this->is_plugin_installed( $slug ) ) {
1135
+                    if ( current_user_can( 'install_plugins' ) ) {
1136
+                        $install_link_count++;
1137
+
1138
+                        if ( true === $plugin['required'] ) {
1139
+                            $message['notice_can_install_required'][] = $slug;
1140
+                        } else {
1141
+                            $message['notice_can_install_recommended'][] = $slug;
1142
+                        }
1143
+                    }
1144
+                    if ( true === $plugin['required'] ) {
1145
+                        $total_required_action_count++;
1146
+                    }
1147
+                } else {
1148
+                    if ( ! $this->is_plugin_active( $slug ) && $this->can_plugin_activate( $slug ) ) {
1149
+                        if ( current_user_can( 'activate_plugins' ) ) {
1150
+                            $activate_link_count++;
1151
+
1152
+                            if ( true === $plugin['required'] ) {
1153
+                                $message['notice_can_activate_required'][] = $slug;
1154
+                            } else {
1155
+                                $message['notice_can_activate_recommended'][] = $slug;
1156
+                            }
1157
+                        }
1158
+                        if ( true === $plugin['required'] ) {
1159
+                            $total_required_action_count++;
1160
+                        }
1161
+                    }
1162
+
1163
+                    if ( $this->does_plugin_require_update( $slug ) || false !== $this->does_plugin_have_update( $slug ) ) {
1164
+
1165
+                        if ( current_user_can( 'update_plugins' ) ) {
1166
+                            $update_link_count++;
1167
+
1168
+                            if ( $this->does_plugin_require_update( $slug ) ) {
1169
+                                $message['notice_ask_to_update'][] = $slug;
1170
+                            } elseif ( false !== $this->does_plugin_have_update( $slug ) ) {
1171
+                                $message['notice_ask_to_update_maybe'][] = $slug;
1172
+                            }
1173
+                        }
1174
+                        if ( true === $plugin['required'] ) {
1175
+                            $total_required_action_count++;
1176
+                        }
1177
+                    }
1178
+                }
1179
+            }
1180
+            unset( $slug, $plugin );
1181
+
1182
+            // If we have notices to display, we move forward.
1183
+            if ( ! empty( $message ) || $total_required_action_count > 0 ) {
1184
+                krsort( $message ); // Sort messages.
1185
+                $rendered = '';
1186
+
1187
+                // As add_settings_error() wraps the final message in a <p> and as the final message can't be
1188
+                // filtered, using <p>'s in our html would render invalid html output.
1189
+                $line_template = '<span style="display: block; margin: 0.5em 0.5em 0 0; clear: both;">%s</span>' . "\n";
1190
+
1191
+                if ( ! current_user_can( 'activate_plugins' ) && ! current_user_can( 'install_plugins' ) && ! current_user_can( 'update_plugins' ) ) {
1192
+                    $rendered  = esc_html( $this->strings['notice_cannot_install_activate'] ) . ' ' . esc_html( $this->strings['contact_admin'] );
1193
+                    $rendered .= $this->create_user_action_links_for_notice( 0, 0, 0, $line_template );
1194
+                } else {
1195
+
1196
+                    // If dismissable is false and a message is set, output it now.
1197
+                    if ( ! $this->dismissable && ! empty( $this->dismiss_msg ) ) {
1198
+                        $rendered .= sprintf( $line_template, wp_kses_post( $this->dismiss_msg ) );
1199
+                    }
1200
+
1201
+                    // Render the individual message lines for the notice.
1202
+                    foreach ( $message as $type => $plugin_group ) {
1203
+                        $linked_plugins = array();
1204
+
1205
+                        // Get the external info link for a plugin if one is available.
1206
+                        foreach ( $plugin_group as $plugin_slug ) {
1207
+                            $linked_plugins[] = $this->get_info_link( $plugin_slug );
1208
+                        }
1209
+                        unset( $plugin_slug );
1210
+
1211
+                        $count          = count( $plugin_group );
1212
+                        $linked_plugins = array_map( array( 'TGMPA_Utils', 'wrap_in_em' ), $linked_plugins );
1213
+                        $last_plugin    = array_pop( $linked_plugins ); // Pop off last name to prep for readability.
1214
+                        $imploded       = empty( $linked_plugins ) ? $last_plugin : ( implode( ', ', $linked_plugins ) . ' ' . esc_html_x( 'and', 'plugin A *and* plugin B', 'tgmpa' ) . ' ' . $last_plugin );
1215
+
1216
+                        $rendered .= sprintf(
1217
+                            $line_template,
1218
+                            sprintf(
1219
+                                translate_nooped_plural( $this->strings[ $type ], $count, 'tgmpa' ),
1220
+                                $imploded,
1221
+                                $count
1222
+                            )
1223
+                        );
1224
+
1225
+                    }
1226
+                    unset( $type, $plugin_group, $linked_plugins, $count, $last_plugin, $imploded );
1227
+
1228
+                    $rendered .= $this->create_user_action_links_for_notice( $install_link_count, $update_link_count, $activate_link_count, $line_template );
1229
+                }
1230
+
1231
+                // Register the nag messages and prepare them to be processed.
1232
+                add_settings_error( 'tgmpa', 'tgmpa', $rendered, $this->get_admin_notice_class() );
1233
+            }
1234
+
1235
+            // Admin options pages already output settings_errors, so this is to avoid duplication.
1236
+            if ( 'options-general' !== $GLOBALS['current_screen']->parent_base ) {
1237
+                $this->display_settings_errors();
1238
+            }
1239
+        }
1240
+
1241
+        /**
1242
+         * Generate the user action links for the admin notice.
1243
+         *
1244
+         * @since 2.6.0
1245
+         *
1246
+         * @param int $install_count  Number of plugins to install.
1247
+         * @param int $update_count   Number of plugins to update.
1248
+         * @param int $activate_count Number of plugins to activate.
1249
+         * @param int $line_template  Template for the HTML tag to output a line.
1250
+         * @return string Action links.
1251
+         */
1252
+        protected function create_user_action_links_for_notice( $install_count, $update_count, $activate_count, $line_template ) {
1253
+            // Setup action links.
1254
+            $action_links = array(
1255
+                'install'  => '',
1256
+                'update'   => '',
1257
+                'activate' => '',
1258
+                'dismiss'  => $this->dismissable ? '<a href="' . esc_url( wp_nonce_url( add_query_arg( 'tgmpa-dismiss', 'dismiss_admin_notices' ), 'tgmpa-dismiss-' . get_current_user_id() ) ) . '" class="dismiss-notice" target="_parent">' . esc_html( $this->strings['dismiss'] ) . '</a>' : '',
1259
+            );
1260
+
1261
+            $link_template = '<a href="%2$s">%1$s</a>';
1262
+
1263
+            if ( current_user_can( 'install_plugins' ) ) {
1264
+                if ( $install_count > 0 ) {
1265
+                    $action_links['install'] = sprintf(
1266
+                        $link_template,
1267
+                        translate_nooped_plural( $this->strings['install_link'], $install_count, 'tgmpa' ),
1268
+                        esc_url( $this->get_tgmpa_status_url( 'install' ) )
1269
+                    );
1270
+                }
1271
+                if ( $update_count > 0 ) {
1272
+                    $action_links['update'] = sprintf(
1273
+                        $link_template,
1274
+                        translate_nooped_plural( $this->strings['update_link'], $update_count, 'tgmpa' ),
1275
+                        esc_url( $this->get_tgmpa_status_url( 'update' ) )
1276
+                    );
1277
+                }
1278
+            }
1279
+
1280
+            if ( current_user_can( 'activate_plugins' ) && $activate_count > 0 ) {
1281
+                $action_links['activate'] = sprintf(
1282
+                    $link_template,
1283
+                    translate_nooped_plural( $this->strings['activate_link'], $activate_count, 'tgmpa' ),
1284
+                    esc_url( $this->get_tgmpa_status_url( 'activate' ) )
1285
+                );
1286
+            }
1287
+
1288
+            $action_links = apply_filters( 'tgmpa_notice_action_links', $action_links );
1289
+
1290
+            $action_links = array_filter( (array) $action_links ); // Remove any empty array items.
1291
+
1292
+            if ( ! empty( $action_links ) ) {
1293
+                $action_links = sprintf( $line_template, implode( ' | ', $action_links ) );
1294
+                return apply_filters( 'tgmpa_notice_rendered_action_links', $action_links );
1295
+            } else {
1296
+                return '';
1297
+            }
1298
+        }
1299
+
1300
+        /**
1301
+         * Get admin notice class.
1302
+         *
1303
+         * Work around all the changes to the various admin notice classes between WP 4.4 and 3.7
1304
+         * (lowest supported version by TGMPA).
1305
+         *
1306
+         * @since 2.6.0
1307
+         *
1308
+         * @return string
1309
+         */
1310
+        protected function get_admin_notice_class() {
1311
+            if ( ! empty( $this->strings['nag_type'] ) ) {
1312
+                return sanitize_html_class( strtolower( $this->strings['nag_type'] ) );
1313
+            } else {
1314
+                if ( version_compare( $this->wp_version, '4.2', '>=' ) ) {
1315
+                    return 'notice-warning';
1316
+                } elseif ( version_compare( $this->wp_version, '4.1', '>=' ) ) {
1317
+                    return 'notice';
1318
+                } else {
1319
+                    return 'updated';
1320
+                }
1321
+            }
1322
+        }
1323
+
1324
+        /**
1325
+         * Display settings errors and remove those which have been displayed to avoid duplicate messages showing
1326
+         *
1327
+         * @since 2.5.0
1328
+         */
1329
+        protected function display_settings_errors() {
1330
+            global $wp_settings_errors;
1331
+
1332
+            settings_errors( 'tgmpa' );
1333
+
1334
+            foreach ( (array) $wp_settings_errors as $key => $details ) {
1335
+                if ( 'tgmpa' === $details['setting'] ) {
1336
+                    unset( $wp_settings_errors[ $key ] );
1337
+                    break;
1338
+                }
1339
+            }
1340
+        }
1341
+
1342
+        /**
1343
+         * Register dismissal of admin notices.
1344
+         *
1345
+         * Acts on the dismiss link in the admin nag messages.
1346
+         * If clicked, the admin notice disappears and will no longer be visible to this user.
1347
+         *
1348
+         * @since 2.1.0
1349
+         */
1350
+        public function dismiss() {
1351
+            if ( isset( $_GET['tgmpa-dismiss'] ) && check_admin_referer( 'tgmpa-dismiss-' . get_current_user_id() ) ) {
1352
+                update_user_meta( get_current_user_id(), 'tgmpa_dismissed_notice_' . $this->id, 1 );
1353
+            }
1354
+        }
1355
+
1356
+        /**
1357
+         * Add individual plugin to our collection of plugins.
1358
+         *
1359
+         * If the required keys are not set or the plugin has already
1360
+         * been registered, the plugin is not added.
1361
+         *
1362
+         * @since 2.0.0
1363
+         *
1364
+         * @param array|null $plugin Array of plugin arguments or null if invalid argument.
1365
+         * @return null Return early if incorrect argument.
1366
+         */
1367
+        public function register( $plugin ) {
1368
+            if ( empty( $plugin['slug'] ) || empty( $plugin['name'] ) ) {
1369
+                return;
1370
+            }
1371
+
1372
+            if ( empty( $plugin['slug'] ) || ! is_string( $plugin['slug'] ) || isset( $this->plugins[ $plugin['slug'] ] ) ) {
1373
+                return;
1374
+            }
1375
+
1376
+            $defaults = array(
1377
+                'name'               => '',      // String
1378
+                'slug'               => '',      // String
1379
+                'source'             => 'repo',  // String
1380
+                'required'           => false,   // Boolean
1381
+                'version'            => '',      // String
1382
+                'force_activation'   => false,   // Boolean
1383
+                'force_deactivation' => false,   // Boolean
1384
+                'external_url'       => '',      // String
1385
+                'is_callable'        => '',      // String|Array.
1386
+            );
1387
+
1388
+            // Prepare the received data.
1389
+            $plugin = wp_parse_args( $plugin, $defaults );
1390
+
1391
+            // Standardize the received slug.
1392
+            $plugin['slug'] = $this->sanitize_key( $plugin['slug'] );
1393
+
1394
+            // Forgive users for using string versions of booleans or floats for version number.
1395
+            $plugin['version']            = (string) $plugin['version'];
1396
+            $plugin['source']             = empty( $plugin['source'] ) ? 'repo' : $plugin['source'];
1397
+            $plugin['required']           = TGMPA_Utils::validate_bool( $plugin['required'] );
1398
+            $plugin['force_activation']   = TGMPA_Utils::validate_bool( $plugin['force_activation'] );
1399
+            $plugin['force_deactivation'] = TGMPA_Utils::validate_bool( $plugin['force_deactivation'] );
1400
+
1401
+            // Enrich the received data.
1402
+            $plugin['file_path']   = $this->_get_plugin_basename_from_slug( $plugin['slug'] );
1403
+            $plugin['source_type'] = $this->get_plugin_source_type( $plugin['source'] );
1404
+
1405
+            // Set the class properties.
1406
+            $this->plugins[ $plugin['slug'] ]    = $plugin;
1407
+            $this->sort_order[ $plugin['slug'] ] = $plugin['name'];
1408
+
1409
+            // Should we add the force activation hook ?
1410
+            if ( true === $plugin['force_activation'] ) {
1411
+                $this->has_forced_activation = true;
1412
+            }
1413
+
1414
+            // Should we add the force deactivation hook ?
1415
+            if ( true === $plugin['force_deactivation'] ) {
1416
+                $this->has_forced_deactivation = true;
1417
+            }
1418
+        }
1419
+
1420
+        /**
1421
+         * Determine what type of source the plugin comes from.
1422
+         *
1423
+         * @since 2.5.0
1424
+         *
1425
+         * @param string $source The source of the plugin as provided, either empty (= WP repo), a file path
1426
+         *                       (= bundled) or an external URL.
1427
+         * @return string 'repo', 'external', or 'bundled'
1428
+         */
1429
+        protected function get_plugin_source_type( $source ) {
1430
+            if ( 'repo' === $source || preg_match( self::WP_REPO_REGEX, $source ) ) {
1431
+                return 'repo';
1432
+            } elseif ( preg_match( self::IS_URL_REGEX, $source ) ) {
1433
+                return 'external';
1434
+            } else {
1435
+                return 'bundled';
1436
+            }
1437
+        }
1438
+
1439
+        /**
1440
+         * Sanitizes a string key.
1441
+         *
1442
+         * Near duplicate of WP Core `sanitize_key()`. The difference is that uppercase characters *are*
1443
+         * allowed, so as not to break upgrade paths from non-standard bundled plugins using uppercase
1444
+         * characters in the plugin directory path/slug. Silly them.
1445
+         *
1446
+         * @see https://developer.wordpress.org/reference/hooks/sanitize_key/
1447
+         *
1448
+         * @since 2.5.0
1449
+         *
1450
+         * @param string $key String key.
1451
+         * @return string Sanitized key
1452
+         */
1453
+        public function sanitize_key( $key ) {
1454
+            $raw_key = $key;
1455
+            $key     = preg_replace( '`[^A-Za-z0-9_-]`', '', $key );
1456
+
1457
+            /**
1458
+             * Filter a sanitized key string.
1459
+             *
1460
+             * @since 2.5.0
1461
+             *
1462
+             * @param string $key     Sanitized key.
1463
+             * @param string $raw_key The key prior to sanitization.
1464
+             */
1465
+            return apply_filters( 'tgmpa_sanitize_key', $key, $raw_key );
1466
+        }
1467
+
1468
+        /**
1469
+         * Amend default configuration settings.
1470
+         *
1471
+         * @since 2.0.0
1472
+         *
1473
+         * @param array $config Array of config options to pass as class properties.
1474
+         */
1475
+        public function config( $config ) {
1476
+            $keys = array(
1477
+                'id',
1478
+                'default_path',
1479
+                'has_notices',
1480
+                'dismissable',
1481
+                'dismiss_msg',
1482
+                'menu',
1483
+                'parent_slug',
1484
+                'capability',
1485
+                'is_automatic',
1486
+                'message',
1487
+                'strings',
1488
+            );
1489
+
1490
+            foreach ( $keys as $key ) {
1491
+                if ( isset( $config[ $key ] ) ) {
1492
+                    if ( is_array( $config[ $key ] ) ) {
1493
+                        $this->$key = array_merge( $this->$key, $config[ $key ] );
1494
+                    } else {
1495
+                        $this->$key = $config[ $key ];
1496
+                    }
1497
+                }
1498
+            }
1499
+        }
1500
+
1501
+        /**
1502
+         * Amend action link after plugin installation.
1503
+         *
1504
+         * @since 2.0.0
1505
+         *
1506
+         * @param array $install_actions Existing array of actions.
1507
+         * @return false|array Amended array of actions.
1508
+         */
1509
+        public function actions( $install_actions ) {
1510
+            // Remove action links on the TGMPA install page.
1511
+            if ( $this->is_tgmpa_page() ) {
1512
+                return false;
1513
+            }
1514
+
1515
+            return $install_actions;
1516
+        }
1517
+
1518
+        /**
1519
+         * Flushes the plugins cache on theme switch to prevent stale entries
1520
+         * from remaining in the plugin table.
1521
+         *
1522
+         * @since 2.4.0
1523
+         *
1524
+         * @param bool $clear_update_cache Optional. Whether to clear the Plugin updates cache.
1525
+         *                                 Parameter added in v2.5.0.
1526
+         */
1527
+        public function flush_plugins_cache( $clear_update_cache = true ) {
1528
+            wp_clean_plugins_cache( $clear_update_cache );
1529
+        }
1530
+
1531
+        /**
1532
+         * Set file_path key for each installed plugin.
1533
+         *
1534
+         * @since 2.1.0
1535
+         *
1536
+         * @param string $plugin_slug Optional. If set, only (re-)populates the file path for that specific plugin.
1537
+         *                            Parameter added in v2.5.0.
1538
+         */
1539
+        public function populate_file_path( $plugin_slug = '' ) {
1540
+            if ( ! empty( $plugin_slug ) && is_string( $plugin_slug ) && isset( $this->plugins[ $plugin_slug ] ) ) {
1541
+                $this->plugins[ $plugin_slug ]['file_path'] = $this->_get_plugin_basename_from_slug( $plugin_slug );
1542
+            } else {
1543
+                // Add file_path key for all plugins.
1544
+                foreach ( $this->plugins as $slug => $values ) {
1545
+                    $this->plugins[ $slug ]['file_path'] = $this->_get_plugin_basename_from_slug( $slug );
1546
+                }
1547
+            }
1548
+        }
1549
+
1550
+        /**
1551
+         * Helper function to extract the file path of the plugin file from the
1552
+         * plugin slug, if the plugin is installed.
1553
+         *
1554
+         * @since 2.0.0
1555
+         *
1556
+         * @param string $slug Plugin slug (typically folder name) as provided by the developer.
1557
+         * @return string Either file path for plugin if installed, or just the plugin slug.
1558
+         */
1559
+        protected function _get_plugin_basename_from_slug( $slug ) {
1560
+            $keys = array_keys( $this->get_plugins() );
1561
+
1562
+            foreach ( $keys as $key ) {
1563
+                if ( preg_match( '|^' . $slug . '/|', $key ) ) {
1564
+                    return $key;
1565
+                }
1566
+            }
1567
+
1568
+            return $slug;
1569
+        }
1570
+
1571
+        /**
1572
+         * Retrieve plugin data, given the plugin name.
1573
+         *
1574
+         * Loops through the registered plugins looking for $name. If it finds it,
1575
+         * it returns the $data from that plugin. Otherwise, returns false.
1576
+         *
1577
+         * @since 2.1.0
1578
+         *
1579
+         * @param string $name Name of the plugin, as it was registered.
1580
+         * @param string $data Optional. Array key of plugin data to return. Default is slug.
1581
+         * @return string|boolean Plugin slug if found, false otherwise.
1582
+         */
1583
+        public function _get_plugin_data_from_name( $name, $data = 'slug' ) {
1584
+            foreach ( $this->plugins as $values ) {
1585
+                if ( $name === $values['name'] && isset( $values[ $data ] ) ) {
1586
+                    return $values[ $data ];
1587
+                }
1588
+            }
1589
+
1590
+            return false;
1591
+        }
1592
+
1593
+        /**
1594
+         * Retrieve the download URL for a package.
1595
+         *
1596
+         * @since 2.5.0
1597
+         *
1598
+         * @param string $slug Plugin slug.
1599
+         * @return string Plugin download URL or path to local file or empty string if undetermined.
1600
+         */
1601
+        public function get_download_url( $slug ) {
1602
+            $dl_source = '';
1603
+
1604
+            switch ( $this->plugins[ $slug ]['source_type'] ) {
1605
+                case 'repo':
1606
+                    return $this->get_wp_repo_download_url( $slug );
1607
+                case 'external':
1608
+                    return $this->plugins[ $slug ]['source'];
1609
+                case 'bundled':
1610
+                    return $this->default_path . $this->plugins[ $slug ]['source'];
1611
+            }
1612
+
1613
+            return $dl_source; // Should never happen.
1614
+        }
1615
+
1616
+        /**
1617
+         * Retrieve the download URL for a WP repo package.
1618
+         *
1619
+         * @since 2.5.0
1620
+         *
1621
+         * @param string $slug Plugin slug.
1622
+         * @return string Plugin download URL.
1623
+         */
1624
+        protected function get_wp_repo_download_url( $slug ) {
1625
+            $source = '';
1626
+            $api    = $this->get_plugins_api( $slug );
1627
+
1628
+            if ( false !== $api && isset( $api->download_link ) ) {
1629
+                $source = $api->download_link;
1630
+            }
1631
+
1632
+            return $source;
1633
+        }
1634
+
1635
+        /**
1636
+         * Try to grab information from WordPress API.
1637
+         *
1638
+         * @since 2.5.0
1639
+         *
1640
+         * @param string $slug Plugin slug.
1641
+         * @return object Plugins_api response object on success, WP_Error on failure.
1642
+         */
1643
+        protected function get_plugins_api( $slug ) {
1644
+            static $api = array(); // Cache received responses.
1645
+
1646
+            if ( ! isset( $api[ $slug ] ) ) {
1647
+                if ( ! function_exists( 'plugins_api' ) ) {
1648
+                    require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
1649
+                }
1650
+
1651
+                $response = plugins_api( 'plugin_information', array( 'slug' => $slug, 'fields' => array( 'sections' => false ) ) );
1652
+
1653
+                $api[ $slug ] = false;
1654
+
1655
+                if ( is_wp_error( $response ) ) {
1656
+                    wp_die( esc_html( $this->strings['oops'] ) );
1657
+                } else {
1658
+                    $api[ $slug ] = $response;
1659
+                }
1660
+            }
1661
+
1662
+            return $api[ $slug ];
1663
+        }
1664
+
1665
+        /**
1666
+         * Retrieve a link to a plugin information page.
1667
+         *
1668
+         * @since 2.5.0
1669
+         *
1670
+         * @param string $slug Plugin slug.
1671
+         * @return string Fully formed html link to a plugin information page if available
1672
+         *                or the plugin name if not.
1673
+         */
1674
+        public function get_info_link( $slug ) {
1675
+            if ( ! empty( $this->plugins[ $slug ]['external_url'] ) && preg_match( self::IS_URL_REGEX, $this->plugins[ $slug ]['external_url'] ) ) {
1676
+                $link = sprintf(
1677
+                    '<a href="%1$s" target="_blank">%2$s</a>',
1678
+                    esc_url( $this->plugins[ $slug ]['external_url'] ),
1679
+                    esc_html( $this->plugins[ $slug ]['name'] )
1680
+                );
1681
+            } elseif ( 'repo' === $this->plugins[ $slug ]['source_type'] ) {
1682
+                $url = add_query_arg(
1683
+                    array(
1684
+                        'tab'       => 'plugin-information',
1685
+                        'plugin'    => urlencode( $slug ),
1686
+                        'TB_iframe' => 'true',
1687
+                        'width'     => '640',
1688
+                        'height'    => '500',
1689
+                    ),
1690
+                    self_admin_url( 'plugin-install.php' )
1691
+                );
1692
+
1693
+                $link = sprintf(
1694
+                    '<a href="%1$s" class="thickbox">%2$s</a>',
1695
+                    esc_url( $url ),
1696
+                    esc_html( $this->plugins[ $slug ]['name'] )
1697
+                );
1698
+            } else {
1699
+                $link = esc_html( $this->plugins[ $slug ]['name'] ); // No hyperlink.
1700
+            }
1701
+
1702
+            return $link;
1703
+        }
1704
+
1705
+        /**
1706
+         * Determine if we're on the TGMPA Install page.
1707
+         *
1708
+         * @since 2.1.0
1709
+         *
1710
+         * @return boolean True when on the TGMPA page, false otherwise.
1711
+         */
1712
+        protected function is_tgmpa_page() {
1713
+            return isset( $_GET['page'] ) && $this->menu === $_GET['page'];
1714
+        }
1715
+
1716
+        /**
1717
+         * Determine if we're on a WP Core installation/upgrade page.
1718
+         *
1719
+         * @since 2.6.0
1720
+         *
1721
+         * @return boolean True when on a WP Core installation/upgrade page, false otherwise.
1722
+         */
1723
+        protected function is_core_update_page() {
1724
+            // Current screen is not always available, most notably on the customizer screen.
1725
+            if ( ! function_exists( 'get_current_screen' ) ) {
1726
+                return false;
1727
+            }
1728
+
1729
+            $screen = get_current_screen();
1730
+
1731
+            if ( 'update-core' === $screen->base ) {
1732
+                // Core update screen.
1733
+                return true;
1734
+            } elseif ( 'plugins' === $screen->base && ! empty( $_POST['action'] ) ) { // WPCS: CSRF ok.
1735
+                // Plugins bulk update screen.
1736
+                return true;
1737
+            } elseif ( 'update' === $screen->base && ! empty( $_POST['action'] ) ) { // WPCS: CSRF ok.
1738
+                // Individual updates (ajax call).
1739
+                return true;
1740
+            }
1741
+
1742
+            return false;
1743
+        }
1744
+
1745
+        /**
1746
+         * Retrieve the URL to the TGMPA Install page.
1747
+         *
1748
+         * I.e. depending on the config settings passed something along the lines of:
1749
+         * http://example.com/wp-admin/themes.php?page=tgmpa-install-plugins
1750
+         *
1751
+         * @since 2.5.0
1752
+         *
1753
+         * @return string Properly encoded URL (not escaped).
1754
+         */
1755
+        public function get_tgmpa_url() {
1756
+            static $url;
1757
+
1758
+            if ( ! isset( $url ) ) {
1759
+                $parent = $this->parent_slug;
1760
+                if ( false === strpos( $parent, '.php' ) ) {
1761
+                    $parent = 'admin.php';
1762
+                }
1763
+                $url = add_query_arg(
1764
+                    array(
1765
+                        'page' => urlencode( $this->menu ),
1766
+                    ),
1767
+                    self_admin_url( $parent )
1768
+                );
1769
+            }
1770
+
1771
+            return $url;
1772
+        }
1773
+
1774
+        /**
1775
+         * Retrieve the URL to the TGMPA Install page for a specific plugin status (view).
1776
+         *
1777
+         * I.e. depending on the config settings passed something along the lines of:
1778
+         * http://example.com/wp-admin/themes.php?page=tgmpa-install-plugins&plugin_status=install
1779
+         *
1780
+         * @since 2.5.0
1781
+         *
1782
+         * @param string $status Plugin status - either 'install', 'update' or 'activate'.
1783
+         * @return string Properly encoded URL (not escaped).
1784
+         */
1785
+        public function get_tgmpa_status_url( $status ) {
1786
+            return add_query_arg(
1787
+                array(
1788
+                    'plugin_status' => urlencode( $status ),
1789
+                ),
1790
+                $this->get_tgmpa_url()
1791
+            );
1792
+        }
1793
+
1794
+        /**
1795
+         * Determine whether there are open actions for plugins registered with TGMPA.
1796
+         *
1797
+         * @since 2.5.0
1798
+         *
1799
+         * @return bool True if complete, i.e. no outstanding actions. False otherwise.
1800
+         */
1801
+        public function is_tgmpa_complete() {
1802
+            $complete = true;
1803
+            foreach ( $this->plugins as $slug => $plugin ) {
1804
+                if ( ! $this->is_plugin_active( $slug ) || false !== $this->does_plugin_have_update( $slug ) ) {
1805
+                    $complete = false;
1806
+                    break;
1807
+                }
1808
+            }
1809
+
1810
+            return $complete;
1811
+        }
1812
+
1813
+        /**
1814
+         * Check if a plugin is installed. Does not take must-use plugins into account.
1815
+         *
1816
+         * @since 2.5.0
1817
+         *
1818
+         * @param string $slug Plugin slug.
1819
+         * @return bool True if installed, false otherwise.
1820
+         */
1821
+        public function is_plugin_installed( $slug ) {
1822
+            $installed_plugins = $this->get_plugins(); // Retrieve a list of all installed plugins (WP cached).
1823
+
1824
+            return ( ! empty( $installed_plugins[ $this->plugins[ $slug ]['file_path'] ] ) );
1825
+        }
1826
+
1827
+        /**
1828
+         * Check if a plugin is active.
1829
+         *
1830
+         * @since 2.5.0
1831
+         *
1832
+         * @param string $slug Plugin slug.
1833
+         * @return bool True if active, false otherwise.
1834
+         */
1835
+        public function is_plugin_active( $slug ) {
1836
+            return ( ( ! empty( $this->plugins[ $slug ]['is_callable'] ) && is_callable( $this->plugins[ $slug ]['is_callable'] ) ) || is_plugin_active( $this->plugins[ $slug ]['file_path'] ) );
1837
+        }
1838
+
1839
+        /**
1840
+         * Check if a plugin can be updated, i.e. if we have information on the minimum WP version required
1841
+         * available, check whether the current install meets them.
1842
+         *
1843
+         * @since 2.5.0
1844
+         *
1845
+         * @param string $slug Plugin slug.
1846
+         * @return bool True if OK to update, false otherwise.
1847
+         */
1848
+        public function can_plugin_update( $slug ) {
1849
+            // We currently can't get reliable info on non-WP-repo plugins - issue #380.
1850
+            if ( 'repo' !== $this->plugins[ $slug ]['source_type'] ) {
1851
+                return true;
1852
+            }
1853
+
1854
+            $api = $this->get_plugins_api( $slug );
1855
+
1856
+            if ( false !== $api && isset( $api->requires ) ) {
1857
+                return version_compare( $this->wp_version, $api->requires, '>=' );
1858
+            }
1859
+
1860
+            // No usable info received from the plugins API, presume we can update.
1861
+            return true;
1862
+        }
1863
+
1864
+        /**
1865
+         * Check to see if the plugin is 'updatetable', i.e. installed, with an update available
1866
+         * and no WP version requirements blocking it.
1867
+         *
1868
+         * @since 2.6.0
1869
+         *
1870
+         * @param string $slug Plugin slug.
1871
+         * @return bool True if OK to proceed with update, false otherwise.
1872
+         */
1873
+        public function is_plugin_updatetable( $slug ) {
1874
+            if ( ! $this->is_plugin_installed( $slug ) ) {
1875
+                return false;
1876
+            } else {
1877
+                return ( false !== $this->does_plugin_have_update( $slug ) && $this->can_plugin_update( $slug ) );
1878
+            }
1879
+        }
1880
+
1881
+        /**
1882
+         * Check if a plugin can be activated, i.e. is not currently active and meets the minimum
1883
+         * plugin version requirements set in TGMPA (if any).
1884
+         *
1885
+         * @since 2.5.0
1886
+         *
1887
+         * @param string $slug Plugin slug.
1888
+         * @return bool True if OK to activate, false otherwise.
1889
+         */
1890
+        public function can_plugin_activate( $slug ) {
1891
+            return ( ! $this->is_plugin_active( $slug ) && ! $this->does_plugin_require_update( $slug ) );
1892
+        }
1893
+
1894
+        /**
1895
+         * Retrieve the version number of an installed plugin.
1896
+         *
1897
+         * @since 2.5.0
1898
+         *
1899
+         * @param string $slug Plugin slug.
1900
+         * @return string Version number as string or an empty string if the plugin is not installed
1901
+         *                or version unknown (plugins which don't comply with the plugin header standard).
1902
+         */
1903
+        public function get_installed_version( $slug ) {
1904
+            $installed_plugins = $this->get_plugins(); // Retrieve a list of all installed plugins (WP cached).
1905
+
1906
+            if ( ! empty( $installed_plugins[ $this->plugins[ $slug ]['file_path'] ]['Version'] ) ) {
1907
+                return $installed_plugins[ $this->plugins[ $slug ]['file_path'] ]['Version'];
1908
+            }
1909
+
1910
+            return '';
1911
+        }
1912
+
1913
+        /**
1914
+         * Check whether a plugin complies with the minimum version requirements.
1915
+         *
1916
+         * @since 2.5.0
1917
+         *
1918
+         * @param string $slug Plugin slug.
1919
+         * @return bool True when a plugin needs to be updated, otherwise false.
1920
+         */
1921
+        public function does_plugin_require_update( $slug ) {
1922
+            $installed_version = $this->get_installed_version( $slug );
1923
+            $minimum_version   = $this->plugins[ $slug ]['version'];
1924
+
1925
+            return version_compare( $minimum_version, $installed_version, '>' );
1926
+        }
1927
+
1928
+        /**
1929
+         * Check whether there is an update available for a plugin.
1930
+         *
1931
+         * @since 2.5.0
1932
+         *
1933
+         * @param string $slug Plugin slug.
1934
+         * @return false|string Version number string of the available update or false if no update available.
1935
+         */
1936
+        public function does_plugin_have_update( $slug ) {
1937
+            // Presume bundled and external plugins will point to a package which meets the minimum required version.
1938
+            if ( 'repo' !== $this->plugins[ $slug ]['source_type'] ) {
1939
+                if ( $this->does_plugin_require_update( $slug ) ) {
1940
+                    return $this->plugins[ $slug ]['version'];
1941
+                }
1942
+
1943
+                return false;
1944
+            }
1945
+
1946
+            $repo_updates = get_site_transient( 'update_plugins' );
1947
+
1948
+            if ( isset( $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->new_version ) ) {
1949
+                return $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->new_version;
1950
+            }
1951
+
1952
+            return false;
1953
+        }
1954
+
1955
+        /**
1956
+         * Retrieve potential upgrade notice for a plugin.
1957
+         *
1958
+         * @since 2.5.0
1959
+         *
1960
+         * @param string $slug Plugin slug.
1961
+         * @return string The upgrade notice or an empty string if no message was available or provided.
1962
+         */
1963
+        public function get_upgrade_notice( $slug ) {
1964
+            // We currently can't get reliable info on non-WP-repo plugins - issue #380.
1965
+            if ( 'repo' !== $this->plugins[ $slug ]['source_type'] ) {
1966
+                return '';
1967
+            }
1968
+
1969
+            $repo_updates = get_site_transient( 'update_plugins' );
1970
+
1971
+            if ( ! empty( $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->upgrade_notice ) ) {
1972
+                return $repo_updates->response[ $this->plugins[ $slug ]['file_path'] ]->upgrade_notice;
1973
+            }
1974
+
1975
+            return '';
1976
+        }
1977
+
1978
+        /**
1979
+         * Wrapper around the core WP get_plugins function, making sure it's actually available.
1980
+         *
1981
+         * @since 2.5.0
1982
+         *
1983
+         * @param string $plugin_folder Optional. Relative path to single plugin folder.
1984
+         * @return array Array of installed plugins with plugin information.
1985
+         */
1986
+        public function get_plugins( $plugin_folder = '' ) {
1987
+            if ( ! function_exists( 'get_plugins' ) ) {
1988
+                require_once ABSPATH . 'wp-admin/includes/plugin.php';
1989
+            }
1990
+
1991
+            return get_plugins( $plugin_folder );
1992
+        }
1993
+
1994
+        /**
1995
+         * Delete dismissable nag option when theme is switched.
1996
+         *
1997
+         * This ensures that the user(s) is/are again reminded via nag of required
1998
+         * and/or recommended plugins if they re-activate the theme.
1999
+         *
2000
+         * @since 2.1.1
2001
+         */
2002
+        public function update_dismiss() {
2003
+            delete_metadata( 'user', null, 'tgmpa_dismissed_notice_' . $this->id, null, true );
2004
+        }
2005
+
2006
+        /**
2007
+         * Forces plugin activation if the parameter 'force_activation' is
2008
+         * set to true.
2009
+         *
2010
+         * This allows theme authors to specify certain plugins that must be
2011
+         * active at all times while using the current theme.
2012
+         *
2013
+         * Please take special care when using this parameter as it has the
2014
+         * potential to be harmful if not used correctly. Setting this parameter
2015
+         * to true will not allow the specified plugin to be deactivated unless
2016
+         * the user switches themes.
2017
+         *
2018
+         * @since 2.2.0
2019
+         */
2020
+        public function force_activation() {
2021
+            foreach ( $this->plugins as $slug => $plugin ) {
2022
+                if ( true === $plugin['force_activation'] ) {
2023
+                    if ( ! $this->is_plugin_installed( $slug ) ) {
2024
+                        // Oops, plugin isn't there so iterate to next condition.
2025
+                        continue;
2026
+                    } elseif ( $this->can_plugin_activate( $slug ) ) {
2027
+                        // There we go, activate the plugin.
2028
+                        activate_plugin( $plugin['file_path'] );
2029
+                    }
2030
+                }
2031
+            }
2032
+        }
2033
+
2034
+        /**
2035
+         * Forces plugin deactivation if the parameter 'force_deactivation'
2036
+         * is set to true and adds the plugin to the 'recently active' plugins list.
2037
+         *
2038
+         * This allows theme authors to specify certain plugins that must be
2039
+         * deactivated upon switching from the current theme to another.
2040
+         *
2041
+         * Please take special care when using this parameter as it has the
2042
+         * potential to be harmful if not used correctly.
2043
+         *
2044
+         * @since 2.2.0
2045
+         */
2046
+        public function force_deactivation() {
2047
+            $deactivated = array();
2048
+
2049
+            foreach ( $this->plugins as $slug => $plugin ) {
2050
+                /*
2051 2051
 				 * Only proceed forward if the parameter is set to true and plugin is active
2052 2052
 				 * as a 'normal' (not must-use) plugin.
2053 2053
 				 */
2054
-				if ( true === $plugin['force_deactivation'] && is_plugin_active( $plugin['file_path'] ) ) {
2055
-					deactivate_plugins( $plugin['file_path'] );
2056
-					$deactivated[ $plugin['file_path'] ] = time();
2057
-				}
2058
-			}
2059
-
2060
-			if ( ! empty( $deactivated ) ) {
2061
-				update_option( 'recently_activated', $deactivated + (array) get_option( 'recently_activated' ) );
2062
-			}
2063
-		}
2064
-
2065
-		/**
2066
-		 * Echo the current TGMPA version number to the page.
2067
-		 *
2068
-		 * @since 2.5.0
2069
-		 */
2070
-		public function show_tgmpa_version() {
2071
-			echo '<p style="float: right; padding: 0em 1.5em 0.5em 0;"><strong><small>',
2072
-				esc_html(
2073
-					sprintf(
2074
-						/* translators: %s: version number */
2075
-						__( 'TGMPA v%s', 'tgmpa' ),
2076
-						self::TGMPA_VERSION
2077
-					)
2078
-				),
2079
-				'</small></strong></p>';
2080
-		}
2081
-
2082
-		/**
2083
-		 * Returns the singleton instance of the class.
2084
-		 *
2085
-		 * @since 2.4.0
2086
-		 *
2087
-		 * @return \TGM_Plugin_Activation The TGM_Plugin_Activation object.
2088
-		 */
2089
-		public static function get_instance() {
2090
-			if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
2091
-				self::$instance = new self();
2092
-			}
2093
-
2094
-			return self::$instance;
2095
-		}
2096
-	}
2097
-
2098
-	if ( ! function_exists( 'load_tgm_plugin_activation' ) ) {
2099
-		/**
2100
-		 * Ensure only one instance of the class is ever invoked.
2101
-		 *
2102
-		 * @since 2.5.0
2103
-		 */
2104
-		function load_tgm_plugin_activation() {
2105
-			$GLOBALS['tgmpa'] = TGM_Plugin_Activation::get_instance();
2106
-		}
2107
-	}
2108
-
2109
-	if ( did_action( 'plugins_loaded' ) ) {
2110
-		load_tgm_plugin_activation();
2111
-	} else {
2112
-		add_action( 'plugins_loaded', 'load_tgm_plugin_activation' );
2113
-	}
2054
+                if ( true === $plugin['force_deactivation'] && is_plugin_active( $plugin['file_path'] ) ) {
2055
+                    deactivate_plugins( $plugin['file_path'] );
2056
+                    $deactivated[ $plugin['file_path'] ] = time();
2057
+                }
2058
+            }
2059
+
2060
+            if ( ! empty( $deactivated ) ) {
2061
+                update_option( 'recently_activated', $deactivated + (array) get_option( 'recently_activated' ) );
2062
+            }
2063
+        }
2064
+
2065
+        /**
2066
+         * Echo the current TGMPA version number to the page.
2067
+         *
2068
+         * @since 2.5.0
2069
+         */
2070
+        public function show_tgmpa_version() {
2071
+            echo '<p style="float: right; padding: 0em 1.5em 0.5em 0;"><strong><small>',
2072
+                esc_html(
2073
+                    sprintf(
2074
+                        /* translators: %s: version number */
2075
+                        __( 'TGMPA v%s', 'tgmpa' ),
2076
+                        self::TGMPA_VERSION
2077
+                    )
2078
+                ),
2079
+                '</small></strong></p>';
2080
+        }
2081
+
2082
+        /**
2083
+         * Returns the singleton instance of the class.
2084
+         *
2085
+         * @since 2.4.0
2086
+         *
2087
+         * @return \TGM_Plugin_Activation The TGM_Plugin_Activation object.
2088
+         */
2089
+        public static function get_instance() {
2090
+            if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {
2091
+                self::$instance = new self();
2092
+            }
2093
+
2094
+            return self::$instance;
2095
+        }
2096
+    }
2097
+
2098
+    if ( ! function_exists( 'load_tgm_plugin_activation' ) ) {
2099
+        /**
2100
+         * Ensure only one instance of the class is ever invoked.
2101
+         *
2102
+         * @since 2.5.0
2103
+         */
2104
+        function load_tgm_plugin_activation() {
2105
+            $GLOBALS['tgmpa'] = TGM_Plugin_Activation::get_instance();
2106
+        }
2107
+    }
2108
+
2109
+    if ( did_action( 'plugins_loaded' ) ) {
2110
+        load_tgm_plugin_activation();
2111
+    } else {
2112
+        add_action( 'plugins_loaded', 'load_tgm_plugin_activation' );
2113
+    }
2114 2114
 }
2115 2115
 
2116 2116
 if ( ! function_exists( 'tgmpa' ) ) {
2117
-	/**
2118
-	 * Helper function to register a collection of required plugins.
2119
-	 *
2120
-	 * @since 2.0.0
2121
-	 * @api
2122
-	 *
2123
-	 * @param array $plugins An array of plugin arrays.
2124
-	 * @param array $config  Optional. An array of configuration values.
2125
-	 */
2126
-	function tgmpa( $plugins, $config = array() ) {
2127
-		$instance = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
2128
-
2129
-		foreach ( $plugins as $plugin ) {
2130
-			call_user_func( array( $instance, 'register' ), $plugin );
2131
-		}
2132
-
2133
-		if ( ! empty( $config ) && is_array( $config ) ) {
2134
-			// Send out notices for deprecated arguments passed.
2135
-			if ( isset( $config['notices'] ) ) {
2136
-				_deprecated_argument( __FUNCTION__, '2.2.0', 'The `notices` config parameter was renamed to `has_notices` in TGMPA 2.2.0. Please adjust your configuration.' );
2137
-				if ( ! isset( $config['has_notices'] ) ) {
2138
-					$config['has_notices'] = $config['notices'];
2139
-				}
2140
-			}
2141
-
2142
-			if ( isset( $config['parent_menu_slug'] ) ) {
2143
-				_deprecated_argument( __FUNCTION__, '2.4.0', 'The `parent_menu_slug` config parameter was removed in TGMPA 2.4.0. In TGMPA 2.5.0 an alternative was (re-)introduced. Please adjust your configuration. For more information visit the website: http://tgmpluginactivation.com/configuration/#h-configuration-options.' );
2144
-			}
2145
-			if ( isset( $config['parent_url_slug'] ) ) {
2146
-				_deprecated_argument( __FUNCTION__, '2.4.0', 'The `parent_url_slug` config parameter was removed in TGMPA 2.4.0. In TGMPA 2.5.0 an alternative was (re-)introduced. Please adjust your configuration. For more information visit the website: http://tgmpluginactivation.com/configuration/#h-configuration-options.' );
2147
-			}
2148
-
2149
-			call_user_func( array( $instance, 'config' ), $config );
2150
-		}
2151
-	}
2117
+    /**
2118
+     * Helper function to register a collection of required plugins.
2119
+     *
2120
+     * @since 2.0.0
2121
+     * @api
2122
+     *
2123
+     * @param array $plugins An array of plugin arrays.
2124
+     * @param array $config  Optional. An array of configuration values.
2125
+     */
2126
+    function tgmpa( $plugins, $config = array() ) {
2127
+        $instance = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
2128
+
2129
+        foreach ( $plugins as $plugin ) {
2130
+            call_user_func( array( $instance, 'register' ), $plugin );
2131
+        }
2132
+
2133
+        if ( ! empty( $config ) && is_array( $config ) ) {
2134
+            // Send out notices for deprecated arguments passed.
2135
+            if ( isset( $config['notices'] ) ) {
2136
+                _deprecated_argument( __FUNCTION__, '2.2.0', 'The `notices` config parameter was renamed to `has_notices` in TGMPA 2.2.0. Please adjust your configuration.' );
2137
+                if ( ! isset( $config['has_notices'] ) ) {
2138
+                    $config['has_notices'] = $config['notices'];
2139
+                }
2140
+            }
2141
+
2142
+            if ( isset( $config['parent_menu_slug'] ) ) {
2143
+                _deprecated_argument( __FUNCTION__, '2.4.0', 'The `parent_menu_slug` config parameter was removed in TGMPA 2.4.0. In TGMPA 2.5.0 an alternative was (re-)introduced. Please adjust your configuration. For more information visit the website: http://tgmpluginactivation.com/configuration/#h-configuration-options.' );
2144
+            }
2145
+            if ( isset( $config['parent_url_slug'] ) ) {
2146
+                _deprecated_argument( __FUNCTION__, '2.4.0', 'The `parent_url_slug` config parameter was removed in TGMPA 2.4.0. In TGMPA 2.5.0 an alternative was (re-)introduced. Please adjust your configuration. For more information visit the website: http://tgmpluginactivation.com/configuration/#h-configuration-options.' );
2147
+            }
2148
+
2149
+            call_user_func( array( $instance, 'config' ), $config );
2150
+        }
2151
+    }
2152 2152
 }
2153 2153
 
2154 2154
 /**
@@ -2158,980 +2158,980 @@  discard block
 block discarded – undo
2158 2158
  * @since 2.2.0
2159 2159
  */
2160 2160
 if ( ! class_exists( 'WP_List_Table' ) ) {
2161
-	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
2161
+    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
2162 2162
 }
2163 2163
 
2164 2164
 if ( ! class_exists( 'TGMPA_List_Table' ) ) {
2165 2165
 
2166
-	/**
2167
-	 * List table class for handling plugins.
2168
-	 *
2169
-	 * Extends the WP_List_Table class to provide a future-compatible
2170
-	 * way of listing out all required/recommended plugins.
2171
-	 *
2172
-	 * Gives users an interface similar to the Plugin Administration
2173
-	 * area with similar (albeit stripped down) capabilities.
2174
-	 *
2175
-	 * This class also allows for the bulk install of plugins.
2176
-	 *
2177
-	 * @since 2.2.0
2178
-	 *
2179
-	 * @package TGM-Plugin-Activation
2180
-	 * @author  Thomas Griffin
2181
-	 * @author  Gary Jones
2182
-	 */
2183
-	class TGMPA_List_Table extends WP_List_Table {
2184
-		/**
2185
-		 * TGMPA instance.
2186
-		 *
2187
-		 * @since 2.5.0
2188
-		 *
2189
-		 * @var object
2190
-		 */
2191
-		protected $tgmpa;
2192
-
2193
-		/**
2194
-		 * The currently chosen view.
2195
-		 *
2196
-		 * @since 2.5.0
2197
-		 *
2198
-		 * @var string One of: 'all', 'install', 'update', 'activate'
2199
-		 */
2200
-		public $view_context = 'all';
2201
-
2202
-		/**
2203
-		 * The plugin counts for the various views.
2204
-		 *
2205
-		 * @since 2.5.0
2206
-		 *
2207
-		 * @var array
2208
-		 */
2209
-		protected $view_totals = array(
2210
-			'all'      => 0,
2211
-			'install'  => 0,
2212
-			'update'   => 0,
2213
-			'activate' => 0,
2214
-		);
2215
-
2216
-		/**
2217
-		 * References parent constructor and sets defaults for class.
2218
-		 *
2219
-		 * @since 2.2.0
2220
-		 */
2221
-		public function __construct() {
2222
-			$this->tgmpa = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
2223
-
2224
-			parent::__construct(
2225
-				array(
2226
-					'singular' => 'plugin',
2227
-					'plural'   => 'plugins',
2228
-					'ajax'     => false,
2229
-				)
2230
-			);
2231
-
2232
-			if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'install', 'update', 'activate' ), true ) ) {
2233
-				$this->view_context = sanitize_key( $_REQUEST['plugin_status'] );
2234
-			}
2235
-
2236
-			add_filter( 'tgmpa_table_data_items', array( $this, 'sort_table_items' ) );
2237
-		}
2238
-
2239
-		/**
2240
-		 * Get a list of CSS classes for the <table> tag.
2241
-		 *
2242
-		 * Overruled to prevent the 'plural' argument from being added.
2243
-		 *
2244
-		 * @since 2.5.0
2245
-		 *
2246
-		 * @return array CSS classnames.
2247
-		 */
2248
-		public function get_table_classes() {
2249
-			return array( 'widefat', 'fixed' );
2250
-		}
2251
-
2252
-		/**
2253
-		 * Gathers and renames all of our plugin information to be used by WP_List_Table to create our table.
2254
-		 *
2255
-		 * @since 2.2.0
2256
-		 *
2257
-		 * @return array $table_data Information for use in table.
2258
-		 */
2259
-		protected function _gather_plugin_data() {
2260
-			// Load thickbox for plugin links.
2261
-			$this->tgmpa->admin_init();
2262
-			$this->tgmpa->thickbox();
2263
-
2264
-			// Categorize the plugins which have open actions.
2265
-			$plugins = $this->categorize_plugins_to_views();
2266
-
2267
-			// Set the counts for the view links.
2268
-			$this->set_view_totals( $plugins );
2269
-
2270
-			// Prep variables for use and grab list of all installed plugins.
2271
-			$table_data = array();
2272
-			$i          = 0;
2273
-
2274
-			// Redirect to the 'all' view if no plugins were found for the selected view context.
2275
-			if ( empty( $plugins[ $this->view_context ] ) ) {
2276
-				$this->view_context = 'all';
2277
-			}
2278
-
2279
-			foreach ( $plugins[ $this->view_context ] as $slug => $plugin ) {
2280
-				$table_data[ $i ]['sanitized_plugin']  = $plugin['name'];
2281
-				$table_data[ $i ]['slug']              = $slug;
2282
-				$table_data[ $i ]['plugin']            = '<strong>' . $this->tgmpa->get_info_link( $slug ) . '</strong>';
2283
-				$table_data[ $i ]['source']            = $this->get_plugin_source_type_text( $plugin['source_type'] );
2284
-				$table_data[ $i ]['type']              = $this->get_plugin_advise_type_text( $plugin['required'] );
2285
-				$table_data[ $i ]['status']            = $this->get_plugin_status_text( $slug );
2286
-				$table_data[ $i ]['installed_version'] = $this->tgmpa->get_installed_version( $slug );
2287
-				$table_data[ $i ]['minimum_version']   = $plugin['version'];
2288
-				$table_data[ $i ]['available_version'] = $this->tgmpa->does_plugin_have_update( $slug );
2289
-
2290
-				// Prep the upgrade notice info.
2291
-				$upgrade_notice = $this->tgmpa->get_upgrade_notice( $slug );
2292
-				if ( ! empty( $upgrade_notice ) ) {
2293
-					$table_data[ $i ]['upgrade_notice'] = $upgrade_notice;
2294
-
2295
-					add_action( "tgmpa_after_plugin_row_{$slug}", array( $this, 'wp_plugin_update_row' ), 10, 2 );
2296
-				}
2297
-
2298
-				$table_data[ $i ] = apply_filters( 'tgmpa_table_data_item', $table_data[ $i ], $plugin );
2299
-
2300
-				$i++;
2301
-			}
2302
-
2303
-			return $table_data;
2304
-		}
2305
-
2306
-		/**
2307
-		 * Categorize the plugins which have open actions into views for the TGMPA page.
2308
-		 *
2309
-		 * @since 2.5.0
2310
-		 */
2311
-		protected function categorize_plugins_to_views() {
2312
-			$plugins = array(
2313
-				'all'      => array(), // Meaning: all plugins which still have open actions.
2314
-				'install'  => array(),
2315
-				'update'   => array(),
2316
-				'activate' => array(),
2317
-			);
2318
-
2319
-			foreach ( $this->tgmpa->plugins as $slug => $plugin ) {
2320
-				if ( $this->tgmpa->is_plugin_active( $slug ) && false === $this->tgmpa->does_plugin_have_update( $slug ) ) {
2321
-					// No need to display plugins if they are installed, up-to-date and active.
2322
-					continue;
2323
-				} else {
2324
-					$plugins['all'][ $slug ] = $plugin;
2325
-
2326
-					if ( ! $this->tgmpa->is_plugin_installed( $slug ) ) {
2327
-						$plugins['install'][ $slug ] = $plugin;
2328
-					} else {
2329
-						if ( false !== $this->tgmpa->does_plugin_have_update( $slug ) ) {
2330
-							$plugins['update'][ $slug ] = $plugin;
2331
-						}
2332
-
2333
-						if ( $this->tgmpa->can_plugin_activate( $slug ) ) {
2334
-							$plugins['activate'][ $slug ] = $plugin;
2335
-						}
2336
-					}
2337
-				}
2338
-			}
2339
-
2340
-			return $plugins;
2341
-		}
2342
-
2343
-		/**
2344
-		 * Set the counts for the view links.
2345
-		 *
2346
-		 * @since 2.5.0
2347
-		 *
2348
-		 * @param array $plugins Plugins order by view.
2349
-		 */
2350
-		protected function set_view_totals( $plugins ) {
2351
-			foreach ( $plugins as $type => $list ) {
2352
-				$this->view_totals[ $type ] = count( $list );
2353
-			}
2354
-		}
2355
-
2356
-		/**
2357
-		 * Get the plugin required/recommended text string.
2358
-		 *
2359
-		 * @since 2.5.0
2360
-		 *
2361
-		 * @param string $required Plugin required setting.
2362
-		 * @return string
2363
-		 */
2364
-		protected function get_plugin_advise_type_text( $required ) {
2365
-			if ( true === $required ) {
2366
-				return __( 'Required', 'tgmpa' );
2367
-			}
2368
-
2369
-			return __( 'Recommended', 'tgmpa' );
2370
-		}
2371
-
2372
-		/**
2373
-		 * Get the plugin source type text string.
2374
-		 *
2375
-		 * @since 2.5.0
2376
-		 *
2377
-		 * @param string $type Plugin type.
2378
-		 * @return string
2379
-		 */
2380
-		protected function get_plugin_source_type_text( $type ) {
2381
-			$string = '';
2382
-
2383
-			switch ( $type ) {
2384
-				case 'repo':
2385
-					$string = __( 'WordPress Repository', 'tgmpa' );
2386
-					break;
2387
-				case 'external':
2388
-					$string = __( 'External Source', 'tgmpa' );
2389
-					break;
2390
-				case 'bundled':
2391
-					$string = __( 'Pre-Packaged', 'tgmpa' );
2392
-					break;
2393
-			}
2394
-
2395
-			return $string;
2396
-		}
2397
-
2398
-		/**
2399
-		 * Determine the plugin status message.
2400
-		 *
2401
-		 * @since 2.5.0
2402
-		 *
2403
-		 * @param string $slug Plugin slug.
2404
-		 * @return string
2405
-		 */
2406
-		protected function get_plugin_status_text( $slug ) {
2407
-			if ( ! $this->tgmpa->is_plugin_installed( $slug ) ) {
2408
-				return __( 'Not Installed', 'tgmpa' );
2409
-			}
2410
-
2411
-			if ( ! $this->tgmpa->is_plugin_active( $slug ) ) {
2412
-				$install_status = __( 'Installed But Not Activated', 'tgmpa' );
2413
-			} else {
2414
-				$install_status = __( 'Active', 'tgmpa' );
2415
-			}
2416
-
2417
-			$update_status = '';
2418
-
2419
-			if ( $this->tgmpa->does_plugin_require_update( $slug ) && false === $this->tgmpa->does_plugin_have_update( $slug ) ) {
2420
-				$update_status = __( 'Required Update not Available', 'tgmpa' );
2421
-
2422
-			} elseif ( $this->tgmpa->does_plugin_require_update( $slug ) ) {
2423
-				$update_status = __( 'Requires Update', 'tgmpa' );
2424
-
2425
-			} elseif ( false !== $this->tgmpa->does_plugin_have_update( $slug ) ) {
2426
-				$update_status = __( 'Update recommended', 'tgmpa' );
2427
-			}
2428
-
2429
-			if ( '' === $update_status ) {
2430
-				return $install_status;
2431
-			}
2432
-
2433
-			return sprintf(
2434
-				/* translators: 1: install status, 2: update status */
2435
-				_x( '%1$s, %2$s', 'Install/Update Status', 'tgmpa' ),
2436
-				$install_status,
2437
-				$update_status
2438
-			);
2439
-		}
2440
-
2441
-		/**
2442
-		 * Sort plugins by Required/Recommended type and by alphabetical plugin name within each type.
2443
-		 *
2444
-		 * @since 2.5.0
2445
-		 *
2446
-		 * @param array $items Prepared table items.
2447
-		 * @return array Sorted table items.
2448
-		 */
2449
-		public function sort_table_items( $items ) {
2450
-			$type = array();
2451
-			$name = array();
2452
-
2453
-			foreach ( $items as $i => $plugin ) {
2454
-				$type[ $i ] = $plugin['type']; // Required / recommended.
2455
-				$name[ $i ] = $plugin['sanitized_plugin'];
2456
-			}
2457
-
2458
-			array_multisort( $type, SORT_DESC, $name, SORT_ASC, $items );
2459
-
2460
-			return $items;
2461
-		}
2462
-
2463
-		/**
2464
-		 * Get an associative array ( id => link ) of the views available on this table.
2465
-		 *
2466
-		 * @since 2.5.0
2467
-		 *
2468
-		 * @return array
2469
-		 */
2470
-		public function get_views() {
2471
-			$status_links = array();
2472
-
2473
-			foreach ( $this->view_totals as $type => $count ) {
2474
-				if ( $count < 1 ) {
2475
-					continue;
2476
-				}
2477
-
2478
-				switch ( $type ) {
2479
-					case 'all':
2480
-						/* translators: 1: number of plugins. */
2481
-						$text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'plugins', 'tgmpa' );
2482
-						break;
2483
-					case 'install':
2484
-						/* translators: 1: number of plugins. */
2485
-						$text = _n( 'To Install <span class="count">(%s)</span>', 'To Install <span class="count">(%s)</span>', $count, 'tgmpa' );
2486
-						break;
2487
-					case 'update':
2488
-						/* translators: 1: number of plugins. */
2489
-						$text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count, 'tgmpa' );
2490
-						break;
2491
-					case 'activate':
2492
-						/* translators: 1: number of plugins. */
2493
-						$text = _n( 'To Activate <span class="count">(%s)</span>', 'To Activate <span class="count">(%s)</span>', $count, 'tgmpa' );
2494
-						break;
2495
-					default:
2496
-						$text = '';
2497
-						break;
2498
-				}
2499
-
2500
-				if ( ! empty( $text ) ) {
2501
-
2502
-					$status_links[ $type ] = sprintf(
2503
-						'<a href="%s"%s>%s</a>',
2504
-						esc_url( $this->tgmpa->get_tgmpa_status_url( $type ) ),
2505
-						( $type === $this->view_context ) ? ' class="current"' : '',
2506
-						sprintf( $text, number_format_i18n( $count ) )
2507
-					);
2508
-				}
2509
-			}
2510
-
2511
-			return $status_links;
2512
-		}
2513
-
2514
-		/**
2515
-		 * Create default columns to display important plugin information
2516
-		 * like type, action and status.
2517
-		 *
2518
-		 * @since 2.2.0
2519
-		 *
2520
-		 * @param array  $item        Array of item data.
2521
-		 * @param string $column_name The name of the column.
2522
-		 * @return string
2523
-		 */
2524
-		public function column_default( $item, $column_name ) {
2525
-			return $item[ $column_name ];
2526
-		}
2527
-
2528
-		/**
2529
-		 * Required for bulk installing.
2530
-		 *
2531
-		 * Adds a checkbox for each plugin.
2532
-		 *
2533
-		 * @since 2.2.0
2534
-		 *
2535
-		 * @param array $item Array of item data.
2536
-		 * @return string The input checkbox with all necessary info.
2537
-		 */
2538
-		public function column_cb( $item ) {
2539
-			return sprintf(
2540
-				'<input type="checkbox" name="%1$s[]" value="%2$s" id="%3$s" />',
2541
-				esc_attr( $this->_args['singular'] ),
2542
-				esc_attr( $item['slug'] ),
2543
-				esc_attr( $item['sanitized_plugin'] )
2544
-			);
2545
-		}
2546
-
2547
-		/**
2548
-		 * Create default title column along with the action links.
2549
-		 *
2550
-		 * @since 2.2.0
2551
-		 *
2552
-		 * @param array $item Array of item data.
2553
-		 * @return string The plugin name and action links.
2554
-		 */
2555
-		public function column_plugin( $item ) {
2556
-			return sprintf(
2557
-				'%1$s %2$s',
2558
-				$item['plugin'],
2559
-				$this->row_actions( $this->get_row_actions( $item ), true )
2560
-			);
2561
-		}
2562
-
2563
-		/**
2564
-		 * Create version information column.
2565
-		 *
2566
-		 * @since 2.5.0
2567
-		 *
2568
-		 * @param array $item Array of item data.
2569
-		 * @return string HTML-formatted version information.
2570
-		 */
2571
-		public function column_version( $item ) {
2572
-			$output = array();
2573
-
2574
-			if ( $this->tgmpa->is_plugin_installed( $item['slug'] ) ) {
2575
-				$installed = ! empty( $item['installed_version'] ) ? $item['installed_version'] : _x( 'unknown', 'as in: "version nr unknown"', 'tgmpa' );
2576
-
2577
-				$color = '';
2578
-				if ( ! empty( $item['minimum_version'] ) && $this->tgmpa->does_plugin_require_update( $item['slug'] ) ) {
2579
-					$color = ' color: #ff0000; font-weight: bold;';
2580
-				}
2581
-
2582
-				$output[] = sprintf(
2583
-					'<p><span style="min-width: 32px; text-align: right; float: right;%1$s">%2$s</span>' . __( 'Installed version:', 'tgmpa' ) . '</p>',
2584
-					$color,
2585
-					$installed
2586
-				);
2587
-			}
2588
-
2589
-			if ( ! empty( $item['minimum_version'] ) ) {
2590
-				$output[] = sprintf(
2591
-					'<p><span style="min-width: 32px; text-align: right; float: right;">%1$s</span>' . __( 'Minimum required version:', 'tgmpa' ) . '</p>',
2592
-					$item['minimum_version']
2593
-				);
2594
-			}
2595
-
2596
-			if ( ! empty( $item['available_version'] ) ) {
2597
-				$color = '';
2598
-				if ( ! empty( $item['minimum_version'] ) && version_compare( $item['available_version'], $item['minimum_version'], '>=' ) ) {
2599
-					$color = ' color: #71C671; font-weight: bold;';
2600
-				}
2601
-
2602
-				$output[] = sprintf(
2603
-					'<p><span style="min-width: 32px; text-align: right; float: right;%1$s">%2$s</span>' . __( 'Available version:', 'tgmpa' ) . '</p>',
2604
-					$color,
2605
-					$item['available_version']
2606
-				);
2607
-			}
2608
-
2609
-			if ( empty( $output ) ) {
2610
-				return '&nbsp;'; // Let's not break the table layout.
2611
-			} else {
2612
-				return implode( "\n", $output );
2613
-			}
2614
-		}
2615
-
2616
-		/**
2617
-		 * Sets default message within the plugins table if no plugins
2618
-		 * are left for interaction.
2619
-		 *
2620
-		 * Hides the menu item to prevent the user from clicking and
2621
-		 * getting a permissions error.
2622
-		 *
2623
-		 * @since 2.2.0
2624
-		 */
2625
-		public function no_items() {
2626
-			echo esc_html__( 'No plugins to install, update or activate.', 'tgmpa' ) . ' <a href="' . esc_url( self_admin_url() ) . '"> ' . esc_html__( 'Return to the Dashboard', 'tgmpa' ) . '</a>';
2627
-			echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>';
2628
-		}
2629
-
2630
-		/**
2631
-		 * Output all the column information within the table.
2632
-		 *
2633
-		 * @since 2.2.0
2634
-		 *
2635
-		 * @return array $columns The column names.
2636
-		 */
2637
-		public function get_columns() {
2638
-			$columns = array(
2639
-				'cb'     => '<input type="checkbox" />',
2640
-				'plugin' => __( 'Plugin', 'tgmpa' ),
2641
-				'source' => __( 'Source', 'tgmpa' ),
2642
-				'type'   => __( 'Type', 'tgmpa' ),
2643
-			);
2644
-
2645
-			if ( 'all' === $this->view_context || 'update' === $this->view_context ) {
2646
-				$columns['version'] = __( 'Version', 'tgmpa' );
2647
-				$columns['status']  = __( 'Status', 'tgmpa' );
2648
-			}
2649
-
2650
-			return apply_filters( 'tgmpa_table_columns', $columns );
2651
-		}
2652
-
2653
-		/**
2654
-		 * Get name of default primary column
2655
-		 *
2656
-		 * @since 2.5.0 / WP 4.3+ compatibility
2657
-		 * @access protected
2658
-		 *
2659
-		 * @return string
2660
-		 */
2661
-		protected function get_default_primary_column_name() {
2662
-			return 'plugin';
2663
-		}
2664
-
2665
-		/**
2666
-		 * Get the name of the primary column.
2667
-		 *
2668
-		 * @since 2.5.0 / WP 4.3+ compatibility
2669
-		 * @access protected
2670
-		 *
2671
-		 * @return string The name of the primary column.
2672
-		 */
2673
-		protected function get_primary_column_name() {
2674
-			if ( method_exists( 'WP_List_Table', 'get_primary_column_name' ) ) {
2675
-				return parent::get_primary_column_name();
2676
-			} else {
2677
-				return $this->get_default_primary_column_name();
2678
-			}
2679
-		}
2680
-
2681
-		/**
2682
-		 * Get the actions which are relevant for a specific plugin row.
2683
-		 *
2684
-		 * @since 2.5.0
2685
-		 *
2686
-		 * @param array $item Array of item data.
2687
-		 * @return array Array with relevant action links.
2688
-		 */
2689
-		protected function get_row_actions( $item ) {
2690
-			$actions      = array();
2691
-			$action_links = array();
2692
-
2693
-			// Display the 'Install' action link if the plugin is not yet available.
2694
-			if ( ! $this->tgmpa->is_plugin_installed( $item['slug'] ) ) {
2695
-				/* translators: %2$s: plugin name in screen reader markup */
2696
-				$actions['install'] = __( 'Install %2$s', 'tgmpa' );
2697
-			} else {
2698
-				// Display the 'Update' action link if an update is available and WP complies with plugin minimum.
2699
-				if ( false !== $this->tgmpa->does_plugin_have_update( $item['slug'] ) && $this->tgmpa->can_plugin_update( $item['slug'] ) ) {
2700
-					/* translators: %2$s: plugin name in screen reader markup */
2701
-					$actions['update'] = __( 'Update %2$s', 'tgmpa' );
2702
-				}
2703
-
2704
-				// Display the 'Activate' action link, but only if the plugin meets the minimum version.
2705
-				if ( $this->tgmpa->can_plugin_activate( $item['slug'] ) ) {
2706
-					/* translators: %2$s: plugin name in screen reader markup */
2707
-					$actions['activate'] = __( 'Activate %2$s', 'tgmpa' );
2708
-				}
2709
-			}
2710
-
2711
-			// Create the actual links.
2712
-			foreach ( $actions as $action => $text ) {
2713
-				$nonce_url = wp_nonce_url(
2714
-					add_query_arg(
2715
-						array(
2716
-							'plugin'           => urlencode( $item['slug'] ),
2717
-							'tgmpa-' . $action => $action . '-plugin',
2718
-						),
2719
-						$this->tgmpa->get_tgmpa_url()
2720
-					),
2721
-					'tgmpa-' . $action,
2722
-					'tgmpa-nonce'
2723
-				);
2724
-
2725
-				$action_links[ $action ] = sprintf(
2726
-					'<a href="%1$s">' . esc_html( $text ) . '</a>', // $text contains the second placeholder.
2727
-					esc_url( $nonce_url ),
2728
-					'<span class="screen-reader-text">' . esc_html( $item['sanitized_plugin'] ) . '</span>'
2729
-				);
2730
-			}
2731
-
2732
-			$prefix = ( defined( 'WP_NETWORK_ADMIN' ) && WP_NETWORK_ADMIN ) ? 'network_admin_' : '';
2733
-			return apply_filters( "tgmpa_{$prefix}plugin_action_links", array_filter( $action_links ), $item['slug'], $item, $this->view_context );
2734
-		}
2735
-
2736
-		/**
2737
-		 * Generates content for a single row of the table.
2738
-		 *
2739
-		 * @since 2.5.0
2740
-		 *
2741
-		 * @param object $item The current item.
2742
-		 */
2743
-		public function single_row( $item ) {
2744
-			parent::single_row( $item );
2745
-
2746
-			/**
2747
-			 * Fires after each specific row in the TGMPA Plugins list table.
2748
-			 *
2749
-			 * The dynamic portion of the hook name, `$item['slug']`, refers to the slug
2750
-			 * for the plugin.
2751
-			 *
2752
-			 * @since 2.5.0
2753
-			 */
2754
-			do_action( "tgmpa_after_plugin_row_{$item['slug']}", $item['slug'], $item, $this->view_context );
2755
-		}
2756
-
2757
-		/**
2758
-		 * Show the upgrade notice below a plugin row if there is one.
2759
-		 *
2760
-		 * @since 2.5.0
2761
-		 *
2762
-		 * @see /wp-admin/includes/update.php
2763
-		 *
2764
-		 * @param string $slug Plugin slug.
2765
-		 * @param array  $item The information available in this table row.
2766
-		 * @return null Return early if upgrade notice is empty.
2767
-		 */
2768
-		public function wp_plugin_update_row( $slug, $item ) {
2769
-			if ( empty( $item['upgrade_notice'] ) ) {
2770
-				return;
2771
-			}
2772
-
2773
-			echo '
2166
+    /**
2167
+     * List table class for handling plugins.
2168
+     *
2169
+     * Extends the WP_List_Table class to provide a future-compatible
2170
+     * way of listing out all required/recommended plugins.
2171
+     *
2172
+     * Gives users an interface similar to the Plugin Administration
2173
+     * area with similar (albeit stripped down) capabilities.
2174
+     *
2175
+     * This class also allows for the bulk install of plugins.
2176
+     *
2177
+     * @since 2.2.0
2178
+     *
2179
+     * @package TGM-Plugin-Activation
2180
+     * @author  Thomas Griffin
2181
+     * @author  Gary Jones
2182
+     */
2183
+    class TGMPA_List_Table extends WP_List_Table {
2184
+        /**
2185
+         * TGMPA instance.
2186
+         *
2187
+         * @since 2.5.0
2188
+         *
2189
+         * @var object
2190
+         */
2191
+        protected $tgmpa;
2192
+
2193
+        /**
2194
+         * The currently chosen view.
2195
+         *
2196
+         * @since 2.5.0
2197
+         *
2198
+         * @var string One of: 'all', 'install', 'update', 'activate'
2199
+         */
2200
+        public $view_context = 'all';
2201
+
2202
+        /**
2203
+         * The plugin counts for the various views.
2204
+         *
2205
+         * @since 2.5.0
2206
+         *
2207
+         * @var array
2208
+         */
2209
+        protected $view_totals = array(
2210
+            'all'      => 0,
2211
+            'install'  => 0,
2212
+            'update'   => 0,
2213
+            'activate' => 0,
2214
+        );
2215
+
2216
+        /**
2217
+         * References parent constructor and sets defaults for class.
2218
+         *
2219
+         * @since 2.2.0
2220
+         */
2221
+        public function __construct() {
2222
+            $this->tgmpa = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
2223
+
2224
+            parent::__construct(
2225
+                array(
2226
+                    'singular' => 'plugin',
2227
+                    'plural'   => 'plugins',
2228
+                    'ajax'     => false,
2229
+                )
2230
+            );
2231
+
2232
+            if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'install', 'update', 'activate' ), true ) ) {
2233
+                $this->view_context = sanitize_key( $_REQUEST['plugin_status'] );
2234
+            }
2235
+
2236
+            add_filter( 'tgmpa_table_data_items', array( $this, 'sort_table_items' ) );
2237
+        }
2238
+
2239
+        /**
2240
+         * Get a list of CSS classes for the <table> tag.
2241
+         *
2242
+         * Overruled to prevent the 'plural' argument from being added.
2243
+         *
2244
+         * @since 2.5.0
2245
+         *
2246
+         * @return array CSS classnames.
2247
+         */
2248
+        public function get_table_classes() {
2249
+            return array( 'widefat', 'fixed' );
2250
+        }
2251
+
2252
+        /**
2253
+         * Gathers and renames all of our plugin information to be used by WP_List_Table to create our table.
2254
+         *
2255
+         * @since 2.2.0
2256
+         *
2257
+         * @return array $table_data Information for use in table.
2258
+         */
2259
+        protected function _gather_plugin_data() {
2260
+            // Load thickbox for plugin links.
2261
+            $this->tgmpa->admin_init();
2262
+            $this->tgmpa->thickbox();
2263
+
2264
+            // Categorize the plugins which have open actions.
2265
+            $plugins = $this->categorize_plugins_to_views();
2266
+
2267
+            // Set the counts for the view links.
2268
+            $this->set_view_totals( $plugins );
2269
+
2270
+            // Prep variables for use and grab list of all installed plugins.
2271
+            $table_data = array();
2272
+            $i          = 0;
2273
+
2274
+            // Redirect to the 'all' view if no plugins were found for the selected view context.
2275
+            if ( empty( $plugins[ $this->view_context ] ) ) {
2276
+                $this->view_context = 'all';
2277
+            }
2278
+
2279
+            foreach ( $plugins[ $this->view_context ] as $slug => $plugin ) {
2280
+                $table_data[ $i ]['sanitized_plugin']  = $plugin['name'];
2281
+                $table_data[ $i ]['slug']              = $slug;
2282
+                $table_data[ $i ]['plugin']            = '<strong>' . $this->tgmpa->get_info_link( $slug ) . '</strong>';
2283
+                $table_data[ $i ]['source']            = $this->get_plugin_source_type_text( $plugin['source_type'] );
2284
+                $table_data[ $i ]['type']              = $this->get_plugin_advise_type_text( $plugin['required'] );
2285
+                $table_data[ $i ]['status']            = $this->get_plugin_status_text( $slug );
2286
+                $table_data[ $i ]['installed_version'] = $this->tgmpa->get_installed_version( $slug );
2287
+                $table_data[ $i ]['minimum_version']   = $plugin['version'];
2288
+                $table_data[ $i ]['available_version'] = $this->tgmpa->does_plugin_have_update( $slug );
2289
+
2290
+                // Prep the upgrade notice info.
2291
+                $upgrade_notice = $this->tgmpa->get_upgrade_notice( $slug );
2292
+                if ( ! empty( $upgrade_notice ) ) {
2293
+                    $table_data[ $i ]['upgrade_notice'] = $upgrade_notice;
2294
+
2295
+                    add_action( "tgmpa_after_plugin_row_{$slug}", array( $this, 'wp_plugin_update_row' ), 10, 2 );
2296
+                }
2297
+
2298
+                $table_data[ $i ] = apply_filters( 'tgmpa_table_data_item', $table_data[ $i ], $plugin );
2299
+
2300
+                $i++;
2301
+            }
2302
+
2303
+            return $table_data;
2304
+        }
2305
+
2306
+        /**
2307
+         * Categorize the plugins which have open actions into views for the TGMPA page.
2308
+         *
2309
+         * @since 2.5.0
2310
+         */
2311
+        protected function categorize_plugins_to_views() {
2312
+            $plugins = array(
2313
+                'all'      => array(), // Meaning: all plugins which still have open actions.
2314
+                'install'  => array(),
2315
+                'update'   => array(),
2316
+                'activate' => array(),
2317
+            );
2318
+
2319
+            foreach ( $this->tgmpa->plugins as $slug => $plugin ) {
2320
+                if ( $this->tgmpa->is_plugin_active( $slug ) && false === $this->tgmpa->does_plugin_have_update( $slug ) ) {
2321
+                    // No need to display plugins if they are installed, up-to-date and active.
2322
+                    continue;
2323
+                } else {
2324
+                    $plugins['all'][ $slug ] = $plugin;
2325
+
2326
+                    if ( ! $this->tgmpa->is_plugin_installed( $slug ) ) {
2327
+                        $plugins['install'][ $slug ] = $plugin;
2328
+                    } else {
2329
+                        if ( false !== $this->tgmpa->does_plugin_have_update( $slug ) ) {
2330
+                            $plugins['update'][ $slug ] = $plugin;
2331
+                        }
2332
+
2333
+                        if ( $this->tgmpa->can_plugin_activate( $slug ) ) {
2334
+                            $plugins['activate'][ $slug ] = $plugin;
2335
+                        }
2336
+                    }
2337
+                }
2338
+            }
2339
+
2340
+            return $plugins;
2341
+        }
2342
+
2343
+        /**
2344
+         * Set the counts for the view links.
2345
+         *
2346
+         * @since 2.5.0
2347
+         *
2348
+         * @param array $plugins Plugins order by view.
2349
+         */
2350
+        protected function set_view_totals( $plugins ) {
2351
+            foreach ( $plugins as $type => $list ) {
2352
+                $this->view_totals[ $type ] = count( $list );
2353
+            }
2354
+        }
2355
+
2356
+        /**
2357
+         * Get the plugin required/recommended text string.
2358
+         *
2359
+         * @since 2.5.0
2360
+         *
2361
+         * @param string $required Plugin required setting.
2362
+         * @return string
2363
+         */
2364
+        protected function get_plugin_advise_type_text( $required ) {
2365
+            if ( true === $required ) {
2366
+                return __( 'Required', 'tgmpa' );
2367
+            }
2368
+
2369
+            return __( 'Recommended', 'tgmpa' );
2370
+        }
2371
+
2372
+        /**
2373
+         * Get the plugin source type text string.
2374
+         *
2375
+         * @since 2.5.0
2376
+         *
2377
+         * @param string $type Plugin type.
2378
+         * @return string
2379
+         */
2380
+        protected function get_plugin_source_type_text( $type ) {
2381
+            $string = '';
2382
+
2383
+            switch ( $type ) {
2384
+                case 'repo':
2385
+                    $string = __( 'WordPress Repository', 'tgmpa' );
2386
+                    break;
2387
+                case 'external':
2388
+                    $string = __( 'External Source', 'tgmpa' );
2389
+                    break;
2390
+                case 'bundled':
2391
+                    $string = __( 'Pre-Packaged', 'tgmpa' );
2392
+                    break;
2393
+            }
2394
+
2395
+            return $string;
2396
+        }
2397
+
2398
+        /**
2399
+         * Determine the plugin status message.
2400
+         *
2401
+         * @since 2.5.0
2402
+         *
2403
+         * @param string $slug Plugin slug.
2404
+         * @return string
2405
+         */
2406
+        protected function get_plugin_status_text( $slug ) {
2407
+            if ( ! $this->tgmpa->is_plugin_installed( $slug ) ) {
2408
+                return __( 'Not Installed', 'tgmpa' );
2409
+            }
2410
+
2411
+            if ( ! $this->tgmpa->is_plugin_active( $slug ) ) {
2412
+                $install_status = __( 'Installed But Not Activated', 'tgmpa' );
2413
+            } else {
2414
+                $install_status = __( 'Active', 'tgmpa' );
2415
+            }
2416
+
2417
+            $update_status = '';
2418
+
2419
+            if ( $this->tgmpa->does_plugin_require_update( $slug ) && false === $this->tgmpa->does_plugin_have_update( $slug ) ) {
2420
+                $update_status = __( 'Required Update not Available', 'tgmpa' );
2421
+
2422
+            } elseif ( $this->tgmpa->does_plugin_require_update( $slug ) ) {
2423
+                $update_status = __( 'Requires Update', 'tgmpa' );
2424
+
2425
+            } elseif ( false !== $this->tgmpa->does_plugin_have_update( $slug ) ) {
2426
+                $update_status = __( 'Update recommended', 'tgmpa' );
2427
+            }
2428
+
2429
+            if ( '' === $update_status ) {
2430
+                return $install_status;
2431
+            }
2432
+
2433
+            return sprintf(
2434
+                /* translators: 1: install status, 2: update status */
2435
+                _x( '%1$s, %2$s', 'Install/Update Status', 'tgmpa' ),
2436
+                $install_status,
2437
+                $update_status
2438
+            );
2439
+        }
2440
+
2441
+        /**
2442
+         * Sort plugins by Required/Recommended type and by alphabetical plugin name within each type.
2443
+         *
2444
+         * @since 2.5.0
2445
+         *
2446
+         * @param array $items Prepared table items.
2447
+         * @return array Sorted table items.
2448
+         */
2449
+        public function sort_table_items( $items ) {
2450
+            $type = array();
2451
+            $name = array();
2452
+
2453
+            foreach ( $items as $i => $plugin ) {
2454
+                $type[ $i ] = $plugin['type']; // Required / recommended.
2455
+                $name[ $i ] = $plugin['sanitized_plugin'];
2456
+            }
2457
+
2458
+            array_multisort( $type, SORT_DESC, $name, SORT_ASC, $items );
2459
+
2460
+            return $items;
2461
+        }
2462
+
2463
+        /**
2464
+         * Get an associative array ( id => link ) of the views available on this table.
2465
+         *
2466
+         * @since 2.5.0
2467
+         *
2468
+         * @return array
2469
+         */
2470
+        public function get_views() {
2471
+            $status_links = array();
2472
+
2473
+            foreach ( $this->view_totals as $type => $count ) {
2474
+                if ( $count < 1 ) {
2475
+                    continue;
2476
+                }
2477
+
2478
+                switch ( $type ) {
2479
+                    case 'all':
2480
+                        /* translators: 1: number of plugins. */
2481
+                        $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'plugins', 'tgmpa' );
2482
+                        break;
2483
+                    case 'install':
2484
+                        /* translators: 1: number of plugins. */
2485
+                        $text = _n( 'To Install <span class="count">(%s)</span>', 'To Install <span class="count">(%s)</span>', $count, 'tgmpa' );
2486
+                        break;
2487
+                    case 'update':
2488
+                        /* translators: 1: number of plugins. */
2489
+                        $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count, 'tgmpa' );
2490
+                        break;
2491
+                    case 'activate':
2492
+                        /* translators: 1: number of plugins. */
2493
+                        $text = _n( 'To Activate <span class="count">(%s)</span>', 'To Activate <span class="count">(%s)</span>', $count, 'tgmpa' );
2494
+                        break;
2495
+                    default:
2496
+                        $text = '';
2497
+                        break;
2498
+                }
2499
+
2500
+                if ( ! empty( $text ) ) {
2501
+
2502
+                    $status_links[ $type ] = sprintf(
2503
+                        '<a href="%s"%s>%s</a>',
2504
+                        esc_url( $this->tgmpa->get_tgmpa_status_url( $type ) ),
2505
+                        ( $type === $this->view_context ) ? ' class="current"' : '',
2506
+                        sprintf( $text, number_format_i18n( $count ) )
2507
+                    );
2508
+                }
2509
+            }
2510
+
2511
+            return $status_links;
2512
+        }
2513
+
2514
+        /**
2515
+         * Create default columns to display important plugin information
2516
+         * like type, action and status.
2517
+         *
2518
+         * @since 2.2.0
2519
+         *
2520
+         * @param array  $item        Array of item data.
2521
+         * @param string $column_name The name of the column.
2522
+         * @return string
2523
+         */
2524
+        public function column_default( $item, $column_name ) {
2525
+            return $item[ $column_name ];
2526
+        }
2527
+
2528
+        /**
2529
+         * Required for bulk installing.
2530
+         *
2531
+         * Adds a checkbox for each plugin.
2532
+         *
2533
+         * @since 2.2.0
2534
+         *
2535
+         * @param array $item Array of item data.
2536
+         * @return string The input checkbox with all necessary info.
2537
+         */
2538
+        public function column_cb( $item ) {
2539
+            return sprintf(
2540
+                '<input type="checkbox" name="%1$s[]" value="%2$s" id="%3$s" />',
2541
+                esc_attr( $this->_args['singular'] ),
2542
+                esc_attr( $item['slug'] ),
2543
+                esc_attr( $item['sanitized_plugin'] )
2544
+            );
2545
+        }
2546
+
2547
+        /**
2548
+         * Create default title column along with the action links.
2549
+         *
2550
+         * @since 2.2.0
2551
+         *
2552
+         * @param array $item Array of item data.
2553
+         * @return string The plugin name and action links.
2554
+         */
2555
+        public function column_plugin( $item ) {
2556
+            return sprintf(
2557
+                '%1$s %2$s',
2558
+                $item['plugin'],
2559
+                $this->row_actions( $this->get_row_actions( $item ), true )
2560
+            );
2561
+        }
2562
+
2563
+        /**
2564
+         * Create version information column.
2565
+         *
2566
+         * @since 2.5.0
2567
+         *
2568
+         * @param array $item Array of item data.
2569
+         * @return string HTML-formatted version information.
2570
+         */
2571
+        public function column_version( $item ) {
2572
+            $output = array();
2573
+
2574
+            if ( $this->tgmpa->is_plugin_installed( $item['slug'] ) ) {
2575
+                $installed = ! empty( $item['installed_version'] ) ? $item['installed_version'] : _x( 'unknown', 'as in: "version nr unknown"', 'tgmpa' );
2576
+
2577
+                $color = '';
2578
+                if ( ! empty( $item['minimum_version'] ) && $this->tgmpa->does_plugin_require_update( $item['slug'] ) ) {
2579
+                    $color = ' color: #ff0000; font-weight: bold;';
2580
+                }
2581
+
2582
+                $output[] = sprintf(
2583
+                    '<p><span style="min-width: 32px; text-align: right; float: right;%1$s">%2$s</span>' . __( 'Installed version:', 'tgmpa' ) . '</p>',
2584
+                    $color,
2585
+                    $installed
2586
+                );
2587
+            }
2588
+
2589
+            if ( ! empty( $item['minimum_version'] ) ) {
2590
+                $output[] = sprintf(
2591
+                    '<p><span style="min-width: 32px; text-align: right; float: right;">%1$s</span>' . __( 'Minimum required version:', 'tgmpa' ) . '</p>',
2592
+                    $item['minimum_version']
2593
+                );
2594
+            }
2595
+
2596
+            if ( ! empty( $item['available_version'] ) ) {
2597
+                $color = '';
2598
+                if ( ! empty( $item['minimum_version'] ) && version_compare( $item['available_version'], $item['minimum_version'], '>=' ) ) {
2599
+                    $color = ' color: #71C671; font-weight: bold;';
2600
+                }
2601
+
2602
+                $output[] = sprintf(
2603
+                    '<p><span style="min-width: 32px; text-align: right; float: right;%1$s">%2$s</span>' . __( 'Available version:', 'tgmpa' ) . '</p>',
2604
+                    $color,
2605
+                    $item['available_version']
2606
+                );
2607
+            }
2608
+
2609
+            if ( empty( $output ) ) {
2610
+                return '&nbsp;'; // Let's not break the table layout.
2611
+            } else {
2612
+                return implode( "\n", $output );
2613
+            }
2614
+        }
2615
+
2616
+        /**
2617
+         * Sets default message within the plugins table if no plugins
2618
+         * are left for interaction.
2619
+         *
2620
+         * Hides the menu item to prevent the user from clicking and
2621
+         * getting a permissions error.
2622
+         *
2623
+         * @since 2.2.0
2624
+         */
2625
+        public function no_items() {
2626
+            echo esc_html__( 'No plugins to install, update or activate.', 'tgmpa' ) . ' <a href="' . esc_url( self_admin_url() ) . '"> ' . esc_html__( 'Return to the Dashboard', 'tgmpa' ) . '</a>';
2627
+            echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>';
2628
+        }
2629
+
2630
+        /**
2631
+         * Output all the column information within the table.
2632
+         *
2633
+         * @since 2.2.0
2634
+         *
2635
+         * @return array $columns The column names.
2636
+         */
2637
+        public function get_columns() {
2638
+            $columns = array(
2639
+                'cb'     => '<input type="checkbox" />',
2640
+                'plugin' => __( 'Plugin', 'tgmpa' ),
2641
+                'source' => __( 'Source', 'tgmpa' ),
2642
+                'type'   => __( 'Type', 'tgmpa' ),
2643
+            );
2644
+
2645
+            if ( 'all' === $this->view_context || 'update' === $this->view_context ) {
2646
+                $columns['version'] = __( 'Version', 'tgmpa' );
2647
+                $columns['status']  = __( 'Status', 'tgmpa' );
2648
+            }
2649
+
2650
+            return apply_filters( 'tgmpa_table_columns', $columns );
2651
+        }
2652
+
2653
+        /**
2654
+         * Get name of default primary column
2655
+         *
2656
+         * @since 2.5.0 / WP 4.3+ compatibility
2657
+         * @access protected
2658
+         *
2659
+         * @return string
2660
+         */
2661
+        protected function get_default_primary_column_name() {
2662
+            return 'plugin';
2663
+        }
2664
+
2665
+        /**
2666
+         * Get the name of the primary column.
2667
+         *
2668
+         * @since 2.5.0 / WP 4.3+ compatibility
2669
+         * @access protected
2670
+         *
2671
+         * @return string The name of the primary column.
2672
+         */
2673
+        protected function get_primary_column_name() {
2674
+            if ( method_exists( 'WP_List_Table', 'get_primary_column_name' ) ) {
2675
+                return parent::get_primary_column_name();
2676
+            } else {
2677
+                return $this->get_default_primary_column_name();
2678
+            }
2679
+        }
2680
+
2681
+        /**
2682
+         * Get the actions which are relevant for a specific plugin row.
2683
+         *
2684
+         * @since 2.5.0
2685
+         *
2686
+         * @param array $item Array of item data.
2687
+         * @return array Array with relevant action links.
2688
+         */
2689
+        protected function get_row_actions( $item ) {
2690
+            $actions      = array();
2691
+            $action_links = array();
2692
+
2693
+            // Display the 'Install' action link if the plugin is not yet available.
2694
+            if ( ! $this->tgmpa->is_plugin_installed( $item['slug'] ) ) {
2695
+                /* translators: %2$s: plugin name in screen reader markup */
2696
+                $actions['install'] = __( 'Install %2$s', 'tgmpa' );
2697
+            } else {
2698
+                // Display the 'Update' action link if an update is available and WP complies with plugin minimum.
2699
+                if ( false !== $this->tgmpa->does_plugin_have_update( $item['slug'] ) && $this->tgmpa->can_plugin_update( $item['slug'] ) ) {
2700
+                    /* translators: %2$s: plugin name in screen reader markup */
2701
+                    $actions['update'] = __( 'Update %2$s', 'tgmpa' );
2702
+                }
2703
+
2704
+                // Display the 'Activate' action link, but only if the plugin meets the minimum version.
2705
+                if ( $this->tgmpa->can_plugin_activate( $item['slug'] ) ) {
2706
+                    /* translators: %2$s: plugin name in screen reader markup */
2707
+                    $actions['activate'] = __( 'Activate %2$s', 'tgmpa' );
2708
+                }
2709
+            }
2710
+
2711
+            // Create the actual links.
2712
+            foreach ( $actions as $action => $text ) {
2713
+                $nonce_url = wp_nonce_url(
2714
+                    add_query_arg(
2715
+                        array(
2716
+                            'plugin'           => urlencode( $item['slug'] ),
2717
+                            'tgmpa-' . $action => $action . '-plugin',
2718
+                        ),
2719
+                        $this->tgmpa->get_tgmpa_url()
2720
+                    ),
2721
+                    'tgmpa-' . $action,
2722
+                    'tgmpa-nonce'
2723
+                );
2724
+
2725
+                $action_links[ $action ] = sprintf(
2726
+                    '<a href="%1$s">' . esc_html( $text ) . '</a>', // $text contains the second placeholder.
2727
+                    esc_url( $nonce_url ),
2728
+                    '<span class="screen-reader-text">' . esc_html( $item['sanitized_plugin'] ) . '</span>'
2729
+                );
2730
+            }
2731
+
2732
+            $prefix = ( defined( 'WP_NETWORK_ADMIN' ) && WP_NETWORK_ADMIN ) ? 'network_admin_' : '';
2733
+            return apply_filters( "tgmpa_{$prefix}plugin_action_links", array_filter( $action_links ), $item['slug'], $item, $this->view_context );
2734
+        }
2735
+
2736
+        /**
2737
+         * Generates content for a single row of the table.
2738
+         *
2739
+         * @since 2.5.0
2740
+         *
2741
+         * @param object $item The current item.
2742
+         */
2743
+        public function single_row( $item ) {
2744
+            parent::single_row( $item );
2745
+
2746
+            /**
2747
+             * Fires after each specific row in the TGMPA Plugins list table.
2748
+             *
2749
+             * The dynamic portion of the hook name, `$item['slug']`, refers to the slug
2750
+             * for the plugin.
2751
+             *
2752
+             * @since 2.5.0
2753
+             */
2754
+            do_action( "tgmpa_after_plugin_row_{$item['slug']}", $item['slug'], $item, $this->view_context );
2755
+        }
2756
+
2757
+        /**
2758
+         * Show the upgrade notice below a plugin row if there is one.
2759
+         *
2760
+         * @since 2.5.0
2761
+         *
2762
+         * @see /wp-admin/includes/update.php
2763
+         *
2764
+         * @param string $slug Plugin slug.
2765
+         * @param array  $item The information available in this table row.
2766
+         * @return null Return early if upgrade notice is empty.
2767
+         */
2768
+        public function wp_plugin_update_row( $slug, $item ) {
2769
+            if ( empty( $item['upgrade_notice'] ) ) {
2770
+                return;
2771
+            }
2772
+
2773
+            echo '
2774 2774
 				<tr class="plugin-update-tr">
2775 2775
 					<td colspan="', absint( $this->get_column_count() ), '" class="plugin-update colspanchange">
2776 2776
 						<div class="update-message">',
2777
-							esc_html__( 'Upgrade message from the plugin author:', 'tgmpa' ),
2778
-							' <strong>', wp_kses_data( $item['upgrade_notice'] ), '</strong>
2777
+                            esc_html__( 'Upgrade message from the plugin author:', 'tgmpa' ),
2778
+                            ' <strong>', wp_kses_data( $item['upgrade_notice'] ), '</strong>
2779 2779
 						</div>
2780 2780
 					</td>
2781 2781
 				</tr>';
2782
-		}
2783
-
2784
-		/**
2785
-		 * Extra controls to be displayed between bulk actions and pagination.
2786
-		 *
2787
-		 * @since 2.5.0
2788
-		 *
2789
-		 * @param string $which 'top' or 'bottom' table navigation.
2790
-		 */
2791
-		public function extra_tablenav( $which ) {
2792
-			if ( 'bottom' === $which ) {
2793
-				$this->tgmpa->show_tgmpa_version();
2794
-			}
2795
-		}
2796
-
2797
-		/**
2798
-		 * Defines the bulk actions for handling registered plugins.
2799
-		 *
2800
-		 * @since 2.2.0
2801
-		 *
2802
-		 * @return array $actions The bulk actions for the plugin install table.
2803
-		 */
2804
-		public function get_bulk_actions() {
2805
-
2806
-			$actions = array();
2807
-
2808
-			if ( 'update' !== $this->view_context && 'activate' !== $this->view_context ) {
2809
-				if ( current_user_can( 'install_plugins' ) ) {
2810
-					$actions['tgmpa-bulk-install'] = __( 'Install', 'tgmpa' );
2811
-				}
2812
-			}
2813
-
2814
-			if ( 'install' !== $this->view_context ) {
2815
-				if ( current_user_can( 'update_plugins' ) ) {
2816
-					$actions['tgmpa-bulk-update'] = __( 'Update', 'tgmpa' );
2817
-				}
2818
-				if ( current_user_can( 'activate_plugins' ) ) {
2819
-					$actions['tgmpa-bulk-activate'] = __( 'Activate', 'tgmpa' );
2820
-				}
2821
-			}
2822
-
2823
-			return $actions;
2824
-		}
2825
-
2826
-		/**
2827
-		 * Processes bulk installation and activation actions.
2828
-		 *
2829
-		 * The bulk installation process looks for the $_POST information and passes that
2830
-		 * through if a user has to use WP_Filesystem to enter their credentials.
2831
-		 *
2832
-		 * @since 2.2.0
2833
-		 */
2834
-		public function process_bulk_actions() {
2835
-			// Bulk installation process.
2836
-			if ( 'tgmpa-bulk-install' === $this->current_action() || 'tgmpa-bulk-update' === $this->current_action() ) {
2837
-
2838
-				check_admin_referer( 'bulk-' . $this->_args['plural'] );
2839
-
2840
-				$install_type = 'install';
2841
-				if ( 'tgmpa-bulk-update' === $this->current_action() ) {
2842
-					$install_type = 'update';
2843
-				}
2844
-
2845
-				$plugins_to_install = array();
2846
-
2847
-				// Did user actually select any plugins to install/update ?
2848
-				if ( empty( $_POST['plugin'] ) ) {
2849
-					if ( 'install' === $install_type ) {
2850
-						$message = __( 'No plugins were selected to be installed. No action taken.', 'tgmpa' );
2851
-					} else {
2852
-						$message = __( 'No plugins were selected to be updated. No action taken.', 'tgmpa' );
2853
-					}
2854
-
2855
-					echo '<div id="message" class="error"><p>', esc_html( $message ), '</p></div>';
2856
-
2857
-					return false;
2858
-				}
2859
-
2860
-				if ( is_array( $_POST['plugin'] ) ) {
2861
-					$plugins_to_install = (array) $_POST['plugin'];
2862
-				} elseif ( is_string( $_POST['plugin'] ) ) {
2863
-					// Received via Filesystem page - un-flatten array (WP bug #19643).
2864
-					$plugins_to_install = explode( ',', $_POST['plugin'] );
2865
-				}
2866
-
2867
-				// Sanitize the received input.
2868
-				$plugins_to_install = array_map( 'urldecode', $plugins_to_install );
2869
-				$plugins_to_install = array_map( array( $this->tgmpa, 'sanitize_key' ), $plugins_to_install );
2870
-
2871
-				// Validate the received input.
2872
-				foreach ( $plugins_to_install as $key => $slug ) {
2873
-					// Check if the plugin was registered with TGMPA and remove if not.
2874
-					if ( ! isset( $this->tgmpa->plugins[ $slug ] ) ) {
2875
-						unset( $plugins_to_install[ $key ] );
2876
-						continue;
2877
-					}
2878
-
2879
-					// For install: make sure this is a plugin we *can* install and not one already installed.
2880
-					if ( 'install' === $install_type && true === $this->tgmpa->is_plugin_installed( $slug ) ) {
2881
-						unset( $plugins_to_install[ $key ] );
2882
-					}
2883
-
2884
-					// For updates: make sure this is a plugin we *can* update (update available and WP version ok).
2885
-					if ( 'update' === $install_type && false === $this->tgmpa->is_plugin_updatetable( $slug ) ) {
2886
-						unset( $plugins_to_install[ $key ] );
2887
-					}
2888
-				}
2889
-
2890
-				// No need to proceed further if we have no plugins to handle.
2891
-				if ( empty( $plugins_to_install ) ) {
2892
-					if ( 'install' === $install_type ) {
2893
-						$message = __( 'No plugins are available to be installed at this time.', 'tgmpa' );
2894
-					} else {
2895
-						$message = __( 'No plugins are available to be updated at this time.', 'tgmpa' );
2896
-					}
2897
-
2898
-					echo '<div id="message" class="error"><p>', esc_html( $message ), '</p></div>';
2899
-
2900
-					return false;
2901
-				}
2902
-
2903
-				// Pass all necessary information if WP_Filesystem is needed.
2904
-				$url = wp_nonce_url(
2905
-					$this->tgmpa->get_tgmpa_url(),
2906
-					'bulk-' . $this->_args['plural']
2907
-				);
2908
-
2909
-				// Give validated data back to $_POST which is the only place the filesystem looks for extra fields.
2910
-				$_POST['plugin'] = implode( ',', $plugins_to_install ); // Work around for WP bug #19643.
2911
-
2912
-				$method = ''; // Leave blank so WP_Filesystem can populate it as necessary.
2913
-				$fields = array_keys( $_POST ); // Extra fields to pass to WP_Filesystem.
2914
-
2915
-				if ( false === ( $creds = request_filesystem_credentials( esc_url_raw( $url ), $method, false, false, $fields ) ) ) {
2916
-					return true; // Stop the normal page form from displaying, credential request form will be shown.
2917
-				}
2918
-
2919
-				// Now we have some credentials, setup WP_Filesystem.
2920
-				if ( ! WP_Filesystem( $creds ) ) {
2921
-					// Our credentials were no good, ask the user for them again.
2922
-					request_filesystem_credentials( esc_url_raw( $url ), $method, true, false, $fields );
2923
-
2924
-					return true;
2925
-				}
2926
-
2927
-				/* If we arrive here, we have the filesystem */
2928
-
2929
-				// Store all information in arrays since we are processing a bulk installation.
2930
-				$names      = array();
2931
-				$sources    = array(); // Needed for installs.
2932
-				$file_paths = array(); // Needed for upgrades.
2933
-				$to_inject  = array(); // Information to inject into the update_plugins transient.
2934
-
2935
-				// Prepare the data for validated plugins for the install/upgrade.
2936
-				foreach ( $plugins_to_install as $slug ) {
2937
-					$name   = $this->tgmpa->plugins[ $slug ]['name'];
2938
-					$source = $this->tgmpa->get_download_url( $slug );
2939
-
2940
-					if ( ! empty( $name ) && ! empty( $source ) ) {
2941
-						$names[] = $name;
2942
-
2943
-						switch ( $install_type ) {
2944
-
2945
-							case 'install':
2946
-								$sources[] = $source;
2947
-								break;
2948
-
2949
-							case 'update':
2950
-								$file_paths[]                 = $this->tgmpa->plugins[ $slug ]['file_path'];
2951
-								$to_inject[ $slug ]           = $this->tgmpa->plugins[ $slug ];
2952
-								$to_inject[ $slug ]['source'] = $source;
2953
-								break;
2954
-						}
2955
-					}
2956
-				}
2957
-				unset( $slug, $name, $source );
2958
-
2959
-				// Create a new instance of TGMPA_Bulk_Installer.
2960
-				$installer = new TGMPA_Bulk_Installer(
2961
-					new TGMPA_Bulk_Installer_Skin(
2962
-						array(
2963
-							'url'          => esc_url_raw( $this->tgmpa->get_tgmpa_url() ),
2964
-							'nonce'        => 'bulk-' . $this->_args['plural'],
2965
-							'names'        => $names,
2966
-							'install_type' => $install_type,
2967
-						)
2968
-					)
2969
-				);
2970
-
2971
-				// Wrap the install process with the appropriate HTML.
2972
-				echo '<div class="tgmpa">',
2973
-					'<h2 style="font-size: 23px; font-weight: 400; line-height: 29px; margin: 0; padding: 9px 15px 4px 0;">', esc_html( get_admin_page_title() ), '</h2>
2782
+        }
2783
+
2784
+        /**
2785
+         * Extra controls to be displayed between bulk actions and pagination.
2786
+         *
2787
+         * @since 2.5.0
2788
+         *
2789
+         * @param string $which 'top' or 'bottom' table navigation.
2790
+         */
2791
+        public function extra_tablenav( $which ) {
2792
+            if ( 'bottom' === $which ) {
2793
+                $this->tgmpa->show_tgmpa_version();
2794
+            }
2795
+        }
2796
+
2797
+        /**
2798
+         * Defines the bulk actions for handling registered plugins.
2799
+         *
2800
+         * @since 2.2.0
2801
+         *
2802
+         * @return array $actions The bulk actions for the plugin install table.
2803
+         */
2804
+        public function get_bulk_actions() {
2805
+
2806
+            $actions = array();
2807
+
2808
+            if ( 'update' !== $this->view_context && 'activate' !== $this->view_context ) {
2809
+                if ( current_user_can( 'install_plugins' ) ) {
2810
+                    $actions['tgmpa-bulk-install'] = __( 'Install', 'tgmpa' );
2811
+                }
2812
+            }
2813
+
2814
+            if ( 'install' !== $this->view_context ) {
2815
+                if ( current_user_can( 'update_plugins' ) ) {
2816
+                    $actions['tgmpa-bulk-update'] = __( 'Update', 'tgmpa' );
2817
+                }
2818
+                if ( current_user_can( 'activate_plugins' ) ) {
2819
+                    $actions['tgmpa-bulk-activate'] = __( 'Activate', 'tgmpa' );
2820
+                }
2821
+            }
2822
+
2823
+            return $actions;
2824
+        }
2825
+
2826
+        /**
2827
+         * Processes bulk installation and activation actions.
2828
+         *
2829
+         * The bulk installation process looks for the $_POST information and passes that
2830
+         * through if a user has to use WP_Filesystem to enter their credentials.
2831
+         *
2832
+         * @since 2.2.0
2833
+         */
2834
+        public function process_bulk_actions() {
2835
+            // Bulk installation process.
2836
+            if ( 'tgmpa-bulk-install' === $this->current_action() || 'tgmpa-bulk-update' === $this->current_action() ) {
2837
+
2838
+                check_admin_referer( 'bulk-' . $this->_args['plural'] );
2839
+
2840
+                $install_type = 'install';
2841
+                if ( 'tgmpa-bulk-update' === $this->current_action() ) {
2842
+                    $install_type = 'update';
2843
+                }
2844
+
2845
+                $plugins_to_install = array();
2846
+
2847
+                // Did user actually select any plugins to install/update ?
2848
+                if ( empty( $_POST['plugin'] ) ) {
2849
+                    if ( 'install' === $install_type ) {
2850
+                        $message = __( 'No plugins were selected to be installed. No action taken.', 'tgmpa' );
2851
+                    } else {
2852
+                        $message = __( 'No plugins were selected to be updated. No action taken.', 'tgmpa' );
2853
+                    }
2854
+
2855
+                    echo '<div id="message" class="error"><p>', esc_html( $message ), '</p></div>';
2856
+
2857
+                    return false;
2858
+                }
2859
+
2860
+                if ( is_array( $_POST['plugin'] ) ) {
2861
+                    $plugins_to_install = (array) $_POST['plugin'];
2862
+                } elseif ( is_string( $_POST['plugin'] ) ) {
2863
+                    // Received via Filesystem page - un-flatten array (WP bug #19643).
2864
+                    $plugins_to_install = explode( ',', $_POST['plugin'] );
2865
+                }
2866
+
2867
+                // Sanitize the received input.
2868
+                $plugins_to_install = array_map( 'urldecode', $plugins_to_install );
2869
+                $plugins_to_install = array_map( array( $this->tgmpa, 'sanitize_key' ), $plugins_to_install );
2870
+
2871
+                // Validate the received input.
2872
+                foreach ( $plugins_to_install as $key => $slug ) {
2873
+                    // Check if the plugin was registered with TGMPA and remove if not.
2874
+                    if ( ! isset( $this->tgmpa->plugins[ $slug ] ) ) {
2875
+                        unset( $plugins_to_install[ $key ] );
2876
+                        continue;
2877
+                    }
2878
+
2879
+                    // For install: make sure this is a plugin we *can* install and not one already installed.
2880
+                    if ( 'install' === $install_type && true === $this->tgmpa->is_plugin_installed( $slug ) ) {
2881
+                        unset( $plugins_to_install[ $key ] );
2882
+                    }
2883
+
2884
+                    // For updates: make sure this is a plugin we *can* update (update available and WP version ok).
2885
+                    if ( 'update' === $install_type && false === $this->tgmpa->is_plugin_updatetable( $slug ) ) {
2886
+                        unset( $plugins_to_install[ $key ] );
2887
+                    }
2888
+                }
2889
+
2890
+                // No need to proceed further if we have no plugins to handle.
2891
+                if ( empty( $plugins_to_install ) ) {
2892
+                    if ( 'install' === $install_type ) {
2893
+                        $message = __( 'No plugins are available to be installed at this time.', 'tgmpa' );
2894
+                    } else {
2895
+                        $message = __( 'No plugins are available to be updated at this time.', 'tgmpa' );
2896
+                    }
2897
+
2898
+                    echo '<div id="message" class="error"><p>', esc_html( $message ), '</p></div>';
2899
+
2900
+                    return false;
2901
+                }
2902
+
2903
+                // Pass all necessary information if WP_Filesystem is needed.
2904
+                $url = wp_nonce_url(
2905
+                    $this->tgmpa->get_tgmpa_url(),
2906
+                    'bulk-' . $this->_args['plural']
2907
+                );
2908
+
2909
+                // Give validated data back to $_POST which is the only place the filesystem looks for extra fields.
2910
+                $_POST['plugin'] = implode( ',', $plugins_to_install ); // Work around for WP bug #19643.
2911
+
2912
+                $method = ''; // Leave blank so WP_Filesystem can populate it as necessary.
2913
+                $fields = array_keys( $_POST ); // Extra fields to pass to WP_Filesystem.
2914
+
2915
+                if ( false === ( $creds = request_filesystem_credentials( esc_url_raw( $url ), $method, false, false, $fields ) ) ) {
2916
+                    return true; // Stop the normal page form from displaying, credential request form will be shown.
2917
+                }
2918
+
2919
+                // Now we have some credentials, setup WP_Filesystem.
2920
+                if ( ! WP_Filesystem( $creds ) ) {
2921
+                    // Our credentials were no good, ask the user for them again.
2922
+                    request_filesystem_credentials( esc_url_raw( $url ), $method, true, false, $fields );
2923
+
2924
+                    return true;
2925
+                }
2926
+
2927
+                /* If we arrive here, we have the filesystem */
2928
+
2929
+                // Store all information in arrays since we are processing a bulk installation.
2930
+                $names      = array();
2931
+                $sources    = array(); // Needed for installs.
2932
+                $file_paths = array(); // Needed for upgrades.
2933
+                $to_inject  = array(); // Information to inject into the update_plugins transient.
2934
+
2935
+                // Prepare the data for validated plugins for the install/upgrade.
2936
+                foreach ( $plugins_to_install as $slug ) {
2937
+                    $name   = $this->tgmpa->plugins[ $slug ]['name'];
2938
+                    $source = $this->tgmpa->get_download_url( $slug );
2939
+
2940
+                    if ( ! empty( $name ) && ! empty( $source ) ) {
2941
+                        $names[] = $name;
2942
+
2943
+                        switch ( $install_type ) {
2944
+
2945
+                            case 'install':
2946
+                                $sources[] = $source;
2947
+                                break;
2948
+
2949
+                            case 'update':
2950
+                                $file_paths[]                 = $this->tgmpa->plugins[ $slug ]['file_path'];
2951
+                                $to_inject[ $slug ]           = $this->tgmpa->plugins[ $slug ];
2952
+                                $to_inject[ $slug ]['source'] = $source;
2953
+                                break;
2954
+                        }
2955
+                    }
2956
+                }
2957
+                unset( $slug, $name, $source );
2958
+
2959
+                // Create a new instance of TGMPA_Bulk_Installer.
2960
+                $installer = new TGMPA_Bulk_Installer(
2961
+                    new TGMPA_Bulk_Installer_Skin(
2962
+                        array(
2963
+                            'url'          => esc_url_raw( $this->tgmpa->get_tgmpa_url() ),
2964
+                            'nonce'        => 'bulk-' . $this->_args['plural'],
2965
+                            'names'        => $names,
2966
+                            'install_type' => $install_type,
2967
+                        )
2968
+                    )
2969
+                );
2970
+
2971
+                // Wrap the install process with the appropriate HTML.
2972
+                echo '<div class="tgmpa">',
2973
+                    '<h2 style="font-size: 23px; font-weight: 400; line-height: 29px; margin: 0; padding: 9px 15px 4px 0;">', esc_html( get_admin_page_title() ), '</h2>
2974 2974
 					<div class="update-php" style="width: 100%; height: 98%; min-height: 850px; padding-top: 1px;">';
2975 2975
 
2976
-				// Process the bulk installation submissions.
2977
-				add_filter( 'upgrader_source_selection', array( $this->tgmpa, 'maybe_adjust_source_dir' ), 1, 3 );
2978
-
2979
-				if ( 'tgmpa-bulk-update' === $this->current_action() ) {
2980
-					// Inject our info into the update transient.
2981
-					$this->tgmpa->inject_update_info( $to_inject );
2982
-
2983
-					$installer->bulk_upgrade( $file_paths );
2984
-				} else {
2985
-					$installer->bulk_install( $sources );
2986
-				}
2987
-
2988
-				remove_filter( 'upgrader_source_selection', array( $this->tgmpa, 'maybe_adjust_source_dir' ), 1 );
2989
-
2990
-				echo '</div></div>';
2991
-
2992
-				return true;
2993
-			}
2994
-
2995
-			// Bulk activation process.
2996
-			if ( 'tgmpa-bulk-activate' === $this->current_action() ) {
2997
-				check_admin_referer( 'bulk-' . $this->_args['plural'] );
2998
-
2999
-				// Did user actually select any plugins to activate ?
3000
-				if ( empty( $_POST['plugin'] ) ) {
3001
-					echo '<div id="message" class="error"><p>', esc_html__( 'No plugins were selected to be activated. No action taken.', 'tgmpa' ), '</p></div>';
3002
-
3003
-					return false;
3004
-				}
3005
-
3006
-				// Grab plugin data from $_POST.
3007
-				$plugins = array();
3008
-				if ( isset( $_POST['plugin'] ) ) {
3009
-					$plugins = array_map( 'urldecode', (array) $_POST['plugin'] );
3010
-					$plugins = array_map( array( $this->tgmpa, 'sanitize_key' ), $plugins );
3011
-				}
3012
-
3013
-				$plugins_to_activate = array();
3014
-				$plugin_names        = array();
3015
-
3016
-				// Grab the file paths for the selected & inactive plugins from the registration array.
3017
-				foreach ( $plugins as $slug ) {
3018
-					if ( $this->tgmpa->can_plugin_activate( $slug ) ) {
3019
-						$plugins_to_activate[] = $this->tgmpa->plugins[ $slug ]['file_path'];
3020
-						$plugin_names[]        = $this->tgmpa->plugins[ $slug ]['name'];
3021
-					}
3022
-				}
3023
-				unset( $slug );
3024
-
3025
-				// Return early if there are no plugins to activate.
3026
-				if ( empty( $plugins_to_activate ) ) {
3027
-					echo '<div id="message" class="error"><p>', esc_html__( 'No plugins are available to be activated at this time.', 'tgmpa' ), '</p></div>';
3028
-
3029
-					return false;
3030
-				}
3031
-
3032
-				// Now we are good to go - let's start activating plugins.
3033
-				$activate = activate_plugins( $plugins_to_activate );
3034
-
3035
-				if ( is_wp_error( $activate ) ) {
3036
-					echo '<div id="message" class="error"><p>', wp_kses_post( $activate->get_error_message() ), '</p></div>';
3037
-				} else {
3038
-					$count        = count( $plugin_names ); // Count so we can use _n function.
3039
-					$plugin_names = array_map( array( 'TGMPA_Utils', 'wrap_in_strong' ), $plugin_names );
3040
-					$last_plugin  = array_pop( $plugin_names ); // Pop off last name to prep for readability.
3041
-					$imploded     = empty( $plugin_names ) ? $last_plugin : ( implode( ', ', $plugin_names ) . ' ' . esc_html_x( 'and', 'plugin A *and* plugin B', 'tgmpa' ) . ' ' . $last_plugin );
3042
-
3043
-					printf( // WPCS: xss ok.
3044
-						'<div id="message" class="updated"><p>%1$s %2$s.</p></div>',
3045
-						esc_html( _n( 'The following plugin was activated successfully:', 'The following plugins were activated successfully:', $count, 'tgmpa' ) ),
3046
-						$imploded
3047
-					);
3048
-
3049
-					// Update recently activated plugins option.
3050
-					$recent = (array) get_option( 'recently_activated' );
3051
-					foreach ( $plugins_to_activate as $plugin => $time ) {
3052
-						if ( isset( $recent[ $plugin ] ) ) {
3053
-							unset( $recent[ $plugin ] );
3054
-						}
3055
-					}
3056
-					update_option( 'recently_activated', $recent );
3057
-				}
3058
-
3059
-				unset( $_POST ); // Reset the $_POST variable in case user wants to perform one action after another.
3060
-
3061
-				return true;
3062
-			}
3063
-
3064
-			return false;
3065
-		}
3066
-
3067
-		/**
3068
-		 * Prepares all of our information to be outputted into a usable table.
3069
-		 *
3070
-		 * @since 2.2.0
3071
-		 */
3072
-		public function prepare_items() {
3073
-			$columns               = $this->get_columns(); // Get all necessary column information.
3074
-			$hidden                = array(); // No columns to hide, but we must set as an array.
3075
-			$sortable              = array(); // No reason to make sortable columns.
3076
-			$primary               = $this->get_primary_column_name(); // Column which has the row actions.
3077
-			$this->_column_headers = array( $columns, $hidden, $sortable, $primary ); // Get all necessary column headers.
3078
-
3079
-			// Process our bulk activations here.
3080
-			if ( 'tgmpa-bulk-activate' === $this->current_action() ) {
3081
-				$this->process_bulk_actions();
3082
-			}
3083
-
3084
-			// Store all of our plugin data into $items array so WP_List_Table can use it.
3085
-			$this->items = apply_filters( 'tgmpa_table_data_items', $this->_gather_plugin_data() );
3086
-		}
3087
-
3088
-		/* *********** DEPRECATED METHODS *********** */
3089
-
3090
-		/**
3091
-		 * Retrieve plugin data, given the plugin name.
3092
-		 *
3093
-		 * @since      2.2.0
3094
-		 * @deprecated 2.5.0 use {@see TGM_Plugin_Activation::_get_plugin_data_from_name()} instead.
3095
-		 * @see        TGM_Plugin_Activation::_get_plugin_data_from_name()
3096
-		 *
3097
-		 * @param string $name Name of the plugin, as it was registered.
3098
-		 * @param string $data Optional. Array key of plugin data to return. Default is slug.
3099
-		 * @return string|boolean Plugin slug if found, false otherwise.
3100
-		 */
3101
-		protected function _get_plugin_data_from_name( $name, $data = 'slug' ) {
3102
-			_deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'TGM_Plugin_Activation::_get_plugin_data_from_name()' );
3103
-
3104
-			return $this->tgmpa->_get_plugin_data_from_name( $name, $data );
3105
-		}
3106
-	}
2976
+                // Process the bulk installation submissions.
2977
+                add_filter( 'upgrader_source_selection', array( $this->tgmpa, 'maybe_adjust_source_dir' ), 1, 3 );
2978
+
2979
+                if ( 'tgmpa-bulk-update' === $this->current_action() ) {
2980
+                    // Inject our info into the update transient.
2981
+                    $this->tgmpa->inject_update_info( $to_inject );
2982
+
2983
+                    $installer->bulk_upgrade( $file_paths );
2984
+                } else {
2985
+                    $installer->bulk_install( $sources );
2986
+                }
2987
+
2988
+                remove_filter( 'upgrader_source_selection', array( $this->tgmpa, 'maybe_adjust_source_dir' ), 1 );
2989
+
2990
+                echo '</div></div>';
2991
+
2992
+                return true;
2993
+            }
2994
+
2995
+            // Bulk activation process.
2996
+            if ( 'tgmpa-bulk-activate' === $this->current_action() ) {
2997
+                check_admin_referer( 'bulk-' . $this->_args['plural'] );
2998
+
2999
+                // Did user actually select any plugins to activate ?
3000
+                if ( empty( $_POST['plugin'] ) ) {
3001
+                    echo '<div id="message" class="error"><p>', esc_html__( 'No plugins were selected to be activated. No action taken.', 'tgmpa' ), '</p></div>';
3002
+
3003
+                    return false;
3004
+                }
3005
+
3006
+                // Grab plugin data from $_POST.
3007
+                $plugins = array();
3008
+                if ( isset( $_POST['plugin'] ) ) {
3009
+                    $plugins = array_map( 'urldecode', (array) $_POST['plugin'] );
3010
+                    $plugins = array_map( array( $this->tgmpa, 'sanitize_key' ), $plugins );
3011
+                }
3012
+
3013
+                $plugins_to_activate = array();
3014
+                $plugin_names        = array();
3015
+
3016
+                // Grab the file paths for the selected & inactive plugins from the registration array.
3017
+                foreach ( $plugins as $slug ) {
3018
+                    if ( $this->tgmpa->can_plugin_activate( $slug ) ) {
3019
+                        $plugins_to_activate[] = $this->tgmpa->plugins[ $slug ]['file_path'];
3020
+                        $plugin_names[]        = $this->tgmpa->plugins[ $slug ]['name'];
3021
+                    }
3022
+                }
3023
+                unset( $slug );
3024
+
3025
+                // Return early if there are no plugins to activate.
3026
+                if ( empty( $plugins_to_activate ) ) {
3027
+                    echo '<div id="message" class="error"><p>', esc_html__( 'No plugins are available to be activated at this time.', 'tgmpa' ), '</p></div>';
3028
+
3029
+                    return false;
3030
+                }
3031
+
3032
+                // Now we are good to go - let's start activating plugins.
3033
+                $activate = activate_plugins( $plugins_to_activate );
3034
+
3035
+                if ( is_wp_error( $activate ) ) {
3036
+                    echo '<div id="message" class="error"><p>', wp_kses_post( $activate->get_error_message() ), '</p></div>';
3037
+                } else {
3038
+                    $count        = count( $plugin_names ); // Count so we can use _n function.
3039
+                    $plugin_names = array_map( array( 'TGMPA_Utils', 'wrap_in_strong' ), $plugin_names );
3040
+                    $last_plugin  = array_pop( $plugin_names ); // Pop off last name to prep for readability.
3041
+                    $imploded     = empty( $plugin_names ) ? $last_plugin : ( implode( ', ', $plugin_names ) . ' ' . esc_html_x( 'and', 'plugin A *and* plugin B', 'tgmpa' ) . ' ' . $last_plugin );
3042
+
3043
+                    printf( // WPCS: xss ok.
3044
+                        '<div id="message" class="updated"><p>%1$s %2$s.</p></div>',
3045
+                        esc_html( _n( 'The following plugin was activated successfully:', 'The following plugins were activated successfully:', $count, 'tgmpa' ) ),
3046
+                        $imploded
3047
+                    );
3048
+
3049
+                    // Update recently activated plugins option.
3050
+                    $recent = (array) get_option( 'recently_activated' );
3051
+                    foreach ( $plugins_to_activate as $plugin => $time ) {
3052
+                        if ( isset( $recent[ $plugin ] ) ) {
3053
+                            unset( $recent[ $plugin ] );
3054
+                        }
3055
+                    }
3056
+                    update_option( 'recently_activated', $recent );
3057
+                }
3058
+
3059
+                unset( $_POST ); // Reset the $_POST variable in case user wants to perform one action after another.
3060
+
3061
+                return true;
3062
+            }
3063
+
3064
+            return false;
3065
+        }
3066
+
3067
+        /**
3068
+         * Prepares all of our information to be outputted into a usable table.
3069
+         *
3070
+         * @since 2.2.0
3071
+         */
3072
+        public function prepare_items() {
3073
+            $columns               = $this->get_columns(); // Get all necessary column information.
3074
+            $hidden                = array(); // No columns to hide, but we must set as an array.
3075
+            $sortable              = array(); // No reason to make sortable columns.
3076
+            $primary               = $this->get_primary_column_name(); // Column which has the row actions.
3077
+            $this->_column_headers = array( $columns, $hidden, $sortable, $primary ); // Get all necessary column headers.
3078
+
3079
+            // Process our bulk activations here.
3080
+            if ( 'tgmpa-bulk-activate' === $this->current_action() ) {
3081
+                $this->process_bulk_actions();
3082
+            }
3083
+
3084
+            // Store all of our plugin data into $items array so WP_List_Table can use it.
3085
+            $this->items = apply_filters( 'tgmpa_table_data_items', $this->_gather_plugin_data() );
3086
+        }
3087
+
3088
+        /* *********** DEPRECATED METHODS *********** */
3089
+
3090
+        /**
3091
+         * Retrieve plugin data, given the plugin name.
3092
+         *
3093
+         * @since      2.2.0
3094
+         * @deprecated 2.5.0 use {@see TGM_Plugin_Activation::_get_plugin_data_from_name()} instead.
3095
+         * @see        TGM_Plugin_Activation::_get_plugin_data_from_name()
3096
+         *
3097
+         * @param string $name Name of the plugin, as it was registered.
3098
+         * @param string $data Optional. Array key of plugin data to return. Default is slug.
3099
+         * @return string|boolean Plugin slug if found, false otherwise.
3100
+         */
3101
+        protected function _get_plugin_data_from_name( $name, $data = 'slug' ) {
3102
+            _deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'TGM_Plugin_Activation::_get_plugin_data_from_name()' );
3103
+
3104
+            return $this->tgmpa->_get_plugin_data_from_name( $name, $data );
3105
+        }
3106
+    }
3107 3107
 }
3108 3108
 
3109 3109
 
3110 3110
 if ( ! class_exists( 'TGM_Bulk_Installer' ) ) {
3111 3111
 
3112
-	/**
3113
-	 * Hack: Prevent TGMPA v2.4.1- bulk installer class from being loaded if 2.4.1- is loaded after 2.5+.
3114
-	 *
3115
-	 * @since 2.5.2
3116
-	 *
3117
-	 * {@internal The TGMPA_Bulk_Installer class was originally called TGM_Bulk_Installer.
3118
-	 *            For more information, see that class.}}
3119
-	 */
3120
-	class TGM_Bulk_Installer {
3121
-	}
3112
+    /**
3113
+     * Hack: Prevent TGMPA v2.4.1- bulk installer class from being loaded if 2.4.1- is loaded after 2.5+.
3114
+     *
3115
+     * @since 2.5.2
3116
+     *
3117
+     * {@internal The TGMPA_Bulk_Installer class was originally called TGM_Bulk_Installer.
3118
+     *            For more information, see that class.}}
3119
+     */
3120
+    class TGM_Bulk_Installer {
3121
+    }
3122 3122
 }
3123 3123
 if ( ! class_exists( 'TGM_Bulk_Installer_Skin' ) ) {
3124 3124
 
3125
-	/**
3126
-	 * Hack: Prevent TGMPA v2.4.1- bulk installer skin class from being loaded if 2.4.1- is loaded after 2.5+.
3127
-	 *
3128
-	 * @since 2.5.2
3129
-	 *
3130
-	 * {@internal The TGMPA_Bulk_Installer_Skin class was originally called TGM_Bulk_Installer_Skin.
3131
-	 *            For more information, see that class.}}
3132
-	 */
3133
-	class TGM_Bulk_Installer_Skin {
3134
-	}
3125
+    /**
3126
+     * Hack: Prevent TGMPA v2.4.1- bulk installer skin class from being loaded if 2.4.1- is loaded after 2.5+.
3127
+     *
3128
+     * @since 2.5.2
3129
+     *
3130
+     * {@internal The TGMPA_Bulk_Installer_Skin class was originally called TGM_Bulk_Installer_Skin.
3131
+     *            For more information, see that class.}}
3132
+     */
3133
+    class TGM_Bulk_Installer_Skin {
3134
+    }
3135 3135
 }
3136 3136
 
3137 3137
 /**
@@ -3146,210 +3146,210 @@  discard block
 block discarded – undo
3146 3146
  */
3147 3147
 add_action( 'admin_init', 'tgmpa_load_bulk_installer' );
3148 3148
 if ( ! function_exists( 'tgmpa_load_bulk_installer' ) ) {
3149
-	/**
3150
-	 * Load bulk installer
3151
-	 */
3152
-	function tgmpa_load_bulk_installer() {
3153
-		// Silently fail if 2.5+ is loaded *after* an older version.
3154
-		if ( ! isset( $GLOBALS['tgmpa'] ) ) {
3155
-			return;
3156
-		}
3157
-
3158
-		// Get TGMPA class instance.
3159
-		$tgmpa_instance = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
3160
-
3161
-		if ( isset( $_GET['page'] ) && $tgmpa_instance->menu === $_GET['page'] ) {
3162
-			if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
3163
-				require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
3164
-			}
3165
-
3166
-			if ( ! class_exists( 'TGMPA_Bulk_Installer' ) ) {
3167
-
3168
-				/**
3169
-				 * Installer class to handle bulk plugin installations.
3170
-				 *
3171
-				 * Extends WP_Upgrader and customizes to suit the installation of multiple
3172
-				 * plugins.
3173
-				 *
3174
-				 * @since 2.2.0
3175
-				 *
3176
-				 * {@internal Since 2.5.0 the class is an extension of Plugin_Upgrader rather than WP_Upgrader.}}
3177
-				 * {@internal Since 2.5.2 the class has been renamed from TGM_Bulk_Installer to TGMPA_Bulk_Installer.
3178
-				 *            This was done to prevent backward compatibility issues with v2.3.6.}}
3179
-				 *
3180
-				 * @package TGM-Plugin-Activation
3181
-				 * @author  Thomas Griffin
3182
-				 * @author  Gary Jones
3183
-				 */
3184
-				class TGMPA_Bulk_Installer extends Plugin_Upgrader {
3185
-					/**
3186
-					 * Holds result of bulk plugin installation.
3187
-					 *
3188
-					 * @since 2.2.0
3189
-					 *
3190
-					 * @var string
3191
-					 */
3192
-					public $result;
3193
-
3194
-					/**
3195
-					 * Flag to check if bulk installation is occurring or not.
3196
-					 *
3197
-					 * @since 2.2.0
3198
-					 *
3199
-					 * @var boolean
3200
-					 */
3201
-					public $bulk = false;
3202
-
3203
-					/**
3204
-					 * TGMPA instance
3205
-					 *
3206
-					 * @since 2.5.0
3207
-					 *
3208
-					 * @var object
3209
-					 */
3210
-					protected $tgmpa;
3211
-
3212
-					/**
3213
-					 * Whether or not the destination directory needs to be cleared ( = on update).
3214
-					 *
3215
-					 * @since 2.5.0
3216
-					 *
3217
-					 * @var bool
3218
-					 */
3219
-					protected $clear_destination = false;
3220
-
3221
-					/**
3222
-					 * References parent constructor and sets defaults for class.
3223
-					 *
3224
-					 * @since 2.2.0
3225
-					 *
3226
-					 * @param \Bulk_Upgrader_Skin|null $skin Installer skin.
3227
-					 */
3228
-					public function __construct( $skin = null ) {
3229
-						// Get TGMPA class instance.
3230
-						$this->tgmpa = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
3231
-
3232
-						parent::__construct( $skin );
3233
-
3234
-						if ( isset( $this->skin->options['install_type'] ) && 'update' === $this->skin->options['install_type'] ) {
3235
-							$this->clear_destination = true;
3236
-						}
3237
-
3238
-						if ( $this->tgmpa->is_automatic ) {
3239
-							$this->activate_strings();
3240
-						}
3241
-
3242
-						add_action( 'upgrader_process_complete', array( $this->tgmpa, 'populate_file_path' ) );
3243
-					}
3244
-
3245
-					/**
3246
-					 * Sets the correct activation strings for the installer skin to use.
3247
-					 *
3248
-					 * @since 2.2.0
3249
-					 */
3250
-					public function activate_strings() {
3251
-						$this->strings['activation_failed']  = __( 'Plugin activation failed.', 'tgmpa' );
3252
-						$this->strings['activation_success'] = __( 'Plugin activated successfully.', 'tgmpa' );
3253
-					}
3254
-
3255
-					/**
3256
-					 * Performs the actual installation of each plugin.
3257
-					 *
3258
-					 * @since 2.2.0
3259
-					 *
3260
-					 * @see WP_Upgrader::run()
3261
-					 *
3262
-					 * @param array $options The installation config options.
3263
-					 * @return null|array Return early if error, array of installation data on success.
3264
-					 */
3265
-					public function run( $options ) {
3266
-						$result = parent::run( $options );
3267
-
3268
-						// Reset the strings in case we changed one during automatic activation.
3269
-						if ( $this->tgmpa->is_automatic ) {
3270
-							if ( 'update' === $this->skin->options['install_type'] ) {
3271
-								$this->upgrade_strings();
3272
-							} else {
3273
-								$this->install_strings();
3274
-							}
3275
-						}
3276
-
3277
-						return $result;
3278
-					}
3279
-
3280
-					/**
3281
-					 * Processes the bulk installation of plugins.
3282
-					 *
3283
-					 * @since 2.2.0
3284
-					 *
3285
-					 * {@internal This is basically a near identical copy of the WP Core
3286
-					 * Plugin_Upgrader::bulk_upgrade() method, with minor adjustments to deal with
3287
-					 * new installs instead of upgrades.
3288
-					 * For ease of future synchronizations, the adjustments are clearly commented, but no other
3289
-					 * comments are added. Code style has been made to comply.}}
3290
-					 *
3291
-					 * @see Plugin_Upgrader::bulk_upgrade()
3292
-					 * @see https://core.trac.wordpress.org/browser/tags/4.2.1/src/wp-admin/includes/class-wp-upgrader.php#L838
3293
-					 * (@internal Last synced: Dec 31st 2015 against https://core.trac.wordpress.org/browser/trunk?rev=36134}}
3294
-					 *
3295
-					 * @param array $plugins The plugin sources needed for installation.
3296
-					 * @param array $args    Arbitrary passed extra arguments.
3297
-					 * @return array|false   Install confirmation messages on success, false on failure.
3298
-					 */
3299
-					public function bulk_install( $plugins, $args = array() ) {
3300
-						// [TGMPA + ] Hook auto-activation in.
3301
-						add_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3302
-
3303
-						$defaults    = array(
3304
-							'clear_update_cache' => true,
3305
-						);
3306
-						$parsed_args = wp_parse_args( $args, $defaults );
3307
-
3308
-						$this->init();
3309
-						$this->bulk = true;
3310
-
3311
-						$this->install_strings(); // [TGMPA + ] adjusted.
3312
-
3313
-						/* [TGMPA - ] $current = get_site_transient( 'update_plugins' ); */
3314
-
3315
-						/* [TGMPA - ] add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4); */
3316
-
3317
-						$this->skin->header();
3318
-
3319
-						// Connect to the Filesystem first.
3320
-						$res = $this->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) );
3321
-						if ( ! $res ) {
3322
-							$this->skin->footer();
3323
-							return false;
3324
-						}
3325
-
3326
-						$this->skin->bulk_header();
3327
-
3328
-						/*
3149
+    /**
3150
+     * Load bulk installer
3151
+     */
3152
+    function tgmpa_load_bulk_installer() {
3153
+        // Silently fail if 2.5+ is loaded *after* an older version.
3154
+        if ( ! isset( $GLOBALS['tgmpa'] ) ) {
3155
+            return;
3156
+        }
3157
+
3158
+        // Get TGMPA class instance.
3159
+        $tgmpa_instance = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
3160
+
3161
+        if ( isset( $_GET['page'] ) && $tgmpa_instance->menu === $_GET['page'] ) {
3162
+            if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
3163
+                require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
3164
+            }
3165
+
3166
+            if ( ! class_exists( 'TGMPA_Bulk_Installer' ) ) {
3167
+
3168
+                /**
3169
+                 * Installer class to handle bulk plugin installations.
3170
+                 *
3171
+                 * Extends WP_Upgrader and customizes to suit the installation of multiple
3172
+                 * plugins.
3173
+                 *
3174
+                 * @since 2.2.0
3175
+                 *
3176
+                 * {@internal Since 2.5.0 the class is an extension of Plugin_Upgrader rather than WP_Upgrader.}}
3177
+                 * {@internal Since 2.5.2 the class has been renamed from TGM_Bulk_Installer to TGMPA_Bulk_Installer.
3178
+                 *            This was done to prevent backward compatibility issues with v2.3.6.}}
3179
+                 *
3180
+                 * @package TGM-Plugin-Activation
3181
+                 * @author  Thomas Griffin
3182
+                 * @author  Gary Jones
3183
+                 */
3184
+                class TGMPA_Bulk_Installer extends Plugin_Upgrader {
3185
+                    /**
3186
+                     * Holds result of bulk plugin installation.
3187
+                     *
3188
+                     * @since 2.2.0
3189
+                     *
3190
+                     * @var string
3191
+                     */
3192
+                    public $result;
3193
+
3194
+                    /**
3195
+                     * Flag to check if bulk installation is occurring or not.
3196
+                     *
3197
+                     * @since 2.2.0
3198
+                     *
3199
+                     * @var boolean
3200
+                     */
3201
+                    public $bulk = false;
3202
+
3203
+                    /**
3204
+                     * TGMPA instance
3205
+                     *
3206
+                     * @since 2.5.0
3207
+                     *
3208
+                     * @var object
3209
+                     */
3210
+                    protected $tgmpa;
3211
+
3212
+                    /**
3213
+                     * Whether or not the destination directory needs to be cleared ( = on update).
3214
+                     *
3215
+                     * @since 2.5.0
3216
+                     *
3217
+                     * @var bool
3218
+                     */
3219
+                    protected $clear_destination = false;
3220
+
3221
+                    /**
3222
+                     * References parent constructor and sets defaults for class.
3223
+                     *
3224
+                     * @since 2.2.0
3225
+                     *
3226
+                     * @param \Bulk_Upgrader_Skin|null $skin Installer skin.
3227
+                     */
3228
+                    public function __construct( $skin = null ) {
3229
+                        // Get TGMPA class instance.
3230
+                        $this->tgmpa = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
3231
+
3232
+                        parent::__construct( $skin );
3233
+
3234
+                        if ( isset( $this->skin->options['install_type'] ) && 'update' === $this->skin->options['install_type'] ) {
3235
+                            $this->clear_destination = true;
3236
+                        }
3237
+
3238
+                        if ( $this->tgmpa->is_automatic ) {
3239
+                            $this->activate_strings();
3240
+                        }
3241
+
3242
+                        add_action( 'upgrader_process_complete', array( $this->tgmpa, 'populate_file_path' ) );
3243
+                    }
3244
+
3245
+                    /**
3246
+                     * Sets the correct activation strings for the installer skin to use.
3247
+                     *
3248
+                     * @since 2.2.0
3249
+                     */
3250
+                    public function activate_strings() {
3251
+                        $this->strings['activation_failed']  = __( 'Plugin activation failed.', 'tgmpa' );
3252
+                        $this->strings['activation_success'] = __( 'Plugin activated successfully.', 'tgmpa' );
3253
+                    }
3254
+
3255
+                    /**
3256
+                     * Performs the actual installation of each plugin.
3257
+                     *
3258
+                     * @since 2.2.0
3259
+                     *
3260
+                     * @see WP_Upgrader::run()
3261
+                     *
3262
+                     * @param array $options The installation config options.
3263
+                     * @return null|array Return early if error, array of installation data on success.
3264
+                     */
3265
+                    public function run( $options ) {
3266
+                        $result = parent::run( $options );
3267
+
3268
+                        // Reset the strings in case we changed one during automatic activation.
3269
+                        if ( $this->tgmpa->is_automatic ) {
3270
+                            if ( 'update' === $this->skin->options['install_type'] ) {
3271
+                                $this->upgrade_strings();
3272
+                            } else {
3273
+                                $this->install_strings();
3274
+                            }
3275
+                        }
3276
+
3277
+                        return $result;
3278
+                    }
3279
+
3280
+                    /**
3281
+                     * Processes the bulk installation of plugins.
3282
+                     *
3283
+                     * @since 2.2.0
3284
+                     *
3285
+                     * {@internal This is basically a near identical copy of the WP Core
3286
+                     * Plugin_Upgrader::bulk_upgrade() method, with minor adjustments to deal with
3287
+                     * new installs instead of upgrades.
3288
+                     * For ease of future synchronizations, the adjustments are clearly commented, but no other
3289
+                     * comments are added. Code style has been made to comply.}}
3290
+                     *
3291
+                     * @see Plugin_Upgrader::bulk_upgrade()
3292
+                     * @see https://core.trac.wordpress.org/browser/tags/4.2.1/src/wp-admin/includes/class-wp-upgrader.php#L838
3293
+                     * (@internal Last synced: Dec 31st 2015 against https://core.trac.wordpress.org/browser/trunk?rev=36134}}
3294
+                     *
3295
+                     * @param array $plugins The plugin sources needed for installation.
3296
+                     * @param array $args    Arbitrary passed extra arguments.
3297
+                     * @return array|false   Install confirmation messages on success, false on failure.
3298
+                     */
3299
+                    public function bulk_install( $plugins, $args = array() ) {
3300
+                        // [TGMPA + ] Hook auto-activation in.
3301
+                        add_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3302
+
3303
+                        $defaults    = array(
3304
+                            'clear_update_cache' => true,
3305
+                        );
3306
+                        $parsed_args = wp_parse_args( $args, $defaults );
3307
+
3308
+                        $this->init();
3309
+                        $this->bulk = true;
3310
+
3311
+                        $this->install_strings(); // [TGMPA + ] adjusted.
3312
+
3313
+                        /* [TGMPA - ] $current = get_site_transient( 'update_plugins' ); */
3314
+
3315
+                        /* [TGMPA - ] add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4); */
3316
+
3317
+                        $this->skin->header();
3318
+
3319
+                        // Connect to the Filesystem first.
3320
+                        $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) );
3321
+                        if ( ! $res ) {
3322
+                            $this->skin->footer();
3323
+                            return false;
3324
+                        }
3325
+
3326
+                        $this->skin->bulk_header();
3327
+
3328
+                        /*
3329 3329
 						 * Only start maintenance mode if:
3330 3330
 						 * - running Multisite and there are one or more plugins specified, OR
3331 3331
 						 * - a plugin with an update available is currently active.
3332 3332
 						 * @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
3333 3333
 						 */
3334
-						$maintenance = ( is_multisite() && ! empty( $plugins ) );
3334
+                        $maintenance = ( is_multisite() && ! empty( $plugins ) );
3335 3335
 
3336
-						/*
3336
+                        /*
3337 3337
 						[TGMPA - ]
3338 3338
 						foreach ( $plugins as $plugin )
3339 3339
 							$maintenance = $maintenance || ( is_plugin_active( $plugin ) && isset( $current->response[ $plugin] ) );
3340 3340
 						*/
3341
-						if ( $maintenance ) {
3342
-							$this->maintenance_mode( true );
3343
-						}
3341
+                        if ( $maintenance ) {
3342
+                            $this->maintenance_mode( true );
3343
+                        }
3344 3344
 
3345
-						$results = array();
3345
+                        $results = array();
3346 3346
 
3347
-						$this->update_count   = count( $plugins );
3348
-						$this->update_current = 0;
3349
-						foreach ( $plugins as $plugin ) {
3350
-							$this->update_current++;
3347
+                        $this->update_count   = count( $plugins );
3348
+                        $this->update_current = 0;
3349
+                        foreach ( $plugins as $plugin ) {
3350
+                            $this->update_current++;
3351 3351
 
3352
-							/*
3352
+                            /*
3353 3353
 							[TGMPA - ]
3354 3354
 							$this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true);
3355 3355
 
@@ -3368,486 +3368,486 @@  discard block
 block discarded – undo
3368 3368
 							$this->skin->plugin_active = is_plugin_active($plugin);
3369 3369
 							*/
3370 3370
 
3371
-							$result = $this->run(
3372
-								array(
3373
-									'package'           => $plugin, // [TGMPA + ] adjusted.
3374
-									'destination'       => WP_PLUGIN_DIR,
3375
-									'clear_destination' => false, // [TGMPA + ] adjusted.
3376
-									'clear_working'     => true,
3377
-									'is_multi'          => true,
3378
-									'hook_extra'        => array(
3379
-										'plugin' => $plugin,
3380
-									),
3381
-								)
3382
-							);
3383
-
3384
-							$results[ $plugin ] = $this->result;
3385
-
3386
-							// Prevent credentials auth screen from displaying multiple times.
3387
-							if ( false === $result ) {
3388
-								break;
3389
-							}
3390
-						} //end foreach $plugins
3391
-
3392
-						$this->maintenance_mode( false );
3393
-
3394
-						/**
3395
-						 * Fires when the bulk upgrader process is complete.
3396
-						 *
3397
-						 * @since WP 3.6.0 / TGMPA 2.5.0
3398
-						 *
3399
-						 * @param Plugin_Upgrader $this Plugin_Upgrader instance. In other contexts, $this, might
3400
-						 *                              be a Theme_Upgrader or Core_Upgrade instance.
3401
-						 * @param array           $data {
3402
-						 *     Array of bulk item update data.
3403
-						 *
3404
-						 *     @type string $action   Type of action. Default 'update'.
3405
-						 *     @type string $type     Type of update process. Accepts 'plugin', 'theme', or 'core'.
3406
-						 *     @type bool   $bulk     Whether the update process is a bulk update. Default true.
3407
-						 *     @type array  $packages Array of plugin, theme, or core packages to update.
3408
-						 * }
3409
-						 */
3410
-						do_action( 'upgrader_process_complete', $this, array(
3411
-							'action'  => 'install', // [TGMPA + ] adjusted.
3412
-							'type'    => 'plugin',
3413
-							'bulk'    => true,
3414
-							'plugins' => $plugins,
3415
-						) );
3416
-
3417
-						$this->skin->bulk_footer();
3418
-
3419
-						$this->skin->footer();
3420
-
3421
-						// Cleanup our hooks, in case something else does a upgrade on this connection.
3422
-						/* [TGMPA - ] remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin')); */
3423
-
3424
-						// [TGMPA + ] Remove our auto-activation hook.
3425
-						remove_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3426
-
3427
-						// Force refresh of plugin update information.
3428
-						wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
3429
-
3430
-						return $results;
3431
-					}
3432
-
3433
-					/**
3434
-					 * Handle a bulk upgrade request.
3435
-					 *
3436
-					 * @since 2.5.0
3437
-					 *
3438
-					 * @see Plugin_Upgrader::bulk_upgrade()
3439
-					 *
3440
-					 * @param array $plugins The local WP file_path's of the plugins which should be upgraded.
3441
-					 * @param array $args    Arbitrary passed extra arguments.
3442
-					 * @return string|bool Install confirmation messages on success, false on failure.
3443
-					 */
3444
-					public function bulk_upgrade( $plugins, $args = array() ) {
3445
-
3446
-						add_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3447
-
3448
-						$result = parent::bulk_upgrade( $plugins, $args );
3449
-
3450
-						remove_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3451
-
3452
-						return $result;
3453
-					}
3454
-
3455
-					/**
3456
-					 * Abuse a filter to auto-activate plugins after installation.
3457
-					 *
3458
-					 * Hooked into the 'upgrader_post_install' filter hook.
3459
-					 *
3460
-					 * @since 2.5.0
3461
-					 *
3462
-					 * @param bool $bool The value we need to give back (true).
3463
-					 * @return bool
3464
-					 */
3465
-					public function auto_activate( $bool ) {
3466
-						// Only process the activation of installed plugins if the automatic flag is set to true.
3467
-						if ( $this->tgmpa->is_automatic ) {
3468
-							// Flush plugins cache so the headers of the newly installed plugins will be read correctly.
3469
-							wp_clean_plugins_cache();
3470
-
3471
-							// Get the installed plugin file.
3472
-							$plugin_info = $this->plugin_info();
3473
-
3474
-							// Don't try to activate on upgrade of active plugin as WP will do this already.
3475
-							if ( ! is_plugin_active( $plugin_info ) ) {
3476
-								$activate = activate_plugin( $plugin_info );
3477
-
3478
-								// Adjust the success string based on the activation result.
3479
-								$this->strings['process_success'] = $this->strings['process_success'] . "<br />\n";
3480
-
3481
-								if ( is_wp_error( $activate ) ) {
3482
-									$this->skin->error( $activate );
3483
-									$this->strings['process_success'] .= $this->strings['activation_failed'];
3484
-								} else {
3485
-									$this->strings['process_success'] .= $this->strings['activation_success'];
3486
-								}
3487
-							}
3488
-						}
3489
-
3490
-						return $bool;
3491
-					}
3492
-				}
3493
-			}
3494
-
3495
-			if ( ! class_exists( 'TGMPA_Bulk_Installer_Skin' ) ) {
3496
-
3497
-				/**
3498
-				 * Installer skin to set strings for the bulk plugin installations..
3499
-				 *
3500
-				 * Extends Bulk_Upgrader_Skin and customizes to suit the installation of multiple
3501
-				 * plugins.
3502
-				 *
3503
-				 * @since 2.2.0
3504
-				 *
3505
-				 * {@internal Since 2.5.2 the class has been renamed from TGM_Bulk_Installer_Skin to
3506
-				 *            TGMPA_Bulk_Installer_Skin.
3507
-				 *            This was done to prevent backward compatibility issues with v2.3.6.}}
3508
-				 *
3509
-				 * @see https://core.trac.wordpress.org/browser/trunk/src/wp-admin/includes/class-wp-upgrader-skins.php
3510
-				 *
3511
-				 * @package TGM-Plugin-Activation
3512
-				 * @author  Thomas Griffin
3513
-				 * @author  Gary Jones
3514
-				 */
3515
-				class TGMPA_Bulk_Installer_Skin extends Bulk_Upgrader_Skin {
3516
-					/**
3517
-					 * Holds plugin info for each individual plugin installation.
3518
-					 *
3519
-					 * @since 2.2.0
3520
-					 *
3521
-					 * @var array
3522
-					 */
3523
-					public $plugin_info = array();
3524
-
3525
-					/**
3526
-					 * Holds names of plugins that are undergoing bulk installations.
3527
-					 *
3528
-					 * @since 2.2.0
3529
-					 *
3530
-					 * @var array
3531
-					 */
3532
-					public $plugin_names = array();
3533
-
3534
-					/**
3535
-					 * Integer to use for iteration through each plugin installation.
3536
-					 *
3537
-					 * @since 2.2.0
3538
-					 *
3539
-					 * @var integer
3540
-					 */
3541
-					public $i = 0;
3542
-
3543
-					/**
3544
-					 * TGMPA instance
3545
-					 *
3546
-					 * @since 2.5.0
3547
-					 *
3548
-					 * @var object
3549
-					 */
3550
-					protected $tgmpa;
3551
-
3552
-					/**
3553
-					 * Constructor. Parses default args with new ones and extracts them for use.
3554
-					 *
3555
-					 * @since 2.2.0
3556
-					 *
3557
-					 * @param array $args Arguments to pass for use within the class.
3558
-					 */
3559
-					public function __construct( $args = array() ) {
3560
-						// Get TGMPA class instance.
3561
-						$this->tgmpa = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
3562
-
3563
-						// Parse default and new args.
3564
-						$defaults = array(
3565
-							'url'          => '',
3566
-							'nonce'        => '',
3567
-							'names'        => array(),
3568
-							'install_type' => 'install',
3569
-						);
3570
-						$args     = wp_parse_args( $args, $defaults );
3571
-
3572
-						// Set plugin names to $this->plugin_names property.
3573
-						$this->plugin_names = $args['names'];
3574
-
3575
-						// Extract the new args.
3576
-						parent::__construct( $args );
3577
-					}
3578
-
3579
-					/**
3580
-					 * Sets install skin strings for each individual plugin.
3581
-					 *
3582
-					 * Checks to see if the automatic activation flag is set and uses the
3583
-					 * the proper strings accordingly.
3584
-					 *
3585
-					 * @since 2.2.0
3586
-					 */
3587
-					public function add_strings() {
3588
-						if ( 'update' === $this->options['install_type'] ) {
3589
-							parent::add_strings();
3590
-							/* translators: 1: plugin name, 2: action number 3: total number of actions. */
3591
-							$this->upgrader->strings['skin_before_update_header'] = __( 'Updating Plugin %1$s (%2$d/%3$d)', 'tgmpa' );
3592
-						} else {
3593
-							/* translators: 1: plugin name, 2: error message. */
3594
-							$this->upgrader->strings['skin_update_failed_error'] = __( 'An error occurred while installing %1$s: <strong>%2$s</strong>.', 'tgmpa' );
3595
-							/* translators: 1: plugin name. */
3596
-							$this->upgrader->strings['skin_update_failed'] = __( 'The installation of %1$s failed.', 'tgmpa' );
3597
-
3598
-							if ( $this->tgmpa->is_automatic ) {
3599
-								// Automatic activation strings.
3600
-								$this->upgrader->strings['skin_upgrade_start'] = __( 'The installation and activation process is starting. This process may take a while on some hosts, so please be patient.', 'tgmpa' );
3601
-								/* translators: 1: plugin name. */
3602
-								$this->upgrader->strings['skin_update_successful'] = __( '%1$s installed and activated successfully.', 'tgmpa' ) . ' <a href="#" class="hide-if-no-js" onclick="%2$s"><span>' . esc_html__( 'Show Details', 'tgmpa' ) . '</span><span class="hidden">' . esc_html__( 'Hide Details', 'tgmpa' ) . '</span>.</a>';
3603
-								$this->upgrader->strings['skin_upgrade_end']       = __( 'All installations and activations have been completed.', 'tgmpa' );
3604
-								/* translators: 1: plugin name, 2: action number 3: total number of actions. */
3605
-								$this->upgrader->strings['skin_before_update_header'] = __( 'Installing and Activating Plugin %1$s (%2$d/%3$d)', 'tgmpa' );
3606
-							} else {
3607
-								// Default installation strings.
3608
-								$this->upgrader->strings['skin_upgrade_start'] = __( 'The installation process is starting. This process may take a while on some hosts, so please be patient.', 'tgmpa' );
3609
-								/* translators: 1: plugin name. */
3610
-								$this->upgrader->strings['skin_update_successful'] = esc_html__( '%1$s installed successfully.', 'tgmpa' ) . ' <a href="#" class="hide-if-no-js" onclick="%2$s"><span>' . esc_html__( 'Show Details', 'tgmpa' ) . '</span><span class="hidden">' . esc_html__( 'Hide Details', 'tgmpa' ) . '</span>.</a>';
3611
-								$this->upgrader->strings['skin_upgrade_end']       = __( 'All installations have been completed.', 'tgmpa' );
3612
-								/* translators: 1: plugin name, 2: action number 3: total number of actions. */
3613
-								$this->upgrader->strings['skin_before_update_header'] = __( 'Installing Plugin %1$s (%2$d/%3$d)', 'tgmpa' );
3614
-							}
3615
-						}
3616
-					}
3617
-
3618
-					/**
3619
-					 * Outputs the header strings and necessary JS before each plugin installation.
3620
-					 *
3621
-					 * @since 2.2.0
3622
-					 *
3623
-					 * @param string $title Unused in this implementation.
3624
-					 */
3625
-					public function before( $title = '' ) {
3626
-						if ( empty( $title ) ) {
3627
-							$title = esc_html( $this->plugin_names[ $this->i ] );
3628
-						}
3629
-						parent::before( $title );
3630
-					}
3631
-
3632
-					/**
3633
-					 * Outputs the footer strings and necessary JS after each plugin installation.
3634
-					 *
3635
-					 * Checks for any errors and outputs them if they exist, else output
3636
-					 * success strings.
3637
-					 *
3638
-					 * @since 2.2.0
3639
-					 *
3640
-					 * @param string $title Unused in this implementation.
3641
-					 */
3642
-					public function after( $title = '' ) {
3643
-						if ( empty( $title ) ) {
3644
-							$title = esc_html( $this->plugin_names[ $this->i ] );
3645
-						}
3646
-						parent::after( $title );
3647
-
3648
-						$this->i++;
3649
-					}
3650
-
3651
-					/**
3652
-					 * Outputs links after bulk plugin installation is complete.
3653
-					 *
3654
-					 * @since 2.2.0
3655
-					 */
3656
-					public function bulk_footer() {
3657
-						// Serve up the string to say installations (and possibly activations) are complete.
3658
-						parent::bulk_footer();
3659
-
3660
-						// Flush plugins cache so we can make sure that the installed plugins list is always up to date.
3661
-						wp_clean_plugins_cache();
3662
-
3663
-						$this->tgmpa->show_tgmpa_version();
3664
-
3665
-						// Display message based on if all plugins are now active or not.
3666
-						$update_actions = array();
3667
-
3668
-						if ( $this->tgmpa->is_tgmpa_complete() ) {
3669
-							// All plugins are active, so we display the complete string and hide the menu to protect users.
3670
-							echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>';
3671
-							$update_actions['dashboard'] = sprintf(
3672
-								esc_html( $this->tgmpa->strings['complete'] ),
3673
-								'<a href="' . esc_url( self_admin_url() ) . '">' . esc_html__( 'Return to the Dashboard', 'tgmpa' ) . '</a>'
3674
-							);
3675
-						} else {
3676
-							$update_actions['tgmpa_page'] = '<a href="' . esc_url( $this->tgmpa->get_tgmpa_url() ) . '" target="_parent">' . esc_html( $this->tgmpa->strings['return'] ) . '</a>';
3677
-						}
3678
-
3679
-						/**
3680
-						 * Filter the list of action links available following bulk plugin installs/updates.
3681
-						 *
3682
-						 * @since 2.5.0
3683
-						 *
3684
-						 * @param array $update_actions Array of plugin action links.
3685
-						 * @param array $plugin_info    Array of information for the last-handled plugin.
3686
-						 */
3687
-						$update_actions = apply_filters( 'tgmpa_update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info );
3688
-
3689
-						if ( ! empty( $update_actions ) ) {
3690
-							$this->feedback( implode( ' | ', (array) $update_actions ) );
3691
-						}
3692
-					}
3693
-
3694
-					/* *********** DEPRECATED METHODS *********** */
3695
-
3696
-					/**
3697
-					 * Flush header output buffer.
3698
-					 *
3699
-					 * @since      2.2.0
3700
-					 * @deprecated 2.5.0 use {@see Bulk_Upgrader_Skin::flush_output()} instead
3701
-					 * @see        Bulk_Upgrader_Skin::flush_output()
3702
-					 */
3703
-					public function before_flush_output() {
3704
-						_deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'Bulk_Upgrader_Skin::flush_output()' );
3705
-						$this->flush_output();
3706
-					}
3707
-
3708
-					/**
3709
-					 * Flush footer output buffer and iterate $this->i to make sure the
3710
-					 * installation strings reference the correct plugin.
3711
-					 *
3712
-					 * @since      2.2.0
3713
-					 * @deprecated 2.5.0 use {@see Bulk_Upgrader_Skin::flush_output()} instead
3714
-					 * @see        Bulk_Upgrader_Skin::flush_output()
3715
-					 */
3716
-					public function after_flush_output() {
3717
-						_deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'Bulk_Upgrader_Skin::flush_output()' );
3718
-						$this->flush_output();
3719
-						$this->i++;
3720
-					}
3721
-				}
3722
-			}
3723
-		}
3724
-	}
3371
+                            $result = $this->run(
3372
+                                array(
3373
+                                    'package'           => $plugin, // [TGMPA + ] adjusted.
3374
+                                    'destination'       => WP_PLUGIN_DIR,
3375
+                                    'clear_destination' => false, // [TGMPA + ] adjusted.
3376
+                                    'clear_working'     => true,
3377
+                                    'is_multi'          => true,
3378
+                                    'hook_extra'        => array(
3379
+                                        'plugin' => $plugin,
3380
+                                    ),
3381
+                                )
3382
+                            );
3383
+
3384
+                            $results[ $plugin ] = $this->result;
3385
+
3386
+                            // Prevent credentials auth screen from displaying multiple times.
3387
+                            if ( false === $result ) {
3388
+                                break;
3389
+                            }
3390
+                        } //end foreach $plugins
3391
+
3392
+                        $this->maintenance_mode( false );
3393
+
3394
+                        /**
3395
+                         * Fires when the bulk upgrader process is complete.
3396
+                         *
3397
+                         * @since WP 3.6.0 / TGMPA 2.5.0
3398
+                         *
3399
+                         * @param Plugin_Upgrader $this Plugin_Upgrader instance. In other contexts, $this, might
3400
+                         *                              be a Theme_Upgrader or Core_Upgrade instance.
3401
+                         * @param array           $data {
3402
+                         *     Array of bulk item update data.
3403
+                         *
3404
+                         *     @type string $action   Type of action. Default 'update'.
3405
+                         *     @type string $type     Type of update process. Accepts 'plugin', 'theme', or 'core'.
3406
+                         *     @type bool   $bulk     Whether the update process is a bulk update. Default true.
3407
+                         *     @type array  $packages Array of plugin, theme, or core packages to update.
3408
+                         * }
3409
+                         */
3410
+                        do_action( 'upgrader_process_complete', $this, array(
3411
+                            'action'  => 'install', // [TGMPA + ] adjusted.
3412
+                            'type'    => 'plugin',
3413
+                            'bulk'    => true,
3414
+                            'plugins' => $plugins,
3415
+                        ) );
3416
+
3417
+                        $this->skin->bulk_footer();
3418
+
3419
+                        $this->skin->footer();
3420
+
3421
+                        // Cleanup our hooks, in case something else does a upgrade on this connection.
3422
+                        /* [TGMPA - ] remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin')); */
3423
+
3424
+                        // [TGMPA + ] Remove our auto-activation hook.
3425
+                        remove_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3426
+
3427
+                        // Force refresh of plugin update information.
3428
+                        wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
3429
+
3430
+                        return $results;
3431
+                    }
3432
+
3433
+                    /**
3434
+                     * Handle a bulk upgrade request.
3435
+                     *
3436
+                     * @since 2.5.0
3437
+                     *
3438
+                     * @see Plugin_Upgrader::bulk_upgrade()
3439
+                     *
3440
+                     * @param array $plugins The local WP file_path's of the plugins which should be upgraded.
3441
+                     * @param array $args    Arbitrary passed extra arguments.
3442
+                     * @return string|bool Install confirmation messages on success, false on failure.
3443
+                     */
3444
+                    public function bulk_upgrade( $plugins, $args = array() ) {
3445
+
3446
+                        add_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3447
+
3448
+                        $result = parent::bulk_upgrade( $plugins, $args );
3449
+
3450
+                        remove_filter( 'upgrader_post_install', array( $this, 'auto_activate' ), 10 );
3451
+
3452
+                        return $result;
3453
+                    }
3454
+
3455
+                    /**
3456
+                     * Abuse a filter to auto-activate plugins after installation.
3457
+                     *
3458
+                     * Hooked into the 'upgrader_post_install' filter hook.
3459
+                     *
3460
+                     * @since 2.5.0
3461
+                     *
3462
+                     * @param bool $bool The value we need to give back (true).
3463
+                     * @return bool
3464
+                     */
3465
+                    public function auto_activate( $bool ) {
3466
+                        // Only process the activation of installed plugins if the automatic flag is set to true.
3467
+                        if ( $this->tgmpa->is_automatic ) {
3468
+                            // Flush plugins cache so the headers of the newly installed plugins will be read correctly.
3469
+                            wp_clean_plugins_cache();
3470
+
3471
+                            // Get the installed plugin file.
3472
+                            $plugin_info = $this->plugin_info();
3473
+
3474
+                            // Don't try to activate on upgrade of active plugin as WP will do this already.
3475
+                            if ( ! is_plugin_active( $plugin_info ) ) {
3476
+                                $activate = activate_plugin( $plugin_info );
3477
+
3478
+                                // Adjust the success string based on the activation result.
3479
+                                $this->strings['process_success'] = $this->strings['process_success'] . "<br />\n";
3480
+
3481
+                                if ( is_wp_error( $activate ) ) {
3482
+                                    $this->skin->error( $activate );
3483
+                                    $this->strings['process_success'] .= $this->strings['activation_failed'];
3484
+                                } else {
3485
+                                    $this->strings['process_success'] .= $this->strings['activation_success'];
3486
+                                }
3487
+                            }
3488
+                        }
3489
+
3490
+                        return $bool;
3491
+                    }
3492
+                }
3493
+            }
3494
+
3495
+            if ( ! class_exists( 'TGMPA_Bulk_Installer_Skin' ) ) {
3496
+
3497
+                /**
3498
+                 * Installer skin to set strings for the bulk plugin installations..
3499
+                 *
3500
+                 * Extends Bulk_Upgrader_Skin and customizes to suit the installation of multiple
3501
+                 * plugins.
3502
+                 *
3503
+                 * @since 2.2.0
3504
+                 *
3505
+                 * {@internal Since 2.5.2 the class has been renamed from TGM_Bulk_Installer_Skin to
3506
+                 *            TGMPA_Bulk_Installer_Skin.
3507
+                 *            This was done to prevent backward compatibility issues with v2.3.6.}}
3508
+                 *
3509
+                 * @see https://core.trac.wordpress.org/browser/trunk/src/wp-admin/includes/class-wp-upgrader-skins.php
3510
+                 *
3511
+                 * @package TGM-Plugin-Activation
3512
+                 * @author  Thomas Griffin
3513
+                 * @author  Gary Jones
3514
+                 */
3515
+                class TGMPA_Bulk_Installer_Skin extends Bulk_Upgrader_Skin {
3516
+                    /**
3517
+                     * Holds plugin info for each individual plugin installation.
3518
+                     *
3519
+                     * @since 2.2.0
3520
+                     *
3521
+                     * @var array
3522
+                     */
3523
+                    public $plugin_info = array();
3524
+
3525
+                    /**
3526
+                     * Holds names of plugins that are undergoing bulk installations.
3527
+                     *
3528
+                     * @since 2.2.0
3529
+                     *
3530
+                     * @var array
3531
+                     */
3532
+                    public $plugin_names = array();
3533
+
3534
+                    /**
3535
+                     * Integer to use for iteration through each plugin installation.
3536
+                     *
3537
+                     * @since 2.2.0
3538
+                     *
3539
+                     * @var integer
3540
+                     */
3541
+                    public $i = 0;
3542
+
3543
+                    /**
3544
+                     * TGMPA instance
3545
+                     *
3546
+                     * @since 2.5.0
3547
+                     *
3548
+                     * @var object
3549
+                     */
3550
+                    protected $tgmpa;
3551
+
3552
+                    /**
3553
+                     * Constructor. Parses default args with new ones and extracts them for use.
3554
+                     *
3555
+                     * @since 2.2.0
3556
+                     *
3557
+                     * @param array $args Arguments to pass for use within the class.
3558
+                     */
3559
+                    public function __construct( $args = array() ) {
3560
+                        // Get TGMPA class instance.
3561
+                        $this->tgmpa = call_user_func( array( get_class( $GLOBALS['tgmpa'] ), 'get_instance' ) );
3562
+
3563
+                        // Parse default and new args.
3564
+                        $defaults = array(
3565
+                            'url'          => '',
3566
+                            'nonce'        => '',
3567
+                            'names'        => array(),
3568
+                            'install_type' => 'install',
3569
+                        );
3570
+                        $args     = wp_parse_args( $args, $defaults );
3571
+
3572
+                        // Set plugin names to $this->plugin_names property.
3573
+                        $this->plugin_names = $args['names'];
3574
+
3575
+                        // Extract the new args.
3576
+                        parent::__construct( $args );
3577
+                    }
3578
+
3579
+                    /**
3580
+                     * Sets install skin strings for each individual plugin.
3581
+                     *
3582
+                     * Checks to see if the automatic activation flag is set and uses the
3583
+                     * the proper strings accordingly.
3584
+                     *
3585
+                     * @since 2.2.0
3586
+                     */
3587
+                    public function add_strings() {
3588
+                        if ( 'update' === $this->options['install_type'] ) {
3589
+                            parent::add_strings();
3590
+                            /* translators: 1: plugin name, 2: action number 3: total number of actions. */
3591
+                            $this->upgrader->strings['skin_before_update_header'] = __( 'Updating Plugin %1$s (%2$d/%3$d)', 'tgmpa' );
3592
+                        } else {
3593
+                            /* translators: 1: plugin name, 2: error message. */
3594
+                            $this->upgrader->strings['skin_update_failed_error'] = __( 'An error occurred while installing %1$s: <strong>%2$s</strong>.', 'tgmpa' );
3595
+                            /* translators: 1: plugin name. */
3596
+                            $this->upgrader->strings['skin_update_failed'] = __( 'The installation of %1$s failed.', 'tgmpa' );
3597
+
3598
+                            if ( $this->tgmpa->is_automatic ) {
3599
+                                // Automatic activation strings.
3600
+                                $this->upgrader->strings['skin_upgrade_start'] = __( 'The installation and activation process is starting. This process may take a while on some hosts, so please be patient.', 'tgmpa' );
3601
+                                /* translators: 1: plugin name. */
3602
+                                $this->upgrader->strings['skin_update_successful'] = __( '%1$s installed and activated successfully.', 'tgmpa' ) . ' <a href="#" class="hide-if-no-js" onclick="%2$s"><span>' . esc_html__( 'Show Details', 'tgmpa' ) . '</span><span class="hidden">' . esc_html__( 'Hide Details', 'tgmpa' ) . '</span>.</a>';
3603
+                                $this->upgrader->strings['skin_upgrade_end']       = __( 'All installations and activations have been completed.', 'tgmpa' );
3604
+                                /* translators: 1: plugin name, 2: action number 3: total number of actions. */
3605
+                                $this->upgrader->strings['skin_before_update_header'] = __( 'Installing and Activating Plugin %1$s (%2$d/%3$d)', 'tgmpa' );
3606
+                            } else {
3607
+                                // Default installation strings.
3608
+                                $this->upgrader->strings['skin_upgrade_start'] = __( 'The installation process is starting. This process may take a while on some hosts, so please be patient.', 'tgmpa' );
3609
+                                /* translators: 1: plugin name. */
3610
+                                $this->upgrader->strings['skin_update_successful'] = esc_html__( '%1$s installed successfully.', 'tgmpa' ) . ' <a href="#" class="hide-if-no-js" onclick="%2$s"><span>' . esc_html__( 'Show Details', 'tgmpa' ) . '</span><span class="hidden">' . esc_html__( 'Hide Details', 'tgmpa' ) . '</span>.</a>';
3611
+                                $this->upgrader->strings['skin_upgrade_end']       = __( 'All installations have been completed.', 'tgmpa' );
3612
+                                /* translators: 1: plugin name, 2: action number 3: total number of actions. */
3613
+                                $this->upgrader->strings['skin_before_update_header'] = __( 'Installing Plugin %1$s (%2$d/%3$d)', 'tgmpa' );
3614
+                            }
3615
+                        }
3616
+                    }
3617
+
3618
+                    /**
3619
+                     * Outputs the header strings and necessary JS before each plugin installation.
3620
+                     *
3621
+                     * @since 2.2.0
3622
+                     *
3623
+                     * @param string $title Unused in this implementation.
3624
+                     */
3625
+                    public function before( $title = '' ) {
3626
+                        if ( empty( $title ) ) {
3627
+                            $title = esc_html( $this->plugin_names[ $this->i ] );
3628
+                        }
3629
+                        parent::before( $title );
3630
+                    }
3631
+
3632
+                    /**
3633
+                     * Outputs the footer strings and necessary JS after each plugin installation.
3634
+                     *
3635
+                     * Checks for any errors and outputs them if they exist, else output
3636
+                     * success strings.
3637
+                     *
3638
+                     * @since 2.2.0
3639
+                     *
3640
+                     * @param string $title Unused in this implementation.
3641
+                     */
3642
+                    public function after( $title = '' ) {
3643
+                        if ( empty( $title ) ) {
3644
+                            $title = esc_html( $this->plugin_names[ $this->i ] );
3645
+                        }
3646
+                        parent::after( $title );
3647
+
3648
+                        $this->i++;
3649
+                    }
3650
+
3651
+                    /**
3652
+                     * Outputs links after bulk plugin installation is complete.
3653
+                     *
3654
+                     * @since 2.2.0
3655
+                     */
3656
+                    public function bulk_footer() {
3657
+                        // Serve up the string to say installations (and possibly activations) are complete.
3658
+                        parent::bulk_footer();
3659
+
3660
+                        // Flush plugins cache so we can make sure that the installed plugins list is always up to date.
3661
+                        wp_clean_plugins_cache();
3662
+
3663
+                        $this->tgmpa->show_tgmpa_version();
3664
+
3665
+                        // Display message based on if all plugins are now active or not.
3666
+                        $update_actions = array();
3667
+
3668
+                        if ( $this->tgmpa->is_tgmpa_complete() ) {
3669
+                            // All plugins are active, so we display the complete string and hide the menu to protect users.
3670
+                            echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>';
3671
+                            $update_actions['dashboard'] = sprintf(
3672
+                                esc_html( $this->tgmpa->strings['complete'] ),
3673
+                                '<a href="' . esc_url( self_admin_url() ) . '">' . esc_html__( 'Return to the Dashboard', 'tgmpa' ) . '</a>'
3674
+                            );
3675
+                        } else {
3676
+                            $update_actions['tgmpa_page'] = '<a href="' . esc_url( $this->tgmpa->get_tgmpa_url() ) . '" target="_parent">' . esc_html( $this->tgmpa->strings['return'] ) . '</a>';
3677
+                        }
3678
+
3679
+                        /**
3680
+                         * Filter the list of action links available following bulk plugin installs/updates.
3681
+                         *
3682
+                         * @since 2.5.0
3683
+                         *
3684
+                         * @param array $update_actions Array of plugin action links.
3685
+                         * @param array $plugin_info    Array of information for the last-handled plugin.
3686
+                         */
3687
+                        $update_actions = apply_filters( 'tgmpa_update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info );
3688
+
3689
+                        if ( ! empty( $update_actions ) ) {
3690
+                            $this->feedback( implode( ' | ', (array) $update_actions ) );
3691
+                        }
3692
+                    }
3693
+
3694
+                    /* *********** DEPRECATED METHODS *********** */
3695
+
3696
+                    /**
3697
+                     * Flush header output buffer.
3698
+                     *
3699
+                     * @since      2.2.0
3700
+                     * @deprecated 2.5.0 use {@see Bulk_Upgrader_Skin::flush_output()} instead
3701
+                     * @see        Bulk_Upgrader_Skin::flush_output()
3702
+                     */
3703
+                    public function before_flush_output() {
3704
+                        _deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'Bulk_Upgrader_Skin::flush_output()' );
3705
+                        $this->flush_output();
3706
+                    }
3707
+
3708
+                    /**
3709
+                     * Flush footer output buffer and iterate $this->i to make sure the
3710
+                     * installation strings reference the correct plugin.
3711
+                     *
3712
+                     * @since      2.2.0
3713
+                     * @deprecated 2.5.0 use {@see Bulk_Upgrader_Skin::flush_output()} instead
3714
+                     * @see        Bulk_Upgrader_Skin::flush_output()
3715
+                     */
3716
+                    public function after_flush_output() {
3717
+                        _deprecated_function( __FUNCTION__, 'TGMPA 2.5.0', 'Bulk_Upgrader_Skin::flush_output()' );
3718
+                        $this->flush_output();
3719
+                        $this->i++;
3720
+                    }
3721
+                }
3722
+            }
3723
+        }
3724
+    }
3725 3725
 }
3726 3726
 
3727 3727
 if ( ! class_exists( 'TGMPA_Utils' ) ) {
3728 3728
 
3729
-	/**
3730
-	 * Generic utilities for TGMPA.
3731
-	 *
3732
-	 * All methods are static, poor-dev name-spacing class wrapper.
3733
-	 *
3734
-	 * Class was called TGM_Utils in 2.5.0 but renamed TGMPA_Utils in 2.5.1 as this was conflicting with Soliloquy.
3735
-	 *
3736
-	 * @since 2.5.0
3737
-	 *
3738
-	 * @package TGM-Plugin-Activation
3739
-	 * @author  Juliette Reinders Folmer
3740
-	 */
3741
-	class TGMPA_Utils {
3742
-		/**
3743
-		 * Whether the PHP filter extension is enabled.
3744
-		 *
3745
-		 * @see http://php.net/book.filter
3746
-		 *
3747
-		 * @since 2.5.0
3748
-		 *
3749
-		 * @static
3750
-		 *
3751
-		 * @var bool $has_filters True is the extension is enabled.
3752
-		 */
3753
-		public static $has_filters;
3754
-
3755
-		/**
3756
-		 * Wrap an arbitrary string in <em> tags. Meant to be used in combination with array_map().
3757
-		 *
3758
-		 * @since 2.5.0
3759
-		 *
3760
-		 * @static
3761
-		 *
3762
-		 * @param string $string Text to be wrapped.
3763
-		 * @return string
3764
-		 */
3765
-		public static function wrap_in_em( $string ) {
3766
-			return '<em>' . wp_kses_post( $string ) . '</em>';
3767
-		}
3768
-
3769
-		/**
3770
-		 * Wrap an arbitrary string in <strong> tags. Meant to be used in combination with array_map().
3771
-		 *
3772
-		 * @since 2.5.0
3773
-		 *
3774
-		 * @static
3775
-		 *
3776
-		 * @param string $string Text to be wrapped.
3777
-		 * @return string
3778
-		 */
3779
-		public static function wrap_in_strong( $string ) {
3780
-			return '<strong>' . wp_kses_post( $string ) . '</strong>';
3781
-		}
3782
-
3783
-		/**
3784
-		 * Helper function: Validate a value as boolean
3785
-		 *
3786
-		 * @since 2.5.0
3787
-		 *
3788
-		 * @static
3789
-		 *
3790
-		 * @param mixed $value Arbitrary value.
3791
-		 * @return bool
3792
-		 */
3793
-		public static function validate_bool( $value ) {
3794
-			if ( ! isset( self::$has_filters ) ) {
3795
-				self::$has_filters = extension_loaded( 'filter' );
3796
-			}
3797
-
3798
-			if ( self::$has_filters ) {
3799
-				return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
3800
-			} else {
3801
-				return self::emulate_filter_bool( $value );
3802
-			}
3803
-		}
3804
-
3805
-		/**
3806
-		 * Helper function: Cast a value to bool
3807
-		 *
3808
-		 * @since 2.5.0
3809
-		 *
3810
-		 * @static
3811
-		 *
3812
-		 * @param mixed $value Value to cast.
3813
-		 * @return bool
3814
-		 */
3815
-		protected static function emulate_filter_bool( $value ) {
3816
-			// @codingStandardsIgnoreStart
3817
-			static $true  = array(
3818
-				'1',
3819
-				'true', 'True', 'TRUE',
3820
-				'y', 'Y',
3821
-				'yes', 'Yes', 'YES',
3822
-				'on', 'On', 'ON',
3823
-			);
3824
-			static $false = array(
3825
-				'0',
3826
-				'false', 'False', 'FALSE',
3827
-				'n', 'N',
3828
-				'no', 'No', 'NO',
3829
-				'off', 'Off', 'OFF',
3830
-			);
3831
-			// @codingStandardsIgnoreEnd
3832
-
3833
-			if ( is_bool( $value ) ) {
3834
-				return $value;
3835
-			} elseif ( is_int( $value ) && ( 0 === $value || 1 === $value ) ) {
3836
-				return (bool) $value;
3837
-			} elseif ( ( is_float( $value ) && ! is_nan( $value ) ) && ( (float) 0 === $value || (float) 1 === $value ) ) {
3838
-				return (bool) $value;
3839
-			} elseif ( is_string( $value ) ) {
3840
-				$value = trim( $value );
3841
-				if ( in_array( $value, $true, true ) ) {
3842
-					return true;
3843
-				} elseif ( in_array( $value, $false, true ) ) {
3844
-					return false;
3845
-				} else {
3846
-					return false;
3847
-				}
3848
-			}
3849
-
3850
-			return false;
3851
-		}
3852
-	} // End of class TGMPA_Utils
3729
+    /**
3730
+     * Generic utilities for TGMPA.
3731
+     *
3732
+     * All methods are static, poor-dev name-spacing class wrapper.
3733
+     *
3734
+     * Class was called TGM_Utils in 2.5.0 but renamed TGMPA_Utils in 2.5.1 as this was conflicting with Soliloquy.
3735
+     *
3736
+     * @since 2.5.0
3737
+     *
3738
+     * @package TGM-Plugin-Activation
3739
+     * @author  Juliette Reinders Folmer
3740
+     */
3741
+    class TGMPA_Utils {
3742
+        /**
3743
+         * Whether the PHP filter extension is enabled.
3744
+         *
3745
+         * @see http://php.net/book.filter
3746
+         *
3747
+         * @since 2.5.0
3748
+         *
3749
+         * @static
3750
+         *
3751
+         * @var bool $has_filters True is the extension is enabled.
3752
+         */
3753
+        public static $has_filters;
3754
+
3755
+        /**
3756
+         * Wrap an arbitrary string in <em> tags. Meant to be used in combination with array_map().
3757
+         *
3758
+         * @since 2.5.0
3759
+         *
3760
+         * @static
3761
+         *
3762
+         * @param string $string Text to be wrapped.
3763
+         * @return string
3764
+         */
3765
+        public static function wrap_in_em( $string ) {
3766
+            return '<em>' . wp_kses_post( $string ) . '</em>';
3767
+        }
3768
+
3769
+        /**
3770
+         * Wrap an arbitrary string in <strong> tags. Meant to be used in combination with array_map().
3771
+         *
3772
+         * @since 2.5.0
3773
+         *
3774
+         * @static
3775
+         *
3776
+         * @param string $string Text to be wrapped.
3777
+         * @return string
3778
+         */
3779
+        public static function wrap_in_strong( $string ) {
3780
+            return '<strong>' . wp_kses_post( $string ) . '</strong>';
3781
+        }
3782
+
3783
+        /**
3784
+         * Helper function: Validate a value as boolean
3785
+         *
3786
+         * @since 2.5.0
3787
+         *
3788
+         * @static
3789
+         *
3790
+         * @param mixed $value Arbitrary value.
3791
+         * @return bool
3792
+         */
3793
+        public static function validate_bool( $value ) {
3794
+            if ( ! isset( self::$has_filters ) ) {
3795
+                self::$has_filters = extension_loaded( 'filter' );
3796
+            }
3797
+
3798
+            if ( self::$has_filters ) {
3799
+                return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
3800
+            } else {
3801
+                return self::emulate_filter_bool( $value );
3802
+            }
3803
+        }
3804
+
3805
+        /**
3806
+         * Helper function: Cast a value to bool
3807
+         *
3808
+         * @since 2.5.0
3809
+         *
3810
+         * @static
3811
+         *
3812
+         * @param mixed $value Value to cast.
3813
+         * @return bool
3814
+         */
3815
+        protected static function emulate_filter_bool( $value ) {
3816
+            // @codingStandardsIgnoreStart
3817
+            static $true  = array(
3818
+                '1',
3819
+                'true', 'True', 'TRUE',
3820
+                'y', 'Y',
3821
+                'yes', 'Yes', 'YES',
3822
+                'on', 'On', 'ON',
3823
+            );
3824
+            static $false = array(
3825
+                '0',
3826
+                'false', 'False', 'FALSE',
3827
+                'n', 'N',
3828
+                'no', 'No', 'NO',
3829
+                'off', 'Off', 'OFF',
3830
+            );
3831
+            // @codingStandardsIgnoreEnd
3832
+
3833
+            if ( is_bool( $value ) ) {
3834
+                return $value;
3835
+            } elseif ( is_int( $value ) && ( 0 === $value || 1 === $value ) ) {
3836
+                return (bool) $value;
3837
+            } elseif ( ( is_float( $value ) && ! is_nan( $value ) ) && ( (float) 0 === $value || (float) 1 === $value ) ) {
3838
+                return (bool) $value;
3839
+            } elseif ( is_string( $value ) ) {
3840
+                $value = trim( $value );
3841
+                if ( in_array( $value, $true, true ) ) {
3842
+                    return true;
3843
+                } elseif ( in_array( $value, $false, true ) ) {
3844
+                    return false;
3845
+                } else {
3846
+                    return false;
3847
+                }
3848
+            }
3849
+
3850
+            return false;
3851
+        }
3852
+    } // End of class TGMPA_Utils
3853 3853
 } // End of class_exists wrapper
Please login to merge, or discard this patch.