/** * Merge the downloaded extension directory with the existing directory * * @param string $source_wp_fs_dir Downloaded extension directory * @param string $destination_wp_fs_dir * * @return null|WP_Error */ private function merge_extension($source_wp_fs_dir, $destination_wp_fs_dir) { /** @var WP_Filesystem_Base $wp_filesystem */ global $wp_filesystem; $wp_error_id = 'fw_extensions_merge'; $source_files = $wp_filesystem->dirlist($source_wp_fs_dir); if ($source_files === false) { return new WP_Error($wp_error_id, sprintf(__('Cannot read directory "%s".', 'fw'), $source_wp_fs_dir)); } if (empty($source_files)) { // directory is empty, nothing to move return; } /** * Prepare destination directory * Remove everything except the extensions/ directory */ if ($wp_filesystem->exists($destination_wp_fs_dir)) { $destination_files = $wp_filesystem->dirlist($destination_wp_fs_dir); if ($destination_files === false) { return new WP_Error($wp_error_id, sprintf(__('Cannot read directory "%s".', 'fw'), $destination_wp_fs_dir)); } if (!empty($destination_files)) { // the directory contains some files, delete everything foreach ($destination_files as $file) { if ($file['name'] === 'extensions' && $file['type'] === 'd') { // do not touch the extensions/ directory continue; } if (!$wp_filesystem->delete($destination_wp_fs_dir . '/' . $file['name'], true, $file['type'])) { return new WP_Error($wp_error_id, sprintf(__('Cannot delete "%s".', 'fw'), $destination_wp_fs_dir . '/' . $file['name'])); } } unset($destination_files); } } else { if (!FW_WP_Filesystem::mkdir_recursive($destination_wp_fs_dir)) { return new WP_Error($wp_error_id, sprintf(__('Cannot create the "%s" directory.', 'fw'), $destination_wp_fs_dir)); } } $has_sub_extensions = false; foreach ($source_files as $file) { if ($file['name'] === 'extensions' && $file['type'] === 'd') { // do not touch the extensions/ directory $has_sub_extensions = true; continue; } if (!$wp_filesystem->move($source_wp_fs_dir . '/' . $file['name'], $destination_wp_fs_dir . '/' . $file['name'])) { return new WP_Error($wp_error_id, sprintf(__('Cannot move "%s" to "%s".', 'fw'), $source_wp_fs_dir . '/' . $file['name'], $destination_wp_fs_dir . '/' . $file['name'])); } } unset($source_files); if (!$has_sub_extensions) { return; } $sub_extensions = $wp_filesystem->dirlist($source_wp_fs_dir . '/extensions'); if ($sub_extensions === false) { return new WP_Error($wp_error_id, sprintf(__('Cannot read directory "%s".', 'fw'), $source_wp_fs_dir . '/extensions')); } if (empty($sub_extensions)) { // directory is empty, nothing to remove return; } foreach ($sub_extensions as $file) { if ($file['type'] !== 'd') { // wrong, only directories must exist in the extensions/ directory continue; } $merge_result = $this->merge_extension($source_wp_fs_dir . '/extensions/' . $file['name'], $destination_wp_fs_dir . '/extensions/' . $file['name']); if (is_wp_error($merge_result)) { return $merge_result; } } }
/** * Merge two extensions/ directories * @param string $source_dir WP_Filesystem dir '/a/b/c/extensions' * @param string $destination_dir WP_Filesystem dir '/a/b/d/extensions' * @return bool|WP_Error */ private function merge_extensions($source_dir, $destination_dir) { /** @var WP_Filesystem_Base $wp_filesystem */ global $wp_filesystem; $wp_error_id = 'fw_ext_update_merge_extensions'; if (!$wp_filesystem->exists($destination_dir)) { // do a simple move if destination does not exist if (!$wp_filesystem->move($source_dir, $destination_dir)) { return new WP_Error($wp_error_id, sprintf(__('Cannot move "%s" to "%s"', 'fw'), $source_dir, $destination_dir)); } return true; } $source_ext_dirs = $wp_filesystem->dirlist($source_dir, true); if ($source_ext_dirs === false) { return new WP_Error($wp_error_id, __('Cannot access directory: ', 'fw') . $source_dir); } foreach ($source_ext_dirs as $ext_dir) { if (in_array($ext_dir['name'], $this->skip_file_names)) { continue; } if ($ext_dir['type'] !== 'd') { // process only directories from the extensions/ directory continue; } $source_extension_dir = $source_dir . '/' . $ext_dir['name']; $destination_extension_dir = $destination_dir . '/' . $ext_dir['name']; $source_ext_files = $wp_filesystem->dirlist($source_extension_dir, true); if ($source_ext_files === false) { return new WP_Error($wp_error_id, __('Cannot access directory: ', 'fw') . $source_extension_dir); } if (empty($source_ext_files)) { /** * Source extension directory is empty, do nothing. * This happens when the extension is a git submodule in repository * but in zip it comes as an empty directory. */ continue; } // create if not exists if (!$wp_filesystem->exists($destination_extension_dir)) { if (!FW_WP_Filesystem::mkdir_recursive($destination_extension_dir)) { return new WP_Error($wp_error_id, __('Cannot create directory: ', 'fw') . $destination_extension_dir); } } $dest_ext_files = $wp_filesystem->dirlist($destination_extension_dir, true); if ($dest_ext_files === false) { return new WP_Error($wp_error_id, __('Cannot access directory: ', 'fw') . $destination_extension_dir); } $destination_has_extensions_dir = false; foreach ($dest_ext_files as $dest_ext_file) { if (in_array($dest_ext_file['name'], $this->skip_file_names)) { continue; } if ($dest_ext_file['name'] === 'extensions' && $dest_ext_file['type'] === 'd') { $destination_has_extensions_dir = true; continue; } $dest_ext_file_path = $destination_extension_dir . '/' . $dest_ext_file['name']; if (!$wp_filesystem->delete($dest_ext_file_path, true, $dest_ext_file['type'])) { return new WP_Error($wp_error_id, __('Cannot delete: ', 'fw') . $dest_ext_file_path); } } $source_has_extensions_dir = false; foreach ($source_ext_files as $source_ext_file) { if (in_array($source_ext_file['name'], $this->skip_file_names)) { continue; } if ($source_ext_file['name'] === 'extensions' && $source_ext_file['type'] === 'd') { $source_has_extensions_dir = true; continue; } $source_ext_file_path = $source_extension_dir . '/' . $source_ext_file['name']; $dest_ext_file_path = $destination_extension_dir . '/' . $source_ext_file['name']; if (!$wp_filesystem->move($source_ext_file_path, $dest_ext_file_path)) { return new WP_Error($wp_error_id, sprintf(__('Cannot move "%s" to "%s"', 'fw'), $source_ext_file_path, $dest_ext_file_path)); } } if ($source_has_extensions_dir) { if ($destination_has_extensions_dir) { $merge_result = $this->merge_extensions($source_extension_dir . '/extensions', $destination_extension_dir . '/extensions'); if ($merge_result !== true) { return $merge_result; } } else { if (!$wp_filesystem->move($source_extension_dir . '/extensions', $destination_extension_dir . '/extensions')) { return new WP_Error($wp_error_id, sprintf(__('Cannot move "%s" to "%s"', 'fw'), $source_extension_dir . '/extensions', $destination_extension_dir . '/extensions')); } } } } return true; }
/** * @internal */ public function _action_update_framework() { $nonce_name = '_nonce_fw_ext_update_framework'; if (!isset($_POST[$nonce_name]) || !wp_verify_nonce($_POST[$nonce_name])) { wp_die(__('Invalid nonce.', 'fw')); } if (!class_exists('_FW_Ext_Update_Framework_Upgrader_Skin')) { fw_include_file_isolated($this->get_declared_path('/includes/classes/class--fw-ext-update-framework-upgrader-skin.php')); } $skin = new _FW_Ext_Update_Framework_Upgrader_Skin(array('title' => __('Update Framework', 'fw'))); require_once ABSPATH . 'wp-admin/admin-header.php'; $skin->header(); $update = $this->get_framework_update(true); do { if ($update === false) { $skin->error(__('Failed to get framework latest version.', 'fw')); break; } elseif (is_wp_error($update)) { $skin->error($update); break; } $context = $this->context; if (!FW_WP_Filesystem::request_access($context, fw_current_url(), array($nonce_name))) { break; } $this->maintenance_mode(true); /** @var WP_Filesystem_Base $wp_filesystem */ global $wp_filesystem; $tmp_download_dir = FW_WP_Filesystem::real_path_to_filesystem_path(FW_CACHE_DIR . '/update'); // just in case it already exists, clear everything, it may contain broken/old files $wp_filesystem->rmdir($tmp_download_dir, true); if (!FW_WP_Filesystem::mkdir_recursive($tmp_download_dir)) { $skin->error(__('Cannot create directory: ' . $tmp_download_dir, 'fw')); break; } $skin->feedback(__('Downloading framework...', 'fw')); /** @var FW_Ext_Update_Service $service */ $service = $this->get_child($update['service']); $downloaded_files_dir = $service->_download_framework($update['latest_version'], $tmp_download_dir); if (!$downloaded_files_dir) { $skin->error(__('Failed to download framework.', 'fw')); break; } elseif (is_wp_error($downloaded_files_dir)) { $skin->error($downloaded_files_dir); break; } $skin->feedback(__('Installing framework...', 'fw')); $framework_dir = FW_WP_Filesystem::real_path_to_filesystem_path(FW_DIR); // remove entire framework directory $wp_filesystem->rmdir($framework_dir, true); // move downloaded directory as new framework directory $wp_filesystem->move($downloaded_files_dir, $framework_dir); $skin->feedback(__('Framework updated.', 'fw')); $wp_filesystem->delete($tmp_download_dir, true, 'd'); $skin->set_result(true); $skin->after(); } while (false); $this->maintenance_mode(false); $skin->footer(); require_once ABSPATH . 'wp-admin/admin-footer.php'; }
/** * Copy Theme Available Extensions to a tmp directory * Used before theme update * @since 2.6.0 * @return null|WP_Error */ public function theme_available_extensions_copy() { /** @var WP_Filesystem_Base $wp_filesystem */ global $wp_filesystem; if (!$wp_filesystem || is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) { return new WP_Error('fs_not_initialized', __('WP Filesystem is not initialized', 'fw')); } $wpfs_tmp_dir = FW_WP_Filesystem::real_path_to_filesystem_path($this->get_tmp_dir('/theme-ext')); if ($wp_filesystem->exists($wpfs_tmp_dir) && !$wp_filesystem->rmdir($wpfs_tmp_dir, true)) { return new WP_Error('tmp_dir_rm_fail', sprintf(__('Temporary directory cannot be removed: %s', 'fw'), $wpfs_tmp_dir)); } if (!FW_WP_Filesystem::mkdir_recursive($wpfs_tmp_dir)) { return new WP_Error('tmp_dir_rm_fail', sprintf(__('Temporary directory cannot be created: %s', 'fw'), $wpfs_tmp_dir)); } $available_extensions = $this->get_available_extensions(); $installed_extensions = $this->get_installed_extensions(true); $base_dir = fw_get_template_customizations_directory('/extensions'); foreach ($installed_extensions as $name => $ext) { if (!(isset($available_extensions[$name]) && isset($available_extensions[$name]['theme']) && $available_extensions[$name]['theme'])) { continue; } if (($rel_path = preg_replace('/^' . preg_quote($base_dir, '/') . '/', '', $ext['path'])) === $base_dir) { return new WP_Error('rel_path_failed', sprintf(__('Failed to extract relative directory from: %s', 'fw'), $ext['path'])); } if (($wpfs_path = FW_WP_Filesystem::real_path_to_filesystem_path($ext['path'])) === false) { return new WP_Error('real_to_wpfs_filed', sprintf(__('Failed to extract relative directory from: %s', 'fw'), $ext['path'])); } $wpfs_dest_dir = $wpfs_tmp_dir . $rel_path; if (!FW_WP_Filesystem::mkdir_recursive($wpfs_dest_dir)) { return new WP_Error('dest_dir_mk_fail', sprintf(__('Failed to create directory %s', 'fw'), $wpfs_dest_dir)); } if (is_wp_error($copy_result = copy_dir($wpfs_path, $wpfs_dest_dir))) { /** @var WP_Error $copy_result */ return new WP_Error('ext_copy_failed', sprintf(__('Failed to copy extension to %s', 'fw'), $wpfs_dest_dir)); } } }