feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)
Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.
Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
- Provider key: s3compatible
- Reads user-configured endpoint URL from settings
- Uses path-style URL access (required by most S3-compatible services)
- Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
- Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions;
|
||||
|
||||
class Batch_Limits_Exceeded_Exception extends \Exception {
|
||||
}
|
||||
6
classes/upgrades/exceptions/no-more-blogs-exception.php
Normal file
6
classes/upgrades/exceptions/no-more-blogs-exception.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions;
|
||||
|
||||
class No_More_Blogs_Exception extends \Exception {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions;
|
||||
|
||||
class Too_Many_Errors_Exception extends \Exception {
|
||||
}
|
||||
95
classes/upgrades/network-upgrade.php
Normal file
95
classes/upgrades/network-upgrade.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use Amazon_S3_And_CloudFront;
|
||||
|
||||
abstract class Network_Upgrade {
|
||||
|
||||
/**
|
||||
* @var Amazon_S3_And_CloudFront
|
||||
*/
|
||||
protected $as3cf;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $version;
|
||||
|
||||
/**
|
||||
* Network_Upgrade constructor.
|
||||
*
|
||||
* @param Amazon_S3_And_CloudFront $as3cf
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct( $as3cf, $version ) {
|
||||
$this->as3cf = $as3cf;
|
||||
$this->version = $version;
|
||||
|
||||
add_action( 'admin_init', array( $this, 'init' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init upgrade.
|
||||
*/
|
||||
public function init() {
|
||||
if ( ! $this->maybe_upgrade() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->do_upgrade();
|
||||
$this->save_version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe perform upgrade?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function maybe_upgrade() {
|
||||
$stored_version = $this->get_stored_version();
|
||||
|
||||
if ( version_compare( $stored_version, $this->version, '<' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stored version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_stored_version() {
|
||||
static $version;
|
||||
|
||||
if ( is_null( $version ) ) {
|
||||
$version = get_site_option( $this->get_option_name(), '0.0' );
|
||||
}
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get option name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_option_name() {
|
||||
return strtolower( get_class( $this->as3cf ) ) . '_version';
|
||||
}
|
||||
|
||||
/**
|
||||
* Save version to options table.
|
||||
*/
|
||||
protected function save_version() {
|
||||
update_site_option( $this->get_option_name(), $this->version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform upgrade logic.
|
||||
*/
|
||||
abstract protected function do_upgrade();
|
||||
|
||||
}
|
||||
113
classes/upgrades/upgrade-clear-postmeta-cache.php
Normal file
113
classes/upgrades/upgrade-clear-postmeta-cache.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
/**
|
||||
* Clear_Postmeta_Cache Class
|
||||
*
|
||||
* This class clears the postmeta cache after upgrade to 2.6.1
|
||||
*
|
||||
* @since 2.6.1
|
||||
*/
|
||||
class Upgrade_Clear_Postmeta_Cache extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 11;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'clear_postmeta_cache';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $batch_limit = 1000;
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and clear old post meta cache items.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one chunk of post meta cache records.
|
||||
*
|
||||
* @param string $item Table prefix for the current blog.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "DELETE FROM {$item}postmeta WHERE meta_key = 'amazonS3_cache' AND meta_id <= %d LIMIT {$this->batch_limit}";
|
||||
$wpdb->query( $wpdb->prepare( $sql, array( $this->session[ $item ] ) ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count items left to process for the current blog.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_items_to_process() {
|
||||
global $wpdb;
|
||||
|
||||
// Store the highest known meta_id at the time we begin processing.
|
||||
if ( empty( $this->session[ $this->blog_prefix ] ) ) {
|
||||
$sql = "SELECT meta_id FROM {$this->blog_prefix}postmeta WHERE meta_key = 'amazonS3_cache' ORDER BY meta_id DESC LIMIT 0, 1;";
|
||||
$last = $wpdb->get_var( $sql );
|
||||
|
||||
$this->session[ $this->blog_prefix ] = $last;
|
||||
}
|
||||
|
||||
return count( $this->get_items_to_process( $this->blog_prefix, 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of items that each represent one chunk to be cleared.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
$count = $this->get_real_count( $prefix );
|
||||
if ( 0 === $count ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$chunks = ceil( $count / $this->batch_limit );
|
||||
|
||||
return array_fill( 0, $chunks, $prefix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the real number of remaining amazonS3_cache items to clear out.
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function get_real_count( $prefix ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "SELECT count(meta_id) FROM {$prefix}postmeta WHERE meta_key = 'amazonS3_cache' AND meta_id <= %d";
|
||||
$count = $wpdb->get_var( $wpdb->prepare( $sql, $this->session[ $prefix ] ) );
|
||||
|
||||
return (int) $count;
|
||||
}
|
||||
}
|
||||
92
classes/upgrades/upgrade-content-replace-urls.php
Normal file
92
classes/upgrades/upgrade-content-replace-urls.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Utils;
|
||||
|
||||
/**
|
||||
* Upgrade_Content_Replace_URLs Class
|
||||
*
|
||||
* This class handles replacing all S3 URLs in post
|
||||
* content with the local URL.
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
class Upgrade_Content_Replace_URLs extends Upgrade_Filter_Post {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 4;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'replace_provider_urls';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $column_name = 'post_content';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and ensuring that only the local URL exists in post content.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get running message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_message() {
|
||||
return sprintf( __( '<strong>Running Content Upgrade%1$s</strong><br>A find & replace is running in the background to update URLs in your post content. %2$s', 'amazon-s3-and-cloudfront' ), $this->get_progress_text(), $this->get_generic_message() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a new blog for processing.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_blog() {
|
||||
$this->upgrade_theme_mods();
|
||||
|
||||
return parent::upgrade_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade theme mods. Ensures background and header images have local URLs saved to the database.
|
||||
*/
|
||||
protected function upgrade_theme_mods() {
|
||||
global $wpdb;
|
||||
|
||||
$mods = $wpdb->get_results( "SELECT * FROM `{$wpdb->options}` WHERE option_name LIKE 'theme_mods_%'" );
|
||||
|
||||
foreach ( $mods as $mod ) {
|
||||
$value = AS3CF_Utils::maybe_unserialize( $mod->option_value );
|
||||
|
||||
if ( isset( $value['background_image'] ) ) {
|
||||
$value['background_image'] = $this->as3cf->filter_provider->filter_customizer_image( $value['background_image'] );
|
||||
}
|
||||
|
||||
if ( isset( $value['header_image'] ) ) {
|
||||
$value['header_image'] = $this->as3cf->filter_provider->filter_customizer_image( $value['header_image'] );
|
||||
}
|
||||
|
||||
if ( isset( $value['header_image_data'] ) ) {
|
||||
$value['header_image_data'] = $this->as3cf->filter_provider->filter_header_image_data( $value['header_image_data'] );
|
||||
}
|
||||
|
||||
$value = maybe_serialize( $value );
|
||||
|
||||
if ( $value !== $mod->option_value ) {
|
||||
$wpdb->query( "UPDATE `{$wpdb->options}` SET option_value = '{$value}' WHERE option_id = '{$mod->option_id}'" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
103
classes/upgrades/upgrade-edd-replace-urls.php
Normal file
103
classes/upgrades/upgrade-edd-replace-urls.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
||||
|
||||
/**
|
||||
* Upgrade_EDD_Replace_URLs Class
|
||||
*
|
||||
* This class handles replacing all S3 URLs in EDD
|
||||
* downloads with the local URL.
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
class Upgrade_EDD_Replace_URLs extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 5;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'replace_edd_urls';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'post meta';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and ensuring that only the local URL exists in EDD post meta.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items to process.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "SELECT * FROM `{$prefix}postmeta` WHERE meta_key = 'edd_download_files'";
|
||||
|
||||
if ( false !== $offset ) {
|
||||
$sql .= " AND meta_id > {$offset->meta_id}";
|
||||
}
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade item.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
$attachments = AS3CF_Utils::maybe_unserialize( $item->meta_value );
|
||||
|
||||
if ( ! is_array( $attachments ) || empty( $attachments ) ) {
|
||||
// No attachments to process, return
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $attachments as $key => $attachment ) {
|
||||
if ( ! isset( $attachment['attachment_id'] ) || ! isset( $attachment['file'] ) ) {
|
||||
// Can't determine ID or file, continue
|
||||
continue;
|
||||
}
|
||||
|
||||
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment['attachment_id'] );
|
||||
if ( empty( $as3cf_item ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $url = $as3cf_item->get_local_url() ) {
|
||||
$attachments[ $key ]['file'] = $url;
|
||||
}
|
||||
}
|
||||
|
||||
update_post_meta( $item->post_id, 'edd_download_files', $attachments );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
210
classes/upgrades/upgrade-file-sizes.php
Normal file
210
classes/upgrades/upgrade-file-sizes.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
/**
|
||||
* Update File Sizes
|
||||
*
|
||||
* @package amazon-s3-and-cloudfront
|
||||
* @subpackage Classes/Upgrades/File-Sizes
|
||||
* @copyright Copyright (c) 2015, Delicious Brains
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 0.9.3
|
||||
*/
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Error;
|
||||
use AS3CF_Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Upgrade_File_Sizes Class
|
||||
*
|
||||
* This class handles updating the file sizes in the meta data
|
||||
* for attachments that have been removed from the local server
|
||||
*
|
||||
* @since 0.9.3
|
||||
*/
|
||||
class Upgrade_File_Sizes extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 2;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'file_sizes';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'attachments';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and updating the metadata with the sizes of files that have been removed from the server. This will allow us to serve the correct size for media items and the total space used in Multisite subsites.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total file sizes for an attachment and associated files.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
$provider_object = AS3CF_Utils::maybe_fix_serialized_string( $item->provider_object );
|
||||
$fixed = $item->provider_object !== $provider_object;
|
||||
|
||||
$provider_object = AS3CF_Utils::maybe_unserialize( $provider_object );
|
||||
|
||||
if ( false === $provider_object ) {
|
||||
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $fixed ) {
|
||||
if ( update_post_meta( $item->ID, 'amazonS3_info', $provider_object ) ) {
|
||||
$msg = sprintf( __( 'Fixed legacy amazonS3_info metadata when updating file size metadata, please check bucket and path for attachment ID %1$s', 'amazon-s3-and-cloudfront' ), $item->ID );
|
||||
AS3CF_Error::log( $msg );
|
||||
} else {
|
||||
AS3CF_Error::log( 'Failed to fix broken serialized legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
||||
$as3cf_item = Media_Library_Item::get_by_source_id( $item->ID );
|
||||
|
||||
if ( ! $as3cf_item ) {
|
||||
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// $as3cf_item can't exist without a region value, so we can just use it here.
|
||||
$region = $as3cf_item->region();
|
||||
|
||||
$provider_client = $this->as3cf->get_provider_client( $region, true );
|
||||
$main_file = $provider_object['key'];
|
||||
|
||||
$ext = pathinfo( $main_file, PATHINFO_EXTENSION );
|
||||
$prefix = trailingslashit( dirname( $provider_object['key'] ) );
|
||||
|
||||
// Used to search S3 for all files related to an attachment
|
||||
$search_prefix = $prefix . wp_basename( $main_file, ".$ext" );
|
||||
|
||||
$args = array(
|
||||
'Bucket' => $provider_object['bucket'],
|
||||
'Prefix' => $search_prefix,
|
||||
);
|
||||
|
||||
try {
|
||||
// List objects for the attachment
|
||||
$result = $provider_client->list_objects( $args );
|
||||
} catch ( Exception $e ) {
|
||||
AS3CF_Error::log( 'Error listing objects of prefix ' . $search_prefix . ' for attachment ' . $item->ID . ' in bucket: ' . $e->getMessage() );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$file_size_total = 0;
|
||||
$main_file_size = 0;
|
||||
|
||||
if ( ! empty( $result['Contents'] ) ) {
|
||||
foreach ( $result['Contents'] as $object ) {
|
||||
if ( ! isset( $object['Size'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = $object['Size'];
|
||||
|
||||
// Increment the total size of files for the attachment
|
||||
$file_size_total += $size;
|
||||
|
||||
if ( $object['Key'] === $main_file ) {
|
||||
// Record the size of the main file
|
||||
$main_file_size = $size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 === $file_size_total ) {
|
||||
AS3CF_Error::log( 'Total file size for the attachment is 0: ' . $item->ID );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the main file size for the attachment
|
||||
$meta = get_post_meta( $item->ID, '_wp_attachment_metadata', true );
|
||||
$meta['filesize'] = $main_file_size;
|
||||
update_post_meta( $item->ID, '_wp_attachment_metadata', $meta );
|
||||
|
||||
// Add the total file size for all image sizes
|
||||
update_post_meta( $item->ID, 'wpos3_filesize_total', $file_size_total );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attachments removed from the server.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
$all_attachments = $this->get_provider_attachments( $prefix, $limit );
|
||||
$attachments = array();
|
||||
|
||||
foreach ( $all_attachments as $attachment ) {
|
||||
if ( ! file_exists( get_attached_file( $attachment->ID, true ) ) ) {
|
||||
$attachments[] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for database call to get attachments uploaded to S3,
|
||||
* that don't have the file size meta added already
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param null|int $limit
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_provider_attachments( $prefix, $limit = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "SELECT pm1.`post_id` as `ID`, pm1.`meta_value` AS 'provider_object'
|
||||
FROM `{$prefix}postmeta` pm1
|
||||
LEFT OUTER JOIN `{$prefix}postmeta` pm2
|
||||
ON pm1.`post_id` = pm2.`post_id`
|
||||
AND pm2.`meta_key` = 'wpos3_filesize_total'
|
||||
WHERE pm1.`meta_key` = 'amazonS3_info'
|
||||
AND pm2.`post_id` is null";
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql, OBJECT );
|
||||
}
|
||||
}
|
||||
47
classes/upgrades/upgrade-filter-post-excerpt.php
Normal file
47
classes/upgrades/upgrade-filter-post-excerpt.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
/**
|
||||
* Upgrade_Filter_Post_Excerpt Class
|
||||
*
|
||||
* This class handles replacing all S3 URLs in post
|
||||
* excerpts with the local URL.
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
class Upgrade_Filter_Post_Excerpt extends Upgrade_Filter_Post {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 6;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'filter_post_excerpt';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $column_name = 'post_excerpt';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and ensuring that only the local URL exists in post excerpts.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get running message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_message() {
|
||||
return sprintf( __( '<strong>Running Excerpts Upgrade%1$s</strong><br>A find & replace is running in the background to update URLs in your post excerpts. %2$s', 'amazon-s3-and-cloudfront' ), $this->get_progress_text(), $this->get_generic_message() );
|
||||
}
|
||||
}
|
||||
458
classes/upgrades/upgrade-filter-post.php
Normal file
458
classes/upgrades/upgrade-filter-post.php
Normal file
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
||||
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Batch_Limits_Exceeded_Exception;
|
||||
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Too_Many_Errors_Exception;
|
||||
|
||||
/**
|
||||
* Upgrade_Filter_Post Class
|
||||
*
|
||||
* The base upgrade class for handling find and replace
|
||||
* on the posts tables for content filtering.
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
abstract class Upgrade_Filter_Post extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int Time limit in seconds.
|
||||
*/
|
||||
protected $time_limit = 10;
|
||||
|
||||
/**
|
||||
* @var int Batch size limit for this request session.
|
||||
*/
|
||||
protected $size_limit = 50;
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'posts';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $column_name;
|
||||
|
||||
/**
|
||||
* @var int The last post ID used for the bottom range of the item upgrade.
|
||||
*/
|
||||
protected $last_post_id;
|
||||
|
||||
/**
|
||||
* Get highest post ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_highest_post_id() {
|
||||
global $wpdb;
|
||||
|
||||
return (int) $wpdb->get_var( "SELECT MAX(ID) FROM {$wpdb->posts}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items to process.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "SELECT posts.ID FROM `{$prefix}posts` AS posts
|
||||
INNER JOIN `{$prefix}postmeta` AS postmeta
|
||||
ON posts.ID = postmeta.post_id
|
||||
WHERE posts.post_type = 'attachment'
|
||||
AND postmeta.meta_key = 'amazonS3_info'";
|
||||
|
||||
if ( ! empty( $offset ) ) {
|
||||
$sql .= " AND posts.ID < '{$offset}'";
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY posts.ID DESC";
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the given blog, and update blog-specific state.
|
||||
*
|
||||
* @param int $blog_id
|
||||
*/
|
||||
protected function switch_to_blog( $blog_id ) {
|
||||
parent::switch_to_blog( $blog_id );
|
||||
$this->last_post_id = $this->load_last_post_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current blog upgrade as complete.
|
||||
*/
|
||||
protected function blog_upgrade_completed() {
|
||||
parent::blog_upgrade_completed();
|
||||
$this->last_post_id = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the session to be persisted.
|
||||
*/
|
||||
protected function close_session() {
|
||||
parent::close_session();
|
||||
$this->session['last_post_id'] = $this->last_post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade item.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
* @throws Batch_Limits_Exceeded_Exception
|
||||
* @throws Too_Many_Errors_Exception
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
$limit = apply_filters( 'as3cf_update_' . $this->upgrade_name . '_sql_limit', 100000 );
|
||||
$where_highest_id = $this->last_post_id;
|
||||
$where_lowest_id = max( $where_highest_id - $limit, 0 );
|
||||
|
||||
while ( true ) {
|
||||
$this->find_and_replace_attachment_urls( $item->ID, $where_lowest_id, $where_highest_id );
|
||||
|
||||
if ( $where_lowest_id <= 0 ) {
|
||||
// Batch completed
|
||||
return true;
|
||||
}
|
||||
|
||||
$where_highest_id = $where_lowest_id;
|
||||
$where_lowest_id = max( $where_lowest_id - $limit, 0 );
|
||||
$this->last_post_id = $where_lowest_id;
|
||||
|
||||
$this->check_batch_limits();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any actions necessary after the given item is completed.
|
||||
*
|
||||
* @param mixed $item
|
||||
*/
|
||||
protected function item_upgrade_completed( $item ) {
|
||||
parent::item_upgrade_completed( $item );
|
||||
$this->last_item = $item->ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and replace embedded URLs for an attachment.
|
||||
*
|
||||
* @param int $attachment_id
|
||||
* @param int $where_lowest_id
|
||||
* @param int $where_highest_id
|
||||
*/
|
||||
protected function find_and_replace_attachment_urls( $attachment_id, $where_lowest_id, $where_highest_id ) {
|
||||
$meta = wp_get_attachment_metadata( $attachment_id, true );
|
||||
$backups = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
|
||||
$file_path = get_attached_file( $attachment_id, true );
|
||||
$as3cf_item = Item::get_by_source_id( $attachment_id );
|
||||
|
||||
if ( empty( $as3cf_item ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$new_url = $as3cf_item->get_local_url();
|
||||
$old_url = $this->as3cf->maybe_remove_query_string( $as3cf_item->get_provider_url() );
|
||||
|
||||
if ( empty( $old_url ) || empty( $new_url ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urls = $this->get_find_and_replace_urls( $file_path, $old_url, $new_url, $meta, $backups );
|
||||
|
||||
$this->process_pair_replacement( $urls, $where_lowest_id, $where_highest_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get find and replace URLs.
|
||||
*
|
||||
* @param string $file_path
|
||||
* @param string $old_url
|
||||
* @param string $new_url
|
||||
* @param array $meta
|
||||
* @param array|string $backups
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_find_and_replace_urls( $file_path, $old_url, $new_url, $meta, $backups = '' ) {
|
||||
$url_pairs = array();
|
||||
$file_name = wp_basename( $file_path );
|
||||
$old_file_name = wp_basename( $old_url );
|
||||
$new_file_name = wp_basename( $new_url );
|
||||
|
||||
// Full size image
|
||||
$url_pairs[] = $this->add_url_pair( $file_path, $file_name, $old_url, $old_file_name, $new_url, $new_file_name );
|
||||
|
||||
if ( isset( $meta['thumb'] ) && $meta['thumb'] ) {
|
||||
// Replace URLs for legacy thumbnail of image
|
||||
$url_pairs[] = $this->add_url_pair( $file_path, $file_name, $old_url, $old_file_name, $new_url, $new_file_name, $meta['thumb'] );
|
||||
}
|
||||
|
||||
if ( ! empty( $meta['sizes'] ) ) {
|
||||
// Replace URLs for intermediate sizes of image
|
||||
foreach ( $meta['sizes'] as $key => $size ) {
|
||||
if ( ! isset( $size['file'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url_pairs[] = $this->add_url_pair( $file_path, $file_name, $old_url, $old_file_name, $new_url, $new_file_name, $size['file'] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $backups ) ) {
|
||||
// Replace URLs for backup images
|
||||
foreach ( $backups as $backup ) {
|
||||
if ( ! isset( $backup['file'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url_pairs[] = $this->add_url_pair( $file_path, $file_name, $old_url, $old_file_name, $new_url, $new_file_name, $backup['file'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Also find encoded file names
|
||||
$url_pairs = $this->maybe_add_encoded_url_pairs( $url_pairs );
|
||||
|
||||
// Remove URL protocols
|
||||
foreach ( $url_pairs as $key => $url_pair ) {
|
||||
$url_pairs[ $key ]['old_url'] = AS3CF_Utils::remove_scheme( $url_pair['old_url'] );
|
||||
$url_pairs[ $key ]['new_url'] = AS3CF_Utils::remove_scheme( $url_pair['new_url'] );
|
||||
}
|
||||
|
||||
return apply_filters( 'as3cf_update_' . $this->upgrade_name . '_url_pairs', $url_pairs, $file_path, $old_url, $new_url, $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add URL pair.
|
||||
*
|
||||
* @param string $file_path
|
||||
* @param string $file_name
|
||||
* @param string $old_url
|
||||
* @param string $old_file_name
|
||||
* @param string $new_url
|
||||
* @param string $new_file_name
|
||||
* @param string|bool $size_file_name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function add_url_pair( $file_path, $file_name, $old_url, $old_file_name, $new_url, $new_file_name, $size_file_name = false ) {
|
||||
if ( ! $size_file_name ) {
|
||||
return array(
|
||||
'old_path' => $file_path,
|
||||
'old_url' => str_replace( $old_file_name, $file_name, $old_url ),
|
||||
'new_url' => $new_url,
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'old_path' => str_replace( $file_name, $size_file_name, $file_path ),
|
||||
'old_url' => str_replace( $old_file_name, $size_file_name, $old_url ),
|
||||
'new_url' => str_replace( $new_file_name, $size_file_name, $new_url ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe add encoded URL pairs.
|
||||
*
|
||||
* @param array $url_pairs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function maybe_add_encoded_url_pairs( $url_pairs ) {
|
||||
foreach ( $url_pairs as $url_pair ) {
|
||||
$file_name = wp_basename( $url_pair['old_url'] );
|
||||
$encoded_file_name = AS3CF_Utils::encode_filename_in_path( $file_name );
|
||||
|
||||
if ( $file_name !== $encoded_file_name ) {
|
||||
$url_pair['old_url'] = str_replace( $file_name, $encoded_file_name, $url_pair['old_url'] );
|
||||
$url_pairs[] = $url_pair;
|
||||
}
|
||||
}
|
||||
|
||||
return $url_pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the find and replace in the database of old and new URLs.
|
||||
*
|
||||
* @param array $url_pairs
|
||||
* @param int $where_lowest_id
|
||||
* @param int $where_highest_id
|
||||
*/
|
||||
protected function process_pair_replacement( $url_pairs, $where_lowest_id, $where_highest_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$posts = $wpdb->get_results( $this->generate_select_sql( $url_pairs, $where_lowest_id, $where_highest_id ) );
|
||||
|
||||
if ( empty( $posts ) ) {
|
||||
// Nothing to process, move on
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit REPLACE statements to 10 per query and INTO to 100 per query
|
||||
$url_pairs = array_chunk( $url_pairs, 10 );
|
||||
$ids = array_chunk( wp_list_pluck( $posts, 'ID' ), 100 );
|
||||
|
||||
foreach ( $url_pairs as $url_pairs_chunk ) {
|
||||
foreach ( $ids as $ids_chunk ) {
|
||||
$wpdb->query( $this->generate_update_sql( $url_pairs_chunk, $ids_chunk ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate select SQL.
|
||||
*
|
||||
* @param array $url_pairs
|
||||
* @param int $where_lowest_id
|
||||
* @param int $where_highest_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_select_sql( $url_pairs, $where_lowest_id, $where_highest_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$paths = array();
|
||||
|
||||
// Get unique URLs without size string and extension
|
||||
foreach ( $url_pairs as $url_pair ) {
|
||||
$paths[] = AS3CF_Utils::remove_size_from_filename( $url_pair['old_url'], true );
|
||||
}
|
||||
|
||||
$paths = array_unique( $paths );
|
||||
$sql = '';
|
||||
|
||||
foreach ( $paths as $path ) {
|
||||
if ( ! empty( $sql ) ) {
|
||||
$sql .= " OR ";
|
||||
}
|
||||
|
||||
$sql .= "{$this->column_name} LIKE '%{$path}%'";
|
||||
}
|
||||
|
||||
return "SELECT ID FROM {$wpdb->posts} WHERE ID > {$where_lowest_id} AND ID <= {$where_highest_id} AND ({$sql})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate update SQL.
|
||||
*
|
||||
* @param array $url_pairs
|
||||
* @param array $ids
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_update_sql( $url_pairs, $ids ) {
|
||||
global $wpdb;
|
||||
|
||||
$ids = implode( ',', $ids );
|
||||
$sql = '';
|
||||
|
||||
foreach ( $url_pairs as $pair ) {
|
||||
if ( ! isset( $pair['old_url'] ) || ! isset( $pair['new_url'] ) ) {
|
||||
// We need both URLs for the find and replace
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $sql ) ) {
|
||||
// First replace statement
|
||||
$sql = "REPLACE({$this->column_name}, '{$pair['old_url']}', '{$pair['new_url']}')";
|
||||
} else {
|
||||
// Nested replace statement
|
||||
$sql = "REPLACE({$sql}, '{$pair['old_url']}', '{$pair['new_url']}')";
|
||||
}
|
||||
}
|
||||
|
||||
return "UPDATE {$wpdb->posts} SET `{$this->column_name}` = {$sql} WHERE `ID` IN({$ids})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paused message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_paused_message() {
|
||||
return sprintf( __( '<strong>Paused Upgrade</strong><br>The find & replace to update URLs has been paused. %s', 'amazon-s3-and-cloudfront' ), $this->get_generic_message() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notice message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_generic_message() {
|
||||
$link_text = __( 'See our documentation', 'amazon-s3-and-cloudfront' );
|
||||
$url = $this->as3cf->dbrains_url( '/wp-offload-media/doc/content-filtering-upgrade', array(
|
||||
'utm_campaign' => 'support+docs',
|
||||
) );
|
||||
$link = AS3CF_Utils::dbrains_link( $url, $link_text );
|
||||
|
||||
return sprintf( __( '%s for details on why we’re doing this, why it runs slowly, and how to make it run faster.', 'amazon-s3-and-cloudfront' ), $link );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the last blog ID from the session.
|
||||
*
|
||||
* If the ID is found using the standard session key, use that.
|
||||
* Otherwise if it is an older session, derive the ID from the blogs in the session.
|
||||
*
|
||||
* @return bool|int|mixed
|
||||
*/
|
||||
protected function load_last_blog_id() {
|
||||
if ( $blog_id = parent::load_last_blog_id() ) {
|
||||
return $blog_id;
|
||||
}
|
||||
|
||||
$blog_ids = $this->load_processesed_blog_ids();
|
||||
|
||||
return end( $blog_ids );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the processed blog IDs from the session.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function load_processesed_blog_ids() {
|
||||
if ( $ids = parent::load_processesed_blog_ids() ) {
|
||||
return $ids;
|
||||
}
|
||||
|
||||
if ( isset( $this->session['blogs'] ) && is_array( $this->session['blogs'] ) ) {
|
||||
return array_keys( $this->session['blogs'] );
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the last post ID.
|
||||
*
|
||||
* The last post ID is set from the session if set,
|
||||
* otherwise it defaults to the highest post ID on the site.
|
||||
*
|
||||
* @return int Post ID.
|
||||
*/
|
||||
protected function load_last_post_id() {
|
||||
if ( isset( $this->session['last_post_id'] ) ) {
|
||||
return (int) $this->session['last_post_id'];
|
||||
}
|
||||
|
||||
return $this->get_highest_post_id();
|
||||
}
|
||||
}
|
||||
159
classes/upgrades/upgrade-fix-broken-item-extra-data.php
Normal file
159
classes/upgrades/upgrade-fix-broken-item-extra-data.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* Upgrade extra info in custom objects table.
|
||||
*
|
||||
* @package amazon-s3-and-cloudfront
|
||||
* @subpackage Classes/Upgrades/Upgrade_Fix_Broken_Item_Extra_Data
|
||||
* @copyright Copyright (c) 2022, Delicious Brains
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 2.6.2
|
||||
*/
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Error;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Upgrade_Fix_Broken_Item_Extra_Data Class
|
||||
*
|
||||
* This class handles updating extra info in the custom objects table.
|
||||
*
|
||||
* @since 2.6.2
|
||||
*/
|
||||
class Upgrade_Fix_Broken_Item_Extra_Data extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 12;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'fix_broken_item_extra_data';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and updating metadata about offloaded items to new format.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update extra_info in items table.
|
||||
*
|
||||
* @param stdClass $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
Item::disable_cache();
|
||||
$as3cf_item = Media_Library_Item::get_by_source_id( $item->source_id );
|
||||
Item::enable_cache();
|
||||
|
||||
if ( ! $as3cf_item ) {
|
||||
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->source_id . '.' );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $as3cf_item->save();
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
AS3CF_Error::log( 'Error saving item: ' . $result->get_error_message() );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count items left to process for the current blog.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_items_to_process() {
|
||||
return $this->count_items_with_old_extra_info( $this->blog_prefix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all items to be processed.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
return $this->get_items_with_old_extra_info( $prefix, false, $limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of items that have legacy extra info.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_items_with_old_extra_info( $prefix ) {
|
||||
return $this->get_items_with_old_extra_info( $prefix, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for database call to get items with legacy extra info.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
* @param bool $count return count of attachments
|
||||
* @param null|int $limit
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_items_with_old_extra_info( $prefix, $count = false, $limit = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$table = Item::ITEMS_TABLE;
|
||||
|
||||
/**
|
||||
* Find items with legacy or broken extra_info data.
|
||||
*/
|
||||
$sql = "
|
||||
FROM {$prefix}{$table}
|
||||
WHERE (
|
||||
extra_info NOT LIKE '%s:7:\"objects\"%' -- not upgraded
|
||||
OR extra_info LIKE '%s:7:\"objects\";a:0%' -- broken objects array
|
||||
OR extra_info LIKE '%s:13:\"private_sizes\";a%' -- private sizes not migrated
|
||||
OR extra_info LIKE 's:%' -- very broken
|
||||
)
|
||||
AND source_type='media-library'
|
||||
";
|
||||
|
||||
if ( $count ) {
|
||||
$sql = 'SELECT COUNT(source_id)' . $sql;
|
||||
|
||||
return $wpdb->get_var( $sql );
|
||||
}
|
||||
|
||||
$sql = 'SELECT source_id' . $sql;
|
||||
$sql .= ' ORDER BY id';
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql, OBJECT );
|
||||
}
|
||||
}
|
||||
75
classes/upgrades/upgrade-item-extra-data.php
Normal file
75
classes/upgrades/upgrade-item-extra-data.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* Upgrade extra info in custom objects table.
|
||||
*
|
||||
* This upgrade is redundant, superseded by upgrade 12,
|
||||
* but needs to be kept for sequence continuity.
|
||||
*
|
||||
* @package amazon-s3-and-cloudfront
|
||||
* @subpackage Classes/Upgrades/Upgrade_Item_Extra_Data
|
||||
* @copyright Copyright (c) 2021, Delicious Brains
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 2.6.0
|
||||
*/
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Upgrade_Item_Extra_Data Class
|
||||
*
|
||||
* This class handles updating extra info in the custom objects table.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
class Upgrade_Item_Extra_Data extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 10;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'item_extra_data';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and updating metadata about offloaded items to new format.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update extra_info in items table.
|
||||
*
|
||||
* @param stdClass $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all items to be processed.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
189
classes/upgrades/upgrade-items-table.php
Normal file
189
classes/upgrades/upgrade-items-table.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* Upgrade Metadata to use custom objects table.
|
||||
*
|
||||
* @package amazon-s3-and-cloudfront
|
||||
* @subpackage Classes/Upgrades/Upgrade_Items_Table
|
||||
* @copyright Copyright (c) 2014, Delicious Brains
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 2.3.0
|
||||
*/
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Error;
|
||||
use AS3CF_Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
||||
|
||||
/**
|
||||
* Upgrade_Items_Table Class
|
||||
*
|
||||
* This class handles updating the offload metadata for attachments to use a custom table.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
class Upgrade_Items_Table extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 8;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'as3cf_items_table';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and updating the plugin\'s metadata to use a faster storage method. During the update the site\'s total offloaded media count may be inaccurate but will settle down shortly after completing.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an attachment's provider object data from the postmeta table to the custom as3cf_objects table.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
$provider_object = AS3CF_Utils::maybe_fix_serialized_string( $item->provider_object );
|
||||
$fixed = $item->provider_object !== $provider_object;
|
||||
|
||||
// Make sure legacy metadata isn't broken.
|
||||
$provider_object = AS3CF_Utils::maybe_unserialize( $provider_object );
|
||||
|
||||
if ( false === $provider_object ) {
|
||||
AS3CF_Error::log( 'Failed to unserialize legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( empty( $item->source_path ) ) {
|
||||
AS3CF_Error::log( 'Attachment with ID ' . $item->ID . ' with legacy offload metadata has no local file path.' );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $fixed ) {
|
||||
if ( update_post_meta( $item->ID, 'amazonS3_info', $provider_object ) ) {
|
||||
$msg = sprintf( __( 'Fixed legacy amazonS3_info metadata when moved to %1$s table, please check bucket and path for attachment ID %2$s', 'amazon-s3-and-cloudfront' ), Media_Library_Item::items_table(), $item->ID );
|
||||
AS3CF_Error::log( $msg );
|
||||
} else {
|
||||
AS3CF_Error::log( 'Failed to fix broken serialized legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
||||
// If we're here we already know there's legacy metadata and that there isn't a new items table record yet,
|
||||
// or there's legacy metadata and an existing items table record that we can just re-save without issue before deleting legacy metadata.
|
||||
// An existing items table entry takes precedence over legacy metadata to avoid accidental overrides from migrations, custom code or other plugins.
|
||||
$as3cf_item = Media_Library_Item::get_by_source_id( $item->ID );
|
||||
|
||||
if ( ! $as3cf_item ) {
|
||||
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $as3cf_item->save();
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
AS3CF_Error::log( 'Error saving item: ' . $result->get_error_message() );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete old metadata.
|
||||
return delete_post_meta( $item->ID, 'amazonS3_info' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all attachments to be processed.
|
||||
* for the whole site
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_items_to_process() {
|
||||
return $this->count_attachments_with_legacy_metadata( $this->blog_prefix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attachments to be processed.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
$attachments = $this->get_attachments_with_legacy_metadata( $prefix, false, $limit );
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of attachments that have legacy metadata.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_attachments_with_legacy_metadata( $prefix ) {
|
||||
$count = $this->get_attachments_with_legacy_metadata( $prefix, true );
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for database call to get attachments with legacy metadata.
|
||||
*
|
||||
* @param string $prefix Table prefix for blog.
|
||||
* @param bool $count return count of attachments
|
||||
* @param null|int $limit
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_attachments_with_legacy_metadata( $prefix, $count = false, $limit = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "
|
||||
FROM {$prefix}postmeta AS a, {$prefix}postmeta AS p
|
||||
WHERE a.meta_key = '_wp_attached_file'
|
||||
AND p.meta_key = 'amazonS3_info'
|
||||
AND a.post_id = p.post_id
|
||||
";
|
||||
|
||||
if ( $count ) {
|
||||
$sql = 'SELECT COUNT(DISTINCT p.post_id)' . $sql;
|
||||
|
||||
return $wpdb->get_var( $sql );
|
||||
}
|
||||
|
||||
$sql = 'SELECT a.post_id AS ID, p.meta_id AS po_id, a.meta_value AS source_path, p.meta_value AS provider_object' . $sql;
|
||||
$sql .= ' ORDER BY ID, po_id';
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql, OBJECT );
|
||||
}
|
||||
}
|
||||
171
classes/upgrades/upgrade-meta-wp-error.php
Normal file
171
classes/upgrades/upgrade-meta-wp-error.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* Update Broken _wp_attachment_metadata introduced in 0.9.4
|
||||
*
|
||||
* @package amazon-s3-and-cloudfront
|
||||
* @subpackage Classes/Upgrades/Meta-WP-Error
|
||||
* @copyright Copyright (c) 2015, Delicious Brains
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 0.9.5
|
||||
*/
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Error;
|
||||
use AS3CF_Utils;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Upgrade_Meta_WP_Error Class
|
||||
*
|
||||
* This class handles updating the _wp_attachment_metadata
|
||||
* for attachments that have been removed from the local server
|
||||
* and have had it corrupted by another plugin
|
||||
*
|
||||
* @since 0.9.5
|
||||
*/
|
||||
class Upgrade_Meta_WP_Error extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 3;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'meta_error';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'attachments';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and rebuilding the metadata for attachments that may have been corrupted.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the attachment metadata for an attachment
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
$provider_object = AS3CF_Utils::maybe_fix_serialized_string( $item->provider_object );
|
||||
$fixed = $item->provider_object !== $provider_object;
|
||||
|
||||
$provider_object = AS3CF_Utils::maybe_unserialize( $provider_object );
|
||||
|
||||
if ( false === $provider_object ) {
|
||||
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $fixed ) {
|
||||
if ( update_post_meta( $item->ID, 'amazonS3_info', $provider_object ) ) {
|
||||
$msg = sprintf( __( 'Fixed legacy amazonS3_info metadata when rebuilding corrupted attachment metadata, please check bucket and path for attachment ID %1$s', 'amazon-s3-and-cloudfront' ), $item->ID );
|
||||
AS3CF_Error::log( $msg );
|
||||
} else {
|
||||
AS3CF_Error::log( 'Failed to fix broken serialized legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$file = get_attached_file( $item->ID, true );
|
||||
|
||||
if ( ! file_exists( $file ) ) {
|
||||
// Copy back the file to the server if doesn't exist so we can successfully
|
||||
// regenerate the attachment metadata
|
||||
try {
|
||||
$args = array(
|
||||
'Bucket' => $provider_object['bucket'],
|
||||
'Key' => $provider_object['key'],
|
||||
'SaveAs' => $file,
|
||||
);
|
||||
$this->as3cf->get_provider_client( $provider_object['region'], true )->get_object( $args );
|
||||
} catch ( Exception $e ) {
|
||||
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $provider_object['key'], $e->getMessage() ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove corrupted meta
|
||||
delete_post_meta( $item->ID, '_wp_attachment_metadata' );
|
||||
|
||||
require_once ABSPATH . '/wp-admin/includes/image.php';
|
||||
// Generate new attachment meta
|
||||
wp_update_attachment_metadata( $item->ID, wp_generate_attachment_metadata( $item->ID, $file ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all attachments without region in their S3 metadata.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_items_to_process() {
|
||||
return (int) $this->get_attachments_with_error_metadata( $this->blog_prefix, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attachments that don't have region in their S3 meta data for a blog
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
$attachments = $this->get_attachments_with_error_metadata( $prefix, false, $limit );
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get S3 attachments that have had their _wp_attachment_metadata corrupted
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param bool|false $count
|
||||
* @param null|int $limit
|
||||
*
|
||||
* @return array|int
|
||||
*/
|
||||
protected function get_attachments_with_error_metadata( $prefix, $count = false, $limit = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "FROM `{$prefix}postmeta` pm1
|
||||
LEFT OUTER JOIN `{$prefix}postmeta` pm2
|
||||
ON pm1.`post_id` = pm2.`post_id`
|
||||
AND pm2.`meta_key` = '_wp_attachment_metadata'
|
||||
WHERE pm1.`meta_key` = 'amazonS3_info'
|
||||
AND pm2.`meta_value` like '%%WP_Error%%'";
|
||||
|
||||
if ( $count ) {
|
||||
$sql = 'SELECT COUNT(*)' . $sql;
|
||||
|
||||
return $wpdb->get_var( $sql );
|
||||
}
|
||||
|
||||
$sql = "SELECT pm1.`post_id` as `ID`, pm1.`meta_value` AS 'provider_object'" . $sql;
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql, OBJECT );
|
||||
}
|
||||
}
|
||||
176
classes/upgrades/upgrade-region-meta.php
Normal file
176
classes/upgrades/upgrade-region-meta.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* Upgrade Region in Meta
|
||||
*
|
||||
* @package amazon-s3-and-cloudfront
|
||||
* @subpackage Classes/Upgrades/Region-Meta
|
||||
* @copyright Copyright (c) 2014, Delicious Brains
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 0.6.2
|
||||
*/
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Error;
|
||||
use AS3CF_Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
||||
|
||||
/**
|
||||
* Upgrade_Region_Meta Class
|
||||
*
|
||||
* This class handles updating the region of the attachment's bucket in the meta data
|
||||
*
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class Upgrade_Region_Meta extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 1;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'meta_with_region';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and updating the metadata with the bucket region it is served from. This will allow us to serve your files from the proper region subdomain <span style="white-space:nowrap;">(e.g. s3-us-west-2.amazonaws.com)</span>.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the region for the bucket where an attachment is located, update the S3 meta.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
$provider_object = AS3CF_Utils::maybe_fix_serialized_string( $item->provider_object );
|
||||
$fixed = $item->provider_object !== $provider_object;
|
||||
|
||||
$provider_object = AS3CF_Utils::maybe_unserialize( $provider_object );
|
||||
|
||||
if ( false === $provider_object ) {
|
||||
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $fixed ) {
|
||||
if ( update_post_meta( $item->ID, 'amazonS3_info', $provider_object ) ) {
|
||||
$msg = sprintf( __( 'Fixed legacy amazonS3_info metadata when updating its region, please check bucket and path for attachment ID %1$s', 'amazon-s3-and-cloudfront' ), $item->ID );
|
||||
AS3CF_Error::log( $msg );
|
||||
} else {
|
||||
AS3CF_Error::log( 'Failed to fix broken serialized legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
||||
$as3cf_item = Media_Library_Item::get_by_source_id( $item->ID );
|
||||
|
||||
if ( ! $as3cf_item ) {
|
||||
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update legacy amazonS3_info record with region required for subsequent upgrades.
|
||||
$provider_object['region'] = $as3cf_item->region();
|
||||
|
||||
$result = update_post_meta( $item->ID, 'amazonS3_info', $provider_object );
|
||||
|
||||
if ( false === $result ) {
|
||||
AS3CF_Error::log( 'Error updating region in legacy offload metadata for attachment ' . $item->ID );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of all attachments without region in their S3 metadata
|
||||
* for the whole site
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_items_to_process() {
|
||||
return $this->count_attachments_without_region( $this->blog_prefix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attachments that don't have region in their S3 meta data for a blog
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
$attachments = $this->get_attachments_without_region_results( $prefix, false, $limit );
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of attachments that don't have region in their S3 meta data for a blog
|
||||
*
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function count_attachments_without_region( $prefix ) {
|
||||
$count = $this->get_attachments_without_region_results( $prefix, true );
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for database call to get attachments without region
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param bool $count return count of attachments
|
||||
* @param null|int $limit
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_attachments_without_region_results( $prefix, $count = false, $limit = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = " FROM `{$prefix}postmeta`
|
||||
WHERE `meta_key` = 'amazonS3_info'
|
||||
AND `meta_value` NOT LIKE '%%\"region\"%%'";
|
||||
|
||||
if ( $count ) {
|
||||
$sql = 'SELECT COUNT(*)' . $sql;
|
||||
|
||||
return $wpdb->get_var( $sql );
|
||||
}
|
||||
|
||||
$sql = "SELECT `post_id` as `ID`, `meta_value` AS 'provider_object'" . $sql;
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql, OBJECT );
|
||||
}
|
||||
}
|
||||
107
classes/upgrades/upgrade-tools-errors.php
Normal file
107
classes/upgrades/upgrade-tools-errors.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Pro\Tool;
|
||||
use DeliciousBrains\WP_Offload_Media\Pro\Tools_Manager;
|
||||
|
||||
/**
|
||||
* Upgrade_Tools_Errors Class
|
||||
*
|
||||
* This class handles updating internal error info from previous tools executions
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
class Upgrade_Tools_Errors extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 9;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'tools_error';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and reformatting internal data about previous errors from tools.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of tool names that may have saved error info
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
global $as3cf;
|
||||
|
||||
if ( get_class( $as3cf ) !== 'Amazon_S3_And_CloudFront_Pro' ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$tools_manager = Tools_Manager::get_instance( $as3cf );
|
||||
$tools = $tools_manager->get_tools();
|
||||
|
||||
return array_keys( $tools );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update saved errors for a tool.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
global $as3cf;
|
||||
|
||||
if ( empty( $item ) || ! is_string( $item ) ) {
|
||||
// We really don't want to this upgrade to fail,
|
||||
// broken notices can still be dismissed, so just move on.
|
||||
return true;
|
||||
}
|
||||
|
||||
$tools_manager = Tools_Manager::get_instance( $as3cf );
|
||||
$tools = $tools_manager->get_tools();
|
||||
|
||||
if ( ! empty( $tools[ $item ] ) ) {
|
||||
/** @var Tool $tool */
|
||||
$tool = $tools[ $item ];
|
||||
|
||||
$errors = $tool->get_errors();
|
||||
$new_errors = array();
|
||||
|
||||
if ( ! empty( $errors ) ) {
|
||||
foreach ( $errors as $blog_id => $blog ) {
|
||||
foreach ( $blog as $attachment_id => $messages ) {
|
||||
$new_errors[] = (object) array(
|
||||
'blog_id' => $blog_id,
|
||||
'source_type' => 'media-library',
|
||||
'source_id' => $attachment_id,
|
||||
'messages' => (array) $messages,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$tool->update_errors( $new_errors );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
107
classes/upgrades/upgrade-wpos3-to-as3cf.php
Normal file
107
classes/upgrades/upgrade-wpos3-to-as3cf.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
||||
|
||||
use AS3CF_Error;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Upgrade_WPOS3_To_AS3CF Class
|
||||
*
|
||||
* This class handles updating records to use as3cf prefixed keys instead of wpos3 prefixed keys.
|
||||
*/
|
||||
class Upgrade_WPOS3_To_AS3CF extends Upgrade {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $upgrade_id = 7;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $upgrade_name = 'wpos3_to_as3cf';
|
||||
|
||||
/**
|
||||
* @var string 'metadata', 'attachment'
|
||||
*/
|
||||
protected $upgrade_type = 'metadata';
|
||||
|
||||
/**
|
||||
* Get running update text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_running_update_text() {
|
||||
return __( 'and updating the metadata to use key names compatible with the current version.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update record key to use as3cf prefix instead of wpos3.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function upgrade_item( $item ) {
|
||||
global $wpdb;
|
||||
|
||||
$old = $item->the_value;
|
||||
$new = substr_replace( $old, 'as3cf_', 0, strlen( 'wpos3_' ) );
|
||||
|
||||
try {
|
||||
$result = $wpdb->update( $wpdb->{$item->the_table}, array( $item->the_field => $new ), array( $item->the_field => $old ) );
|
||||
} catch ( Exception $e ) {
|
||||
AS3CF_Error::log( 'Error updating ' . $item->the_table . ' records with key ' . $old . ' to use key ' . $new . ': ' . $e->getMessage() );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( false === $result || 1 > $result ) {
|
||||
AS3CF_Error::log( 'Incorrect number of ' . $item->the_table . ' records with key ' . $old . ' updated to use key ' . $new . '.' );
|
||||
$this->error_count++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all record keys that need changing.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param int $limit
|
||||
* @param bool|mixed $offset
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "SELECT DISTINCT 'postmeta' AS the_table, 'meta_key' AS the_field, pm.`meta_key` AS the_value
|
||||
FROM `{$prefix}postmeta` pm
|
||||
WHERE pm.`meta_key` LIKE 'wpos3_%'
|
||||
UNION
|
||||
SELECT DISTINCT 'options' AS the_table, 'option_name' AS the_field, o.`option_name` AS the_value
|
||||
FROM `{$prefix}options` o
|
||||
WHERE o.`option_name` LIKE 'wpos3_%'
|
||||
";
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$sql .= "
|
||||
UNION
|
||||
SELECT DISTINCT 'sitemeta' AS the_table, 'meta_key' AS the_field, sm.`meta_key` AS the_value
|
||||
FROM `{$wpdb->sitemeta}` sm
|
||||
WHERE sm.`meta_key` LIKE 'wpos3_%'
|
||||
";
|
||||
}
|
||||
|
||||
if ( $limit && $limit > 0 ) {
|
||||
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
||||
}
|
||||
|
||||
return $wpdb->get_results( $sql, OBJECT );
|
||||
}
|
||||
}
|
||||
1021
classes/upgrades/upgrade.php
Normal file
1021
classes/upgrades/upgrade.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user