wp/wp-admin/includes/class-plugin-installer-skin.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    16  * @see WP_Upgrader_Skin
    16  * @see WP_Upgrader_Skin
    17  */
    17  */
    18 class Plugin_Installer_Skin extends WP_Upgrader_Skin {
    18 class Plugin_Installer_Skin extends WP_Upgrader_Skin {
    19 	public $api;
    19 	public $api;
    20 	public $type;
    20 	public $type;
       
    21 	public $url;
       
    22 	public $overwrite;
       
    23 
       
    24 	private $is_downgrading = false;
    21 
    25 
    22 	/**
    26 	/**
    23 	 * @param array $args
    27 	 * @param array $args
    24 	 */
    28 	 */
    25 	public function __construct( $args = array() ) {
    29 	public function __construct( $args = array() ) {
    26 		$defaults = array(
    30 		$defaults = array(
    27 			'type'   => 'web',
    31 			'type'      => 'web',
    28 			'url'    => '',
    32 			'url'       => '',
    29 			'plugin' => '',
    33 			'plugin'    => '',
    30 			'nonce'  => '',
    34 			'nonce'     => '',
    31 			'title'  => '',
    35 			'title'     => '',
       
    36 			'overwrite' => '',
    32 		);
    37 		);
    33 		$args     = wp_parse_args( $args, $defaults );
    38 		$args     = wp_parse_args( $args, $defaults );
    34 
    39 
    35 		$this->type = $args['type'];
    40 		$this->type      = $args['type'];
    36 		$this->api  = isset( $args['api'] ) ? $args['api'] : array();
    41 		$this->url       = $args['url'];
       
    42 		$this->api       = isset( $args['api'] ) ? $args['api'] : array();
       
    43 		$this->overwrite = $args['overwrite'];
    37 
    44 
    38 		parent::__construct( $args );
    45 		parent::__construct( $args );
    39 	}
    46 	}
    40 
    47 
    41 	/**
    48 	/**
       
    49 	 * Action to perform before installing a plugin.
       
    50 	 *
       
    51 	 * @since 2.8.0
    42 	 */
    52 	 */
    43 	public function before() {
    53 	public function before() {
    44 		if ( ! empty( $this->api ) ) {
    54 		if ( ! empty( $this->api ) ) {
    45 			/* translators: 1: name of API, 2: version of API */
    55 			$this->upgrader->strings['process_success'] = sprintf(
    46 			$this->upgrader->strings['process_success'] = sprintf( __( 'Successfully installed the plugin <strong>%1$s %2$s</strong>.' ), $this->api->name, $this->api->version );
    56 				$this->upgrader->strings['process_success_specific'],
    47 		}
    57 				$this->api->name,
    48 	}
    58 				$this->api->version
    49 
    59 			);
    50 	/**
    60 		}
       
    61 	}
       
    62 
       
    63 	/**
       
    64 	 * Hides the `process_failed` error when updating a plugin by uploading a zip file.
       
    65 	 *
       
    66 	 * @since 5.5.0
       
    67 	 *
       
    68 	 * @param WP_Error $wp_error WP_Error.
       
    69 	 * @return bool
       
    70 	 */
       
    71 	public function hide_process_failed( $wp_error ) {
       
    72 		if (
       
    73 			'upload' === $this->type &&
       
    74 			'' === $this->overwrite &&
       
    75 			$wp_error->get_error_code() === 'folder_exists'
       
    76 		) {
       
    77 			return true;
       
    78 		}
       
    79 
       
    80 		return false;
       
    81 	}
       
    82 
       
    83 	/**
       
    84 	 * Action to perform following a plugin install.
       
    85 	 *
       
    86 	 * @since 2.8.0
    51 	 */
    87 	 */
    52 	public function after() {
    88 	public function after() {
       
    89 		// Check if the plugin can be overwritten and output the HTML.
       
    90 		if ( $this->do_overwrite() ) {
       
    91 			return;
       
    92 		}
       
    93 
    53 		$plugin_file = $this->upgrader->plugin_info();
    94 		$plugin_file = $this->upgrader->plugin_info();
    54 
    95 
    55 		$install_actions = array();
    96 		$install_actions = array();
    56 
    97 
    57 		$from = isset( $_GET['from'] ) ? wp_unslash( $_GET['from'] ) : 'plugins';
    98 		$from = isset( $_GET['from'] ) ? wp_unslash( $_GET['from'] ) : 'plugins';
    58 
    99 
    59 		if ( 'import' == $from ) {
   100 		if ( 'import' === $from ) {
    60 			$install_actions['activate_plugin'] = '<a class="button button-primary" href="' . wp_nonce_url( 'plugins.php?action=activate&amp;from=import&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin &amp; Run Importer' ) . '</a>';
   101 			$install_actions['activate_plugin'] = sprintf(
    61 		} elseif ( 'press-this' == $from ) {
   102 				'<a class="button button-primary" href="%s" target="_parent">%s</a>',
    62 			$install_actions['activate_plugin'] = '<a class="button button-primary" href="' . wp_nonce_url( 'plugins.php?action=activate&amp;from=press-this&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin &amp; Return to Press This' ) . '</a>';
   103 				wp_nonce_url( 'plugins.php?action=activate&amp;from=import&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ),
       
   104 				__( 'Activate Plugin &amp; Run Importer' )
       
   105 			);
       
   106 		} elseif ( 'press-this' === $from ) {
       
   107 			$install_actions['activate_plugin'] = sprintf(
       
   108 				'<a class="button button-primary" href="%s" target="_parent">%s</a>',
       
   109 				wp_nonce_url( 'plugins.php?action=activate&amp;from=press-this&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ),
       
   110 				__( 'Activate Plugin &amp; Return to Press This' )
       
   111 			);
    63 		} else {
   112 		} else {
    64 			$install_actions['activate_plugin'] = '<a class="button button-primary" href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin' ) . '</a>';
   113 			$install_actions['activate_plugin'] = sprintf(
       
   114 				'<a class="button button-primary" href="%s" target="_parent">%s</a>',
       
   115 				wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ),
       
   116 				__( 'Activate Plugin' )
       
   117 			);
    65 		}
   118 		}
    66 
   119 
    67 		if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
   120 		if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
    68 			$install_actions['network_activate'] = '<a class="button button-primary" href="' . wp_nonce_url( 'plugins.php?action=activate&amp;networkwide=1&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Network Activate' ) . '</a>';
   121 			$install_actions['network_activate'] = sprintf(
       
   122 				'<a class="button button-primary" href="%s" target="_parent">%s</a>',
       
   123 				wp_nonce_url( 'plugins.php?action=activate&amp;networkwide=1&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ),
       
   124 				__( 'Network Activate' )
       
   125 			);
    69 			unset( $install_actions['activate_plugin'] );
   126 			unset( $install_actions['activate_plugin'] );
    70 		}
   127 		}
    71 
   128 
    72 		if ( 'import' == $from ) {
   129 		if ( 'import' === $from ) {
    73 			$install_actions['importers_page'] = '<a href="' . admin_url( 'import.php' ) . '" target="_parent">' . __( 'Return to Importers' ) . '</a>';
   130 			$install_actions['importers_page'] = sprintf(
    74 		} elseif ( $this->type == 'web' ) {
   131 				'<a href="%s" target="_parent">%s</a>',
    75 			$install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugin-install.php' ) . '" target="_parent">' . __( 'Return to Plugin Installer' ) . '</a>';
   132 				admin_url( 'import.php' ),
    76 		} elseif ( 'upload' == $this->type && 'plugins' == $from ) {
   133 				__( 'Return to Importers' )
    77 			$install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugin-install.php' ) . '">' . __( 'Return to Plugin Installer' ) . '</a>';
   134 			);
       
   135 		} elseif ( 'web' === $this->type ) {
       
   136 			$install_actions['plugins_page'] = sprintf(
       
   137 				'<a href="%s" target="_parent">%s</a>',
       
   138 				self_admin_url( 'plugin-install.php' ),
       
   139 				__( 'Return to Plugin Installer' )
       
   140 			);
       
   141 		} elseif ( 'upload' === $this->type && 'plugins' === $from ) {
       
   142 			$install_actions['plugins_page'] = sprintf(
       
   143 				'<a href="%s">%s</a>',
       
   144 				self_admin_url( 'plugin-install.php' ),
       
   145 				__( 'Return to Plugin Installer' )
       
   146 			);
    78 		} else {
   147 		} else {
    79 			$install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>';
   148 			$install_actions['plugins_page'] = sprintf(
       
   149 				'<a href="%s" target="_parent">%s</a>',
       
   150 				self_admin_url( 'plugins.php' ),
       
   151 				__( 'Return to Plugins page' )
       
   152 			);
    80 		}
   153 		}
    81 
   154 
    82 		if ( ! $this->result || is_wp_error( $this->result ) ) {
   155 		if ( ! $this->result || is_wp_error( $this->result ) ) {
    83 			unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
   156 			unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
    84 		} elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) ) {
   157 		} elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) || is_plugin_active( $plugin_file ) ) {
    85 			unset( $install_actions['activate_plugin'] );
   158 			unset( $install_actions['activate_plugin'] );
    86 		}
   159 		}
    87 
   160 
    88 		/**
   161 		/**
    89 		 * Filters the list of action links available following a single plugin installation.
   162 		 * Filters the list of action links available following a single plugin installation.
   100 
   173 
   101 		if ( ! empty( $install_actions ) ) {
   174 		if ( ! empty( $install_actions ) ) {
   102 			$this->feedback( implode( ' ', (array) $install_actions ) );
   175 			$this->feedback( implode( ' ', (array) $install_actions ) );
   103 		}
   176 		}
   104 	}
   177 	}
       
   178 
       
   179 	/**
       
   180 	 * Check if the plugin can be overwritten and output the HTML for overwriting a plugin on upload.
       
   181 	 *
       
   182 	 * @since 5.5.0
       
   183 	 *
       
   184 	 * @return bool Whether the plugin can be overwritten and HTML was outputted.
       
   185 	 */
       
   186 	private function do_overwrite() {
       
   187 		if ( 'upload' !== $this->type || ! is_wp_error( $this->result ) || 'folder_exists' !== $this->result->get_error_code() ) {
       
   188 			return false;
       
   189 		}
       
   190 
       
   191 		$folder = $this->result->get_error_data( 'folder_exists' );
       
   192 		$folder = ltrim( substr( $folder, strlen( WP_PLUGIN_DIR ) ), '/' );
       
   193 
       
   194 		$current_plugin_data = false;
       
   195 		$all_plugins         = get_plugins();
       
   196 
       
   197 		foreach ( $all_plugins as $plugin => $plugin_data ) {
       
   198 			if ( strrpos( $plugin, $folder ) !== 0 ) {
       
   199 				continue;
       
   200 			}
       
   201 
       
   202 			$current_plugin_data = $plugin_data;
       
   203 		}
       
   204 
       
   205 		$new_plugin_data = $this->upgrader->new_plugin_data;
       
   206 
       
   207 		if ( ! $current_plugin_data || ! $new_plugin_data ) {
       
   208 			return false;
       
   209 		}
       
   210 
       
   211 		echo '<h2 class="update-from-upload-heading">' . esc_html( __( 'This plugin is already installed.' ) ) . '</h2>';
       
   212 
       
   213 		$this->is_downgrading = version_compare( $current_plugin_data['Version'], $new_plugin_data['Version'], '>' );
       
   214 
       
   215 		$rows = array(
       
   216 			'Name'        => __( 'Plugin name' ),
       
   217 			'Version'     => __( 'Version' ),
       
   218 			'Author'      => __( 'Author' ),
       
   219 			'RequiresWP'  => __( 'Required WordPress version' ),
       
   220 			'RequiresPHP' => __( 'Required PHP version' ),
       
   221 		);
       
   222 
       
   223 		$table  = '<table class="update-from-upload-comparison"><tbody>';
       
   224 		$table .= '<tr><th></th><th>' . esc_html( __( 'Current' ) ) . '</th>';
       
   225 		$table .= '<th>' . esc_html( __( 'Uploaded' ) ) . '</th></tr>';
       
   226 
       
   227 		$is_same_plugin = true; // Let's consider only these rows.
       
   228 
       
   229 		foreach ( $rows as $field => $label ) {
       
   230 			$old_value = ! empty( $current_plugin_data[ $field ] ) ? (string) $current_plugin_data[ $field ] : '-';
       
   231 			$new_value = ! empty( $new_plugin_data[ $field ] ) ? (string) $new_plugin_data[ $field ] : '-';
       
   232 
       
   233 			$is_same_plugin = $is_same_plugin && ( $old_value === $new_value );
       
   234 
       
   235 			$diff_field   = ( 'Version' !== $field && $new_value !== $old_value );
       
   236 			$diff_version = ( 'Version' === $field && $this->is_downgrading );
       
   237 
       
   238 			$table .= '<tr><td class="name-label">' . $label . '</td><td>' . wp_strip_all_tags( $old_value ) . '</td>';
       
   239 			$table .= ( $diff_field || $diff_version ) ? '<td class="warning">' : '<td>';
       
   240 			$table .= wp_strip_all_tags( $new_value ) . '</td></tr>';
       
   241 		}
       
   242 
       
   243 		$table .= '</tbody></table>';
       
   244 
       
   245 		/**
       
   246 		 * Filters the compare table output for overwriting a plugin package on upload.
       
   247 		 *
       
   248 		 * @since 5.5.0
       
   249 		 *
       
   250 		 * @param string $table               The output table with Name, Version, Author, RequiresWP, and RequiresPHP info.
       
   251 		 * @param array  $current_plugin_data Array with current plugin data.
       
   252 		 * @param array  $new_plugin_data     Array with uploaded plugin data.
       
   253 		 */
       
   254 		echo apply_filters( 'install_plugin_overwrite_comparison', $table, $current_plugin_data, $new_plugin_data );
       
   255 
       
   256 		$install_actions = array();
       
   257 		$can_update      = true;
       
   258 
       
   259 		$blocked_message  = '<p>' . esc_html( __( 'The plugin cannot be updated due to the following:' ) ) . '</p>';
       
   260 		$blocked_message .= '<ul class="ul-disc">';
       
   261 
       
   262 		$requires_php = isset( $new_plugin_data['RequiresPHP'] ) ? $new_plugin_data['RequiresPHP'] : null;
       
   263 		$requires_wp  = isset( $new_plugin_data['RequiresWP'] ) ? $new_plugin_data['RequiresWP'] : null;
       
   264 
       
   265 		if ( ! is_php_version_compatible( $requires_php ) ) {
       
   266 			$error = sprintf(
       
   267 				/* translators: 1: Current PHP version, 2: Version required by the uploaded plugin. */
       
   268 				__( 'The PHP version on your server is %1$s, however the uploaded plugin requires %2$s.' ),
       
   269 				phpversion(),
       
   270 				$requires_php
       
   271 			);
       
   272 
       
   273 			$blocked_message .= '<li>' . esc_html( $error ) . '</li>';
       
   274 			$can_update       = false;
       
   275 		}
       
   276 
       
   277 		if ( ! is_wp_version_compatible( $requires_wp ) ) {
       
   278 			$error = sprintf(
       
   279 				/* translators: 1: Current WordPress version, 2: Version required by the uploaded plugin. */
       
   280 				__( 'Your WordPress version is %1$s, however the uploaded plugin requires %2$s.' ),
       
   281 				get_bloginfo( 'version' ),
       
   282 				$requires_wp
       
   283 			);
       
   284 
       
   285 			$blocked_message .= '<li>' . esc_html( $error ) . '</li>';
       
   286 			$can_update       = false;
       
   287 		}
       
   288 
       
   289 		$blocked_message .= '</ul>';
       
   290 
       
   291 		if ( $can_update ) {
       
   292 			if ( $this->is_downgrading ) {
       
   293 				$warning = sprintf(
       
   294 					/* translators: %s: Documentation URL. */
       
   295 					__( 'You are uploading an older version of a current plugin. You can continue to install the older version, but be sure to <a href="%s">back up your database and files</a> first.' ),
       
   296 					__( 'https://wordpress.org/support/article/wordpress-backups/' )
       
   297 				);
       
   298 			} else {
       
   299 				$warning = sprintf(
       
   300 					/* translators: %s: Documentation URL. */
       
   301 					__( 'You are updating a plugin. Be sure to <a href="%s">back up your database and files</a> first.' ),
       
   302 					__( 'https://wordpress.org/support/article/wordpress-backups/' )
       
   303 				);
       
   304 			}
       
   305 
       
   306 			echo '<p class="update-from-upload-notice">' . $warning . '</p>';
       
   307 
       
   308 			$overwrite = $this->is_downgrading ? 'downgrade-plugin' : 'update-plugin';
       
   309 
       
   310 			$install_actions['overwrite_plugin'] = sprintf(
       
   311 				'<a class="button button-primary update-from-upload-overwrite" href="%s" target="_parent">%s</a>',
       
   312 				wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'plugin-upload' ),
       
   313 				__( 'Replace current with uploaded' )
       
   314 			);
       
   315 		} else {
       
   316 			echo $blocked_message;
       
   317 		}
       
   318 
       
   319 		$cancel_url = add_query_arg( 'action', 'upload-plugin-cancel-overwrite', $this->url );
       
   320 
       
   321 		$install_actions['plugins_page'] = sprintf(
       
   322 			'<a class="button" href="%s">%s</a>',
       
   323 			wp_nonce_url( $cancel_url, 'plugin-upload-cancel-overwrite' ),
       
   324 			__( 'Cancel and go back' )
       
   325 		);
       
   326 
       
   327 		/**
       
   328 		 * Filters the list of action links available following a single plugin installation
       
   329 		 * failure when overwriting is allowed.
       
   330 		 *
       
   331 		 * @since 5.5.0
       
   332 		 *
       
   333 		 * @param string[] $install_actions Array of plugin action links.
       
   334 		 * @param object   $api             Object containing WordPress.org API plugin data.
       
   335 		 * @param array    $new_plugin_data Array with uploaded plugin data.
       
   336 		 */
       
   337 		$install_actions = apply_filters( 'install_plugin_overwrite_actions', $install_actions, $this->api, $new_plugin_data );
       
   338 
       
   339 		if ( ! empty( $install_actions ) ) {
       
   340 			printf(
       
   341 				'<p class="update-from-upload-expired hidden">%s</p>',
       
   342 				__( 'The uploaded file has expired. Please go back and upload it again.' )
       
   343 			);
       
   344 			echo '<p class="update-from-upload-actions">' . implode( ' ', (array) $install_actions ) . '</p>';
       
   345 		}
       
   346 
       
   347 		return true;
       
   348 	}
   105 }
   349 }