函数文档

delete_plugins()

💡 云策文档标注

概述

delete_plugins() 函数用于删除指定插件列表的目录和文件,是 WordPress 插件管理中的核心功能。它处理文件系统操作、触发相关 Hook,并返回操作状态。

关键要点

  • 参数 $plugins 为必填的插件路径数组,相对于 plugins 目录;$deprecated 参数已弃用。
  • 返回值类型多样:成功返回 true,$plugins 为空返回 false,失败返回 WP_Error,需要文件系统凭证时返回 null。
  • 函数内部处理文件系统连接、插件目录定位、递归删除、语言文件清理和插件更新列表更新。
  • 触发 delete_plugin 和 deleted_plugin 两个 Hook,分别在删除尝试前后执行。
  • 依赖多个 WordPress 核心函数,如 request_filesystem_credentials、WP_Filesystem 和 wp_get_installed_translations。

代码示例

// 示例:删除指定插件
$plugins_to_delete = array('akismet/akismet.php', 'hello.php');
$result = delete_plugins($plugins_to_delete);
if (is_wp_error($result)) {
    echo '删除失败: ' . $result->get_error_message();
} elseif ($result === true) {
    echo '删除成功';
} else {
    echo '操作未完成或参数为空';
}

注意事项

  • 使用前需确保文件系统权限正确,否则可能触发凭证请求或返回错误。
  • 函数会自动处理插件卸载钩子(如果插件可卸载),并清理相关翻译文件。
  • 在批量删除或自动化脚本中使用时,应检查返回值以处理各种情况。

📄 原文内容

Removes directory and files of a plugin for a list of plugins.

Parameters

$pluginsstring[]required
List of plugin paths to delete, relative to the plugins directory.
$deprecatedstringrequired
Not used.

Return

bool|null|WP_Error True on success, false if $plugins is empty, WP_Error on failure.
null if filesystem credentials are required to proceed.

Source

function delete_plugins( $plugins, $deprecated = '' ) {
	global $wp_filesystem;

	if ( empty( $plugins ) ) {
		return false;
	}

	$checked = array();
	foreach ( $plugins as $plugin ) {
		$checked[] = 'checked[]=' . $plugin;
	}

	$url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete;=1&' . implode( '&', $checked ), 'bulk-plugins' );

	ob_start();
	$credentials = request_filesystem_credentials( $url );
	$data        = ob_get_clean();

	if ( false === $credentials ) {
		if ( ! empty( $data ) ) {
			require_once ABSPATH . 'wp-admin/admin-header.php';
			echo $data;
			require_once ABSPATH . 'wp-admin/admin-footer.php';
			exit;
		}
		return;
	}

	if ( ! WP_Filesystem( $credentials ) ) {
		ob_start();
		// Failed to connect. Error and request again.
		request_filesystem_credentials( $url, '', true );
		$data = ob_get_clean();

		if ( ! empty( $data ) ) {
			require_once ABSPATH . 'wp-admin/admin-header.php';
			echo $data;
			require_once ABSPATH . 'wp-admin/admin-footer.php';
			exit;
		}
		return;
	}

	if ( ! is_object( $wp_filesystem ) ) {
		return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
	}

	if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
		return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors );
	}

	// Get the base plugin folder.
	$plugins_dir = $wp_filesystem->wp_plugins_dir();
	if ( empty( $plugins_dir ) ) {
		return new WP_Error( 'fs_no_plugins_dir', __( 'Unable to locate WordPress plugin directory.' ) );
	}

	$plugins_dir = trailingslashit( $plugins_dir );

	$plugin_translations = wp_get_installed_translations( 'plugins' );

	$errors = array();

	foreach ( $plugins as $plugin_file ) {
		// Run Uninstall hook.
		if ( is_uninstallable_plugin( $plugin_file ) ) {
			uninstall_plugin( $plugin_file );
		}

		/**
		 * Fires immediately before a plugin deletion attempt.
		 *
		 * @since 4.4.0
		 *
		 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
		 */
		do_action( 'delete_plugin', $plugin_file );

		$this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) );

		/*
		 * If plugin is in its own directory, recursively delete the directory.
		 * Base check on if plugin includes directory separator AND that it's not the root plugin folder.
		 */
		if ( strpos( $plugin_file, '/' ) && $this_plugin_dir !== $plugins_dir ) {
			$deleted = $wp_filesystem->delete( $this_plugin_dir, true );
		} else {
			$deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file );
		}

		/**
		 * Fires immediately after a plugin deletion attempt.
		 *
		 * @since 4.4.0
		 *
		 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
		 * @param bool   $deleted     Whether the plugin deletion was successful.
		 */
		do_action( 'deleted_plugin', $plugin_file, $deleted );

		if ( ! $deleted ) {
			$errors[] = $plugin_file;
			continue;
		}

		$plugin_slug = dirname( $plugin_file );

		if ( 'hello.php' === $plugin_file ) {
			$plugin_slug = 'hello-dolly';
		}

		// Remove language files, silently.
		if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) {
			$translations = $plugin_translations[ $plugin_slug ];

			foreach ( $translations as $translation => $data ) {
				$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' );
				$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' );
				$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.l10n.php' );

				$json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' );
				if ( $json_translation_files ) {
					array_map( array( $wp_filesystem, 'delete' ), $json_translation_files );
				}
			}
		}
	}

	// Remove deleted plugins from the plugin updates list.
	$current = get_site_transient( 'update_plugins' );
	if ( $current ) {
		// Don't remove the plugins that weren't deleted.
		$deleted = array_diff( $plugins, $errors );

		foreach ( $deleted as $plugin_file ) {
			unset( $current->response[ $plugin_file ] );
		}

		set_site_transient( 'update_plugins', $current );
	}

	if ( ! empty( $errors ) ) {
		if ( 1 === count( $errors ) ) {
			/* translators: %s: Plugin filename. */
			$message = __( 'Could not fully remove the plugin %s.' );
		} else {
			/* translators: %s: Comma-separated list of plugin filenames. */
			$message = __( 'Could not fully remove the plugins %s.' );
		}

		return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
	}

	return true;
}

Hooks

do_action( ‘deleted_plugin’, string $plugin_file, bool $deleted )

Fires immediately after a plugin deletion attempt.

do_action( ‘delete_plugin’, string $plugin_file )

Fires immediately before a plugin deletion attempt.

Changelog

Version Description
2.6.0 Introduced.