From d4087e6caf254c50581494df5a7df441d513c1aa Mon Sep 17 00:00:00 2001 From: Jan Stiegler Date: Wed, 26 Aug 2020 10:42:50 +0200 Subject: [PATCH 01/14] Add post_id to enable-media-replace-upload-done action args --- classes/replacer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/replacer.php b/classes/replacer.php index b9316d8..ae27a80 100644 --- a/classes/replacer.php +++ b/classes/replacer.php @@ -224,7 +224,7 @@ public function replaceWith($file, $fileName) $cache = new emrCache(); $cache->flushCache($cache_args); - do_action("enable-media-replace-upload-done", $this->target_url, $this->source_url); + do_action("enable-media-replace-upload-done", $this->target_url, $this->source_url, $this->post_id); return true; } From 48eddf685c955302de1eea93b5d4c04c116af0c6 Mon Sep 17 00:00:00 2001 From: Farte Razvan Date: Mon, 28 Sep 2020 08:45:57 +0200 Subject: [PATCH 02/14] Update composer.json (#67) * Update composer.json * Update composer.json Wrong format composer.json: missing comma --- composer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/composer.json b/composer.json index 5471b3b..41bc901 100644 --- a/composer.json +++ b/composer.json @@ -1,4 +1,6 @@ { + "name": "short-pixel-optimizer/enable-media-replace", + "description": "A free, lightweight and easy to use WordPress plugin that allows you to seamlessly replace an image or file in your Media Library by uploading a new file in its place.", "repositories": [ { "packagist.org": false, From de584e5aa0ccae27b804b9999933680593419efb Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Tue, 29 Sep 2020 16:17:31 +0000 Subject: [PATCH 03/14] Ability to replace across all WordPress Metadata --- classes/replacer.php | 92 +++++++++++++++++++++++++++-------------- tests/test-replacer.php | 79 ++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 33 deletions(-) diff --git a/classes/replacer.php b/classes/replacer.php index f0e8a82..50b328b 100644 --- a/classes/replacer.php +++ b/classes/replacer.php @@ -530,31 +530,19 @@ protected function doSearchReplace($args = array()) Log::addDebug('Doing meta search and replace -', array($search_urls, $replace_urls) ); Log::addDebug('Searching with BaseuRL ' . $current_base_url); + do_action('emr/replace_urls', $search_urls, $replace_urls); + /* Search and replace in WP_POSTS */ // Removed $wpdb->remove_placeholder_escape from here, not compatible with WP 4.8 $posts_sql = $wpdb->prepare( "SELECT ID, post_content FROM $wpdb->posts WHERE post_status = 'publish' AND post_content LIKE %s;", '%' . $current_base_url . '%'); - // json encodes it all differently. Catch json-like encoded urls - //$json_url = str_replace('/', '\/', ltrim($current_base_url, '/') ); - - $postmeta_sql = 'SELECT meta_id, post_id, meta_key, meta_value FROM ' . $wpdb->postmeta . ' - WHERE post_id in (SELECT ID from '. $wpdb->posts . ' where post_status = "publish") AND meta_value like %s'; - $postmeta_sql = $wpdb->prepare($postmeta_sql, '%' . $current_base_url . '%'); - - // This is a desparate solution. Can't find anyway for wpdb->prepare not the add extra slashes to the query, which messes up the query. -// $postmeta_sql = str_replace('[JSON_URL]', $json_url, $postmeta_sql); - - $rsmeta = $wpdb->get_results($postmeta_sql, ARRAY_A); - $rs = $wpdb->get_results( $posts_sql, ARRAY_A ); - $number_of_updates = 0; - Log::addDebug('Queries', array($postmeta_sql, $posts_sql)); - Log::addDebug('Queries found ' . count($rs) . ' post rows and ' . count($rsmeta) . ' meta rows'); - +// Log::addDebug('Queries', array($postmeta_sql, $posts_sql)); +// Log::addDebug('Queries found ' . count($rs) . ' post rows and ' . count($rsmeta) . ' meta rows'); if ( ! empty( $rs ) ) { foreach ( $rs AS $rows ) { @@ -569,6 +557,8 @@ protected function doSearchReplace($args = array()) if ($post_ar['post_content'] !== $post_content) { + Log::addDebug('POST CONTENT TO SAVE', $post_content); + $result = wp_update_post($post_ar); if (is_wp_error($result)) { @@ -579,25 +569,63 @@ protected function doSearchReplace($args = array()) } } - if (! empty($rsmeta)) - { - foreach ($rsmeta as $row) - { - $number_of_updates++; - $content = $row['meta_value']; - $meta_key = $row['meta_key']; - $post_id = $row['post_id']; - $content = $this->replaceContent($content, $search_urls, $replace_urls); //str_replace($search_urls, $replace_urls, $content); - - update_post_meta($post_id, $meta_key, $content); - // $sql = $wpdb->prepare('UPDATE ' . $wpdb->postmeta . ' SET meta_value = %s WHERE meta_id = %d', $content, $row['meta_id'] ); - // $wpdb->query($sql); - } - } + $this->handleMetaData($current_base_url, $search_urls, $replace_urls); } // doSearchReplace + private function handleMetaData($url, $search_urls, $replace_urls) + { + global $wpdb; + + $meta_options = apply_filters('emr/metadata_tables', array('post')); + $number_of_updates = 0; + + foreach($meta_options as $type) + { + + switch($type) + { + case "post": // special case. + $sql = 'SELECT meta_id, post_id as object_id, meta_key, meta_value FROM ' . $wpdb->postmeta . ' + WHERE post_id in (SELECT ID from '. $wpdb->posts . ' where post_status = "publish") AND meta_value like %s'; + $type = 'post'; + break; + default: + $table = $wpdb->{$type . 'meta'}; // termmeta, commentmeta etc + $id = $type . "_id"; + $sql = 'SELECT meta_id, ' . $id . ' as object_id, meta_key, meta_value FROM ' . $table . ' + WHERE meta_value like %s'; + break; + } + + + $sql = $wpdb->prepare($sql, '%' . $url . '%'); + Log::addTemp("metadata sql ", $sql); + // This is a desparate solution. Can't find anyway for wpdb->prepare not the add extra slashes to the query, which messes up the query. + // $postmeta_sql = str_replace('[JSON_URL]', $json_url, $postmeta_sql); + $rsmeta = $wpdb->get_results($sql, ARRAY_A); + + if (! empty($rsmeta)) + { + foreach ($rsmeta as $row) + { + $number_of_updates++; + $content = $row['meta_value']; + $meta_key = $row['meta_key']; + $object_id = $row['object_id']; + // $type = $row['type']; + $content = $this->replaceContent($content, $search_urls, $replace_urls); //str_replace($search_urls, $replace_urls, $content); + + update_metadata($type, $object_id, $meta_key, $content); + + } + } + } // foreach + + return $number_of_updates; + } // function + private function replaceContent($content, $search, $replace) { //$is_serial = false; @@ -640,7 +668,7 @@ private function replaceContent($content, $search, $replace) { Log::addDebug('Value was found to be JSON, encoding'); // wp-slash -> WP does stripslashes_deep which destroys JSON - $content = (json_encode($content, JSON_UNESCAPED_SLASHES)); + $content = wp_slash(json_encode($content, JSON_UNESCAPED_SLASHES)); Log::addDebug('Content returning', array($content)); } diff --git a/tests/test-replacer.php b/tests/test-replacer.php index 4c1fddb..34807b3 100644 --- a/tests/test-replacer.php +++ b/tests/test-replacer.php @@ -120,10 +120,87 @@ public function testJson() $replacerFunc = $replaceRefl->getMethod('isJSON'); $replacerFunc->setAccessible(true); - $bool = $replacerFunc->invoke(self::$replacer, $content); $this->assertTrue($bool); + //TablesPress + $content = '[["Column A","Info Doc"],["Column B","search . '\">PDF\nsearch . '\">PDF"]]'; + + $expected = '[["Column A","Info Doc"],["Column B","replace . '\">PDF\nreplace . '\">PDF"]]'; + + $result = self::$method->invoke(self::$replacer, $content, $this->search, $this->replace); + $this->assertEquals($expected, $result); + + $bool = $replacerFunc->invoke(self::$replacer, $content); + $this->assertTrue($bool); + + $post_id = $this->factory->post->create(array('name' => 'test1', 'status' => 'publish', 'post_content' => $content)); + wp_update_post(array('ID' => $post_id, 'content' => $content)); + + $post = get_post($post_id); + + $this->assertEquals($content, $post->post_content); + + + } + + public function testMetaDataReplace() + { + $term_id = $this->factory->term->create(array('name' => 'test')); + add_term_meta($term_id, 'test', $this->search); + + $post_id = $this->factory->post->create(array('name' => 'test1', 'status' => 'publish')); + add_post_meta($post_id, 'test', $this->search); + + global $wpdb; + + $search_urls = array($this->search); + $replace_urls = array($this->replace); + + $replaceRefl = new ReflectionClass('\EnableMediaReplace\Replacer'); + $replacerFunc = $replaceRefl->getMethod('handleMetaData'); + $replacerFunc->setAccessible(true); + + // Test without replacing ( empty hook ) + add_filter('emr/metadata_tables', array($this, 'filterNoResults')); + $result = $replacerFunc->invoke(self::$replacer, $this->search, $search_urls, $replace_urls); + remove_filter('emr/metadata_tables', array($this, 'filterNoResults')); + + $this->assertEquals(0, $result); + + // Test both term and post at once. + add_filter('emr/metadata_tables', array($this, 'filterPostAndTerm')); + + $result = $replacerFunc->invoke(self::$replacer, $this->search, $search_urls, $replace_urls); + + $this->assertEquals(2, $result); + + $termtest = get_term_meta($term_id, 'test', true); + $posttest = get_post_meta($post_id, 'test', true); + + $this->assertEquals($this->replace, $termtest); + $this->assertEquals($this->replace, $posttest); + + } + + public function filterNoResults() + { return array(); } + + public function filterPostAndTerm() + { + return array('post', 'term'); + } + + public function testProblematicExamples() + { + + $content = ' +
Table Of Contents
+'; + + $result = self::$method->invoke(self::$replacer, $content, $this->search, $this->replace); + + $this->assertEquals($content, $result); } From a250ff23a870dfc5caf695e36dc0d4ac50621c9e Mon Sep 17 00:00:00 2001 From: Bas Schuiling Date: Wed, 30 Sep 2020 14:23:26 +0000 Subject: [PATCH 04/14] Version 3.5 : * Now works with Elementor * Fixes for JSON and slashes - EMR now uses queries instead of WordPress functions * EMR now replaces across all meta tables * EMR remembers last used settings. * Manual Logging will no longer work if user is not logged as administrator --- build/shortpixel/autoload.php | 1 + build/shortpixel/log/src/ShortPixelLogger.php | 14 ++++++- classes/replacer.php | 41 ++++++++++++------- enable-media-replace.php | 11 ++++- js/emr_admin.js | 2 +- readme.txt | 9 +++- tests/test-replacer.php | 15 +++++-- views/popup.php | 32 +++++++++++---- views/upload.php | 9 ++++ 9 files changed, 102 insertions(+), 32 deletions(-) diff --git a/build/shortpixel/autoload.php b/build/shortpixel/autoload.php index 30909f3..0645fd6 100644 --- a/build/shortpixel/autoload.php +++ b/build/shortpixel/autoload.php @@ -2,3 +2,4 @@ require_once (dirname(__FILE__) . "/PackageLoader.php"); $loader = new EnableMediaReplace\Build\PackageLoader(); $loader->load(__DIR__); + \ No newline at end of file diff --git a/build/shortpixel/log/src/ShortPixelLogger.php b/build/shortpixel/log/src/ShortPixelLogger.php index 884a9d2..e60c955 100644 --- a/build/shortpixel/log/src/ShortPixelLogger.php +++ b/build/shortpixel/log/src/ShortPixelLogger.php @@ -138,6 +138,17 @@ protected function addLog($message, $level, $data = array()) return; } + // Force administrator on manuals. + if ( $this->is_manual_request ) + { + if (! function_exists('wp_get_current_user')) // not loaded yet + return false; + + $user_is_administrator = (current_user_can('manage_options')) ? true : false; + if (! $user_is_administrator) + return false; + } + // Check where to log to. if ($this->logPath === false) { @@ -237,7 +248,7 @@ public static function addWarn($message, $args = array()) $log = self::getInstance(); $log->addLog($message, $level, $args); } - // Alias, since it goes wrong so often. + // Alias, since it goes wrong so often. public static function addWarning($message, $args = array()) { self::addWarn($message, $args); @@ -326,6 +337,7 @@ public function loadView() $controller = $this; $template_path = __DIR__ . '/' . $this->template . '.php'; + // var_dump( $template_path); if (file_exists($template_path)) { diff --git a/classes/replacer.php b/classes/replacer.php index 50b328b..a9aad3a 100644 --- a/classes/replacer.php +++ b/classes/replacer.php @@ -552,15 +552,20 @@ protected function doSearchReplace($args = array()) //$post_content = str_replace( $search_urls, $replace_urls, $post_content ); $post_id = $rows['ID']; - $post_ar = array('ID' => $post_id); - $post_ar['post_content'] = $this->replaceContent($post_content, $search_urls, $replace_urls); + //$post_ar = array('ID' => $post_id); + $replaced_content = $this->replaceContent($post_content, $search_urls, $replace_urls); - if ($post_ar['post_content'] !== $post_content) + if ($replaced_content !== $post_content) { - Log::addDebug('POST CONTENT TO SAVE', $post_content); + Log::addDebug('POST CONTENT TO SAVE', $replaced_content); - $result = wp_update_post($post_ar); - if (is_wp_error($result)) + // $result = wp_update_post($post_ar); + $sql = 'UPDATE ' . $wpdb->posts . ' SET post_content = %s WHERE ID = %d'; + $sql = $wpdb->prepare($sql, $replaced_content, $post_id); + + $result = $wpdb->query($sql); + + if ($result === false) { Notice::addError('Something went wrong while replacing' . $result->get_error_message() ); Log::addError('WP-Error during post update', $result); @@ -578,7 +583,7 @@ private function handleMetaData($url, $search_urls, $replace_urls) { global $wpdb; - $meta_options = apply_filters('emr/metadata_tables', array('post')); + $meta_options = apply_filters('emr/metadata_tables', array('post', 'comment', 'term', 'user')); $number_of_updates = 0; foreach($meta_options as $type) @@ -587,21 +592,23 @@ private function handleMetaData($url, $search_urls, $replace_urls) switch($type) { case "post": // special case. - $sql = 'SELECT meta_id, post_id as object_id, meta_key, meta_value FROM ' . $wpdb->postmeta . ' + $sql = 'SELECT meta_id as id, meta_value FROM ' . $wpdb->postmeta . ' WHERE post_id in (SELECT ID from '. $wpdb->posts . ' where post_status = "publish") AND meta_value like %s'; $type = 'post'; + $update_sql = ' UPDATE ' . $wpdb->postmeta . ' SET meta_value = %s WHERE meta_id = %d'; break; default: $table = $wpdb->{$type . 'meta'}; // termmeta, commentmeta etc $id = $type . "_id"; - $sql = 'SELECT meta_id, ' . $id . ' as object_id, meta_key, meta_value FROM ' . $table . ' + $sql = 'SELECT meta_id as id, meta_value FROM ' . $table . ' WHERE meta_value like %s'; + + $update_sql = " UPDATE $table set meta_value = %s WHERE meta_id = %d "; break; } - $sql = $wpdb->prepare($sql, '%' . $url . '%'); - Log::addTemp("metadata sql ", $sql); + // This is a desparate solution. Can't find anyway for wpdb->prepare not the add extra slashes to the query, which messes up the query. // $postmeta_sql = str_replace('[JSON_URL]', $json_url, $postmeta_sql); $rsmeta = $wpdb->get_results($sql, ARRAY_A); @@ -612,12 +619,16 @@ private function handleMetaData($url, $search_urls, $replace_urls) { $number_of_updates++; $content = $row['meta_value']; - $meta_key = $row['meta_key']; - $object_id = $row['object_id']; + //$meta_key = $row['meta_key']; + //$object_id = $row['object_id']; + $id = $row['id']; // $type = $row['type']; $content = $this->replaceContent($content, $search_urls, $replace_urls); //str_replace($search_urls, $replace_urls, $content); - update_metadata($type, $object_id, $meta_key, $content); + // update_metadata($type, $object_id, $meta_key, $content); + $update_sql = $wpdb->prepare($update_sql, $content, $id); + Log::addDebug('Update Meta SQl' . $update_sql); + $result = $wpdb->query($update_sql); } } @@ -668,7 +679,7 @@ private function replaceContent($content, $search, $replace) { Log::addDebug('Value was found to be JSON, encoding'); // wp-slash -> WP does stripslashes_deep which destroys JSON - $content = wp_slash(json_encode($content, JSON_UNESCAPED_SLASHES)); + $content = json_encode($content, JSON_UNESCAPED_SLASHES); Log::addDebug('Content returning', array($content)); } diff --git a/enable-media-replace.php b/enable-media-replace.php index f33c122..b00cb5d 100644 --- a/enable-media-replace.php +++ b/enable-media-replace.php @@ -3,7 +3,7 @@ Plugin Name: Enable Media Replace Plugin URI: https://wordpress.org/plugins/enable-media-replace/ Description: Enable replacing media files by uploading a new file in the "Edit Media" section of the WordPress Media Library -Version: 3.4.2-DEV02 +Version: 3.5 Author: ShortPixel Author URI: https://shortpixel.com Text Domain: enable-media-replace @@ -26,7 +26,7 @@ namespace EnableMediaReplace; -define('EMR_VERSION', '3.4.2-DEV02'); +define('EMR_VERSION', '3.5'); if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. @@ -59,3 +59,10 @@ require_once($plugin_path . 'thumbnail_updater.php'); $emr_plugin = EnableMediaReplacePlugin::get(); + +register_uninstall_hook(__FILE__, 'emr_uninstall'); + +function emr_uninstall() +{ + delete_option('enable_media_replace'); +} diff --git a/js/emr_admin.js b/js/emr_admin.js index 2bf6928..56f2d33 100644 --- a/js/emr_admin.js +++ b/js/emr_admin.js @@ -101,7 +101,7 @@ var status = this.checkUpload(file); this.debug('check upload status ' + status); - this.debug(file.size); + this.debug('file size:' + file.size); if (status) { diff --git a/readme.txt b/readme.txt index ba50d1e..39bc361 100644 --- a/readme.txt +++ b/readme.txt @@ -5,7 +5,7 @@ Tags: replace, attachment, media, files, replace image, replace jpg, change medi Requires at least: 4.9.7 Tested up to: 5.5 Requires PHP: 5.6 -Stable tag: 3.4.2 +Stable tag: 3.5 Easily replace any attached image/file by simply uploading a new file in the Media Library edit view - a real time saver! @@ -47,6 +47,13 @@ If you want more control over the format used to display the time, you can use t == Changelog == += 3.5 = + +* Now works with Elementor +* Fixes for JSON and slashes - EMR now uses queries instead of WordPress functions +* EMR now replaces across all meta tables +* EMR remembers last used settings. +* Manual Logging will no longer work if user is not logged as administrator = 3.4.2 = diff --git a/tests/test-replacer.php b/tests/test-replacer.php index 34807b3..abd1a28 100644 --- a/tests/test-replacer.php +++ b/tests/test-replacer.php @@ -108,6 +108,8 @@ public function testSerialized() public function testJson() { + global $wpdb; + $content = '[["search . '\" alt=\"\" width=\"640\" height=\"426\" class=\"alignnone size-large wp-image-1448\" />","","","",""],["search . '\" alt=\"\" width=\"640\" height=\"853\" class=\"alignnone size-large wp-image-621\" />","","","",""],["","","","",""],["","","","",""],["","","","",""]]'; $expected = '[["replace . '\" alt=\"\" width=\"640\" height=\"426\" class=\"alignnone size-large wp-image-1448\" />","","","",""],["replace . '\" alt=\"\" width=\"640\" height=\"853\" class=\"alignnone size-large wp-image-621\" />","","","",""],["","","","",""],["","","","",""],["","","","",""]]'; @@ -134,12 +136,17 @@ public function testJson() $bool = $replacerFunc->invoke(self::$replacer, $content); $this->assertTrue($bool); - $post_id = $this->factory->post->create(array('name' => 'test1', 'status' => 'publish', 'post_content' => $content)); - wp_update_post(array('ID' => $post_id, 'content' => $content)); + $post_id = $this->factory->post->create(array('name' => 'test1', 'status' => 'publish', 'post_content' => $result)); + //wp_update_post(array('ID' => $post_id, 'post_content' => $result )); + $sql = 'UPDATE ' . $wpdb->posts . ' SET post_content = %s WHERE ID = %d'; + $sql = $wpdb->prepare($sql, $result, $post_id); + $q = $wpdb->query($sql); + $post = get_post($post_id); // somehow get_post still fucks with the content - $post = get_post($post_id); + $sql = 'SELECT * FROM ' . $wpdb->posts . ' where ID = ' . $post_id; + $sqlresult = $wpdb->get_results($sql); - $this->assertEquals($content, $post->post_content); + $this->assertEquals($result, $sqlresult[0]->post_content); } diff --git a/views/popup.php b/views/popup.php index cb5525d..811fd6b 100644 --- a/views/popup.php +++ b/views/popup.php @@ -42,7 +42,14 @@ $emr = EnableMediaReplacePlugin::get(); - +$defaults = array( + 'replace_type' => 'replace', + 'timestamp_replace' => \EnableMediaReplace\Replacer::TIME_UPDATEMODIFIED, + 'custom_date' => date("Y-m-d H:i:s"), + 'new_location' => false, + 'new_location_dir' => false, +); +$settings = get_option('enable_media_replace', $defaults); ?> @@ -122,7 +129,7 @@ $search_disabled = (! $enabled_search) ? 'disabled' : ''; ?>
-