delete_plugins

The timeline below displays how wordpress function delete_plugins has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 6.5

/**
 * Removes directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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;
}

WordPress Version: 6.3

/**
 * Removes directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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');
                $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;
}

WordPress Version: 6.1

/**
 * Removes directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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');
                $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;
}

WordPress Version: 5.8

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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');
                $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;
}

WordPress Version: 5.6

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
                $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;
}

WordPress Version: 5.4

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
                $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;
}

WordPress Version: 5.3

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        ob_start();
        request_filesystem_credentials($url, '', true);
        // Failed to connect, Error and request again.
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $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;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
                $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;
}

WordPress Version: 5.1

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 *
 * @param string[] $plugins    List of plugin paths to delete, relative to the plugins directory.
 * @param string   $deprecated 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.
 */
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)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        ob_start();
        request_filesystem_credentials($url, '', true);
        // Failed to connect, Error and request again.
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $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;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
                $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.
    if ($current = get_site_transient('update_plugins')) {
        // 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;
}

WordPress Version: 4.9

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
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)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        ob_start();
        request_filesystem_credentials($url, '', true);
        // Failed to connect, Error and request again.
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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 Plugin file name.
         */
        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.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $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 Plugin file name.
         * @param bool   $deleted     Whether the plugin deletion was successful.
         */
        do_action('deleted_plugin', $plugin_file, $deleted);
        if (!$deleted) {
            $errors[] = $plugin_file;
            continue;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
            }
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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;
}

WordPress Version: 4.6

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
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)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        ob_start();
        request_filesystem_credentials($url, '', true);
        // Failed to connect, Error and request again.
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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 Plugin file name.
         */
        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.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $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 Plugin file name.
         * @param bool   $deleted     Whether the plugin deletion was successful.
         */
        do_action('deleted_plugin', $plugin_file, $deleted);
        if (!$deleted) {
            $errors[] = $plugin_file;
            continue;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
            }
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 4.4

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
function delete_plugins($plugins, $deprecated = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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 Plugin file name.
         */
        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.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $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 Plugin file name.
         * @param bool   $deleted     Whether the plugin deletion was successful.
         */
        do_action('deleted_plugin', $plugin_file, $deleted);
        if (!$deleted) {
            $errors[] = $plugin_file;
            continue;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
            }
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 4.3

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @global WP_Filesystem_Base $wp_filesystem
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
function delete_plugins($plugins, $deprecated = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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);
        }
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin_file));
        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        } else {
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
        }
        if (!$deleted) {
            $errors[] = $plugin_file;
            continue;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
            }
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 4.2

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
function delete_plugins($plugins, $deprecated = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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);
        }
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin_file));
        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        } else {
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
        }
        if (!$deleted) {
            $errors[] = $plugin_file;
            continue;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
            }
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 4.1

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
function delete_plugins($plugins, $deprecated = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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);
    $translations_dir = $wp_filesystem->wp_lang_dir();
    $translations_dir = trailingslashit($translations_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);
        }
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin_file));
        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        } else {
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
        }
        if (!$deleted) {
            $errors[] = $plugin_file;
            continue;
        }
        // Remove language files, silently.
        $plugin_slug = dirname($plugin_file);
        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');
            }
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 4.0

/**
 * Remove directory and files of a plugin for a list of plugins.
 *
 * @since 2.6.0
 *
 * @param array  $plugins    List of plugins to delete.
 * @param string $deprecated Deprecated.
 * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure.
 *                            Null if filesystem credentials are required to proceed.
 */
function delete_plugins($plugins, $deprecated = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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);
    $errors = array();
    foreach ($plugins as $plugin_file) {
        // Run Uninstall hook
        if (is_uninstallable_plugin($plugin_file)) {
            uninstall_plugin($plugin_file);
        }
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin_file));
        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        } else {
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
        }
        if (!$deleted) {
            $errors[] = $plugin_file;
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 3.8

/**
 * Remove directory and files of a plugin for a single or list of plugin(s).
 *
 * If the plugins parameter list is empty, false will be returned. True when
 * completed.
 *
 * @since 2.6.0
 *
 * @param array $plugins List of plugin
 * @param string $redirect Redirect to page when complete.
 * @return mixed
 */
function delete_plugins($plugins, $redirect = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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);
    $errors = array();
    foreach ($plugins as $plugin_file) {
        // Run Uninstall hook
        if (is_uninstallable_plugin($plugin_file)) {
            uninstall_plugin($plugin_file);
        }
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin_file));
        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        } else {
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
        }
        if (!$deleted) {
            $errors[] = $plugin_file;
        }
    }
    // Remove deleted plugins from the plugin updates list.
    if ($current = get_site_transient('update_plugins')) {
        // 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)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    return true;
}

WordPress Version: 3.7

/**
 * Remove directory and files of a plugin for a single or list of plugin(s).
 *
 * If the plugins parameter list is empty, false will be returned. True when
 * completed.
 *
 * @since 2.6.0
 *
 * @param array $plugins List of plugin
 * @param string $redirect Redirect to page when complete.
 * @return mixed
 */
function delete_plugins($plugins, $redirect = '')
{
    global $wp_filesystem;
    if (empty($plugins)) {
        return false;
    }
    $checked = array();
    foreach ($plugins as $plugin) {
        $checked[] = 'checked[]=' . $plugin;
    }
    ob_start();
    $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
    if (false === $credentials = request_filesystem_credentials($url)) {
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include ABSPATH . 'wp-admin/admin-footer.php';
            exit;
        }
        return;
    }
    if (!WP_Filesystem($credentials)) {
        request_filesystem_credentials($url, '', true);
        //Failed to connect, Error and request again
        $data = ob_get_contents();
        ob_end_clean();
        if (!empty($data)) {
            include_once ABSPATH . 'wp-admin/admin-header.php';
            echo $data;
            include 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->get_error_code()) {
        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);
    $errors = array();
    foreach ($plugins as $plugin_file) {
        // Run Uninstall hook
        if (is_uninstallable_plugin($plugin_file)) {
            uninstall_plugin($plugin_file);
        }
        $this_plugin_dir = trailingslashit(dirname($plugins_dir . $plugin_file));
        // If plugin is in its own directory, recursively delete the directory.
        if (strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir) {
            //base check on if plugin includes directory separator AND that it's not the root plugin folder
            $deleted = $wp_filesystem->delete($this_plugin_dir, true);
        } else {
            $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
        }
        if (!$deleted) {
            $errors[] = $plugin_file;
        }
    }
    if (!empty($errors)) {
        return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)));
    }
    // Force refresh of plugin update information
    if ($current = get_site_transient('update_plugins')) {
        unset($current->response[$plugin_file]);
        set_site_transient('update_plugins', $current);
    }
    return true;
}