Enable Media Replace - Version 3.3.3

Version Description

Release date: 19th July 2019 * Fix error "using $this when not in object context" on some PHP versions

Download this release

Release Info

Developer ShortPixel
Plugin Icon 128x128 Enable Media Replace
Version 3.3.3
Comparing to
See all releases

Code changes from version 3.3.1 to 3.3.3

build/shortpixel/PackageLoader.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace\Build;
3
+
4
+ class PackageLoader
5
+ {
6
+ public $dir;
7
+
8
+ public function getComposerFile()
9
+ {
10
+ return json_decode(file_get_contents($this->dir."/composer.json"), 1);
11
+ }
12
+
13
+ public function load($dir)
14
+ {
15
+ $this->dir = $dir;
16
+ $composer = $this->getComposerFile();
17
+ if(isset($composer["autoload"]["psr-4"])){
18
+ $this->loadPSR4($composer['autoload']['psr-4']);
19
+ }
20
+ if(isset($composer["autoload"]["psr-0"])){
21
+ $this->loadPSR0($composer['autoload']['psr-0']);
22
+ }
23
+ if(isset($composer["autoload"]["files"])){
24
+ $this->loadFiles($composer["autoload"]["files"]);
25
+ }
26
+ }
27
+
28
+ public function loadFiles($files){
29
+ foreach($files as $file){
30
+ $fullpath = $this->dir."/".$file;
31
+ if(file_exists($fullpath)){
32
+ include_once($fullpath);
33
+ }
34
+ }
35
+ }
36
+
37
+ public function loadPSR4($namespaces)
38
+ {
39
+ $this->loadPSR($namespaces, true);
40
+ }
41
+
42
+ public function loadPSR0($namespaces)
43
+ {
44
+ $this->loadPSR($namespaces, false);
45
+ }
46
+
47
+ public function loadPSR($namespaces, $psr4)
48
+ {
49
+ $dir = $this->dir;
50
+ // Foreach namespace specified in the composer, load the given classes
51
+ foreach ($namespaces as $namespace => $classpaths) {
52
+ if (!is_array($classpaths)) {
53
+ $classpaths = array($classpaths);
54
+ }
55
+ spl_autoload_register(function ($classname) use ($namespace, $classpaths, $dir, $psr4) {
56
+ // Check if the namespace matches the class we are looking for
57
+ if (preg_match("#^".preg_quote($namespace)."#", $classname)) {
58
+ // Remove the namespace from the file path since it's psr4
59
+ if ($psr4) {
60
+ $classname = str_replace($namespace, "", $classname);
61
+ }
62
+ $filename = preg_replace("#\\\\#", "/", $classname).".php";
63
+ foreach ($classpaths as $classpath) {
64
+ $fullpath = $dir."/".$classpath."/$filename";
65
+ if (file_exists($fullpath)) {
66
+ include_once $fullpath;
67
+ }
68
+ }
69
+ }
70
+ });
71
+ }
72
+ }
73
+ }
build/shortpixel/autoload.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+ require_once "PackageLoader.php";
3
+ $loader = new EnableMediaReplace\Build\PackageLoader();
4
+ $loader->load(__DIR__);
5
+
build/shortpixel/composer.json ADDED
@@ -0,0 +1 @@
 
1
+ {"name":"EnableMediaReplace\/shortpixelmodules","description":"ShortPixel submodules","type":"function","autoload":{"psr-4":{"EnableMediaReplace\\ShortPixelLogger\\":"log\/src\/","EnableMediaReplace\\Notices\\":"notices\/src\/"}}}
build/shortpixel/log/composer.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "shortpixel/log",
3
+ "description": "ShortPixel Logging",
4
+ "version": "1.1",
5
+ "type": "library",
6
+ "license": "MIT",
7
+ "authors": [
8
+ {
9
+ "name": "Bas",
10
+ "email": "bas@weblogmechanic.com"
11
+ }
12
+ ],
13
+ "minimum-stability": "dev",
14
+ "require": {},
15
+ "autoload": {
16
+ "psr-4": { "ShortPixel\\ShortPixelLogger\\" : "src/" }
17
+ }
18
+ }
build/shortpixel/log/src/DebugItem.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // The data models.
3
+ namespace EnableMediaReplace\ShortPixelLogger;
4
+
5
+
6
+ class DebugItem
7
+ {
8
+ protected $time;
9
+ protected $level;
10
+ protected $message;
11
+ protected $data = array();
12
+ protected $caller = false; // array when filled
13
+
14
+ protected $model;
15
+
16
+ const LEVEL_ERROR = 1;
17
+ const LEVEL_WARN = 2;
18
+ const LEVEL_INFO = 3;
19
+ const LEVEL_DEBUG = 4;
20
+
21
+ public function __construct($message, $args)
22
+ {
23
+ $this->level = $args['level'];
24
+ $data = $args['data'];
25
+
26
+ $this->message = $message;
27
+ $this->time = microtime(true);
28
+
29
+ $this->setCaller();
30
+
31
+ // Add message to data if it seems to be some debug variable.
32
+ if (is_object($this->message) || is_array($this->message))
33
+ {
34
+ $data[] = $this->message;
35
+ $this->message = __('[Data]');
36
+ }
37
+ if (is_array($data) && count($data) > 0)
38
+ {
39
+ $dataType = $this->getDataType($data);
40
+ if ($dataType == 1) // singular
41
+ {
42
+ $this->data[] = print_r($data, true);
43
+ }
44
+ if ($dataType == 2) //array
45
+ {
46
+ foreach($data as $index => $item)
47
+ {
48
+ if (is_object($item) || is_array($item))
49
+ {
50
+ $this->data[] = print_r($item, true);
51
+ }
52
+ }
53
+ }
54
+ } // if
55
+ elseif (! is_array($data)) // this leaves out empty default arrays
56
+ {
57
+ $this->data[] = print_r($data, true);
58
+ }
59
+ }
60
+
61
+ public function getData()
62
+ {
63
+ return array('time' => $this->time, 'level' => $this->level, 'message' => $this->message, 'data' => $this->data, 'caller' => $this->caller);
64
+ }
65
+
66
+ /** Test Data Array for possible values
67
+ *
68
+ * Data can be a collection of several debug vars, a single var, or just an normal array. Test if array has single types,
69
+ * which is a sign the array is not a collection.
70
+ */
71
+ protected function getDataType($data)
72
+ {
73
+ $single_type = array('integer', 'boolean', 'string');
74
+ if (in_array(gettype(reset($data)), $single_type))
75
+ {
76
+ return 1;
77
+ }
78
+ else
79
+ {
80
+ return 2;
81
+ }
82
+ }
83
+
84
+ public function getForFormat()
85
+ {
86
+ $data = $this->getData();
87
+ switch($this->level)
88
+ {
89
+ case self::LEVEL_ERROR:
90
+ $level = 'ERR';
91
+ $color = "\033[31m";
92
+ break;
93
+ case self::LEVEL_WARN:
94
+ $level = 'WRN';
95
+ $color = "\033[33m";
96
+ break;
97
+ case self::LEVEL_INFO:
98
+ $level = 'INF';
99
+ $color = "\033[37m";
100
+ break;
101
+ case self::LEVEL_DEBUG:
102
+ $level = 'DBG';
103
+ $color = "\033[37m";
104
+ break;
105
+
106
+ }
107
+ $color_end = "\033[0m";
108
+
109
+ $data['color'] = $color;
110
+ $data['color_end'] = $color_end;
111
+ $data['level'] = $level;
112
+
113
+ return $data;
114
+
115
+ //return array('time' => $this->time, 'level' => $level, 'message' => $this->message, 'data' => $this->data, 'color' => $color, 'color_end' => $color_end, 'caller' => $this->caller);
116
+
117
+ }
118
+
119
+ protected function setCaller()
120
+ {
121
+ if(PHP_VERSION_ID < 50400) {
122
+ $debug=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
123
+ } else {
124
+ $debug=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,5);
125
+ }
126
+
127
+ $i = 4;
128
+ if (isset($debug[$i]))
129
+ {
130
+ $info = $debug[$i];
131
+ $line = isset($info['line']) ? $info['line'] : 'Line unknown';
132
+ $file = isset($info['file']) ? basename($info['file']) : 'File not set';
133
+
134
+ $this->caller = array('line' => $line, 'file' => $file, 'function' => $info['function']);
135
+ }
136
+
137
+
138
+ }
139
+
140
+
141
+ }
build/shortpixel/log/src/ShortPixelLogger.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace\ShortPixelLogger;
3
+
4
+ /*** Logger class
5
+ *
6
+ * Class uses the debug data model for keeping log entries.
7
+ * Logger should not be called before init hook!
8
+ */
9
+ class ShortPixelLogger
10
+ {
11
+ static protected $instance = null;
12
+ protected $start_time;
13
+
14
+ protected $is_active = false;
15
+ protected $is_manual_request = false;
16
+ protected $show_debug_view = false;
17
+
18
+ protected $items = array();
19
+ protected $logPath = false;
20
+ protected $logMode = FILE_APPEND;
21
+
22
+ protected $logLevel;
23
+ protected $format = "[ %%time%% ] %%color%% %%level%% %%color_end%% \t %%message%% \t %%caller%% ( %%time_passed%% )";
24
+ protected $format_data = "\t %%data%% ";
25
+
26
+ protected $hooks = array();
27
+ /* protected $hooks = array(
28
+ 'shortpixel_image_exists' => array('numargs' => 3),
29
+ 'shortpixel_webp_image_base' => array('numargs' => 2),
30
+ 'shortpixel_image_urls' => array('numargs' => 2),
31
+ ); // @todo monitor hooks, but this should be more dynamic. Do when moving to module via config.
32
+ */
33
+
34
+ // utility
35
+ private $namespace;
36
+ private $view;
37
+
38
+ protected $template = 'view-debug-box';
39
+
40
+ /** Debugger constructor
41
+ * Two ways to activate the debugger. 1) Define SHORTPIXEL_DEBUG in wp-config.php. Either must be true or a number corresponding to required LogLevel
42
+ * 2) Put SHORTPIXEL_DEBUG in the request. Either true or number.
43
+ */
44
+ public function __construct()
45
+ {
46
+ $this->start_time = microtime(true);
47
+ $this->logLevel = DebugItem::LEVEL_WARN;
48
+
49
+ $ns = __NAMESPACE__;
50
+ $this->namespace = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace
51
+
52
+ if ($this->logPath === false)
53
+ {
54
+ $upload_dir = wp_upload_dir(null,false,false);
55
+ $this->logPath = $upload_dir['basedir'] . '/' . $this->namespace . ".log";
56
+ }
57
+
58
+ if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants
59
+ {
60
+ $this->is_manual_request = true;
61
+ $this->is_active = true;
62
+
63
+ if ($_REQUEST['SHORTPIXEL_DEBUG'] === 'true')
64
+ {
65
+ $this->logLevel = DebugItem::LEVEL_INFO;
66
+ }
67
+ else {
68
+ $this->logLevel = intval($_REQUEST['SHORTPIXEL_DEBUG']);
69
+ }
70
+
71
+ }
72
+ else if ( (defined('SHORTPIXEL_DEBUG') && SHORTPIXEL_DEBUG > 0) )
73
+ {
74
+ $this->is_active = true;
75
+ if (SHORTPIXEL_DEBUG === true)
76
+ $this->logLevel = DebugItem::LEVEL_INFO;
77
+ else {
78
+ $this->logLevel = intval(SHORTPIXEL_DEBUG);
79
+ }
80
+ }
81
+
82
+ if (defined('SHORTPIXEL_DEBUG_TARGET') && SHORTPIXEL_DEBUG_TARGET || $this->is_manual_request)
83
+ {
84
+ //$this->logPath = SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log";
85
+ //$this->logMode = defined('SHORTPIXEL_LOG_OVERWRITE') ? 0 : FILE_APPEND;
86
+ if (defined('SHORTPIXEL_LOG_OVERWRITE')) // if overwrite, do this on init once.
87
+ file_put_contents($this->logPath,'-- Log Reset -- ' .PHP_EOL);
88
+
89
+ }
90
+
91
+ /* On Early init, this function might not exist, then queue it when needed */
92
+ if (! function_exists('wp_get_current_user'))
93
+ add_action('plugins_loaded', array($this, 'initView'));
94
+ else
95
+ $this->initView();
96
+
97
+
98
+ if ($this->is_active && count($this->hooks) > 0)
99
+ $this->monitorHooks();
100
+ }
101
+
102
+ /** Init the view when needed. Private function ( public because of WP_HOOK )
103
+ * Never call directly */
104
+ public function initView()
105
+ {
106
+ $user_is_administrator = (current_user_can('manage_options')) ? true : false;
107
+
108
+ if ($this->is_active && $this->is_manual_request && $user_is_administrator )
109
+ {
110
+ $content_url = content_url();
111
+ $logPath = $this->logPath;
112
+ $pathpos = strpos($logPath, 'wp-content') + strlen('wp-content');
113
+ $logPart = substr($logPath, $pathpos);
114
+ $logLink = $content_url . $logPart;
115
+
116
+ $this->view = new \stdClass;
117
+ $this->view->logLink = $logLink;
118
+ add_action('admin_footer', array($this, 'loadView'));
119
+ }
120
+ }
121
+
122
+ public static function getInstance()
123
+ {
124
+ if ( self::$instance === null)
125
+ {
126
+ self::$instance = new ShortPixelLogger();
127
+ }
128
+ return self::$instance;
129
+ }
130
+
131
+ public function setLogPath($logPath)
132
+ {
133
+ $this->logPath = $logPath;
134
+ }
135
+ protected static function addLog($message, $level, $data = array())
136
+ {
137
+ $log = self::getInstance();
138
+
139
+ // don't log anything too low.
140
+ if ($log->logLevel < $level)
141
+ {
142
+ return;
143
+ }
144
+
145
+ $arg = array();
146
+ $args['level'] = $level;
147
+ $args['data'] = $data;
148
+
149
+ $newItem = new DebugItem($message, $args);
150
+ $log->items[] = $newItem;
151
+
152
+ if ($log->is_active)
153
+ {
154
+ $log->write($newItem);
155
+ }
156
+ }
157
+
158
+ /** Writes to log File. */
159
+ protected function write($debugItem, $mode = 'file')
160
+ {
161
+ $items = $debugItem->getForFormat();
162
+ $items['time_passed'] = round ( ($items['time'] - $this->start_time), 5);
163
+ $items['time'] = date('Y-m-d H:i:s', $items['time'] );
164
+
165
+ if ( ($items['caller']) && is_array($items['caller']) && count($items['caller']) > 0)
166
+ {
167
+ $caller = $items['caller'];
168
+ $items['caller'] = $caller['file'] . ' in ' . $caller['function'] . '(' . $caller['line'] . ')';
169
+ }
170
+
171
+ $line = $this->formatLine($items);
172
+
173
+ if ($this->logPath)
174
+ {
175
+ file_put_contents($this->logPath,$line, FILE_APPEND);
176
+ }
177
+ else {
178
+ error_log($line);
179
+ }
180
+ }
181
+
182
+ protected function formatLine($args = array() )
183
+ {
184
+ $line= $this->format;
185
+ foreach($args as $key => $value)
186
+ {
187
+ if (! is_array($value) && ! is_object($value))
188
+ $line = str_replace('%%' . $key . '%%', $value, $line);
189
+ }
190
+
191
+ $line .= PHP_EOL;
192
+
193
+ if (isset($args['data']))
194
+ {
195
+ $data = array_filter($args['data']);
196
+ if (count($data) > 0)
197
+ {
198
+ foreach($data as $item)
199
+ {
200
+ $line .= $item . PHP_EOL;
201
+ }
202
+ }
203
+ }
204
+
205
+ return $line;
206
+ }
207
+
208
+ protected function setLogLevel($level)
209
+ {
210
+ $this->logLevel = $level;
211
+ }
212
+
213
+ protected function getEnv($name)
214
+ {
215
+ if (isset($this->{$name}))
216
+ {
217
+ return $this->{$name};
218
+ }
219
+ else {
220
+ return false;
221
+ }
222
+ }
223
+
224
+ public static function addError($message, $args = array())
225
+ {
226
+ $level = DebugItem::LEVEL_ERROR;
227
+ static::addLog($message, $level, $args);
228
+ }
229
+ public static function addWarn($message, $args = array())
230
+ {
231
+ $level = DebugItem::LEVEL_WARN;
232
+ static::addLog($message, $level, $args);
233
+ }
234
+ public static function addInfo($message, $args = array())
235
+ {
236
+ $level = DebugItem::LEVEL_INFO;
237
+ static::addLog($message, $level, $args);
238
+ }
239
+ public static function addDebug($message, $args = array())
240
+ {
241
+ $level = DebugItem::LEVEL_DEBUG;
242
+ static::addLog($message, $level, $args);
243
+ }
244
+
245
+ public static function logLevel($level)
246
+ {
247
+ $log = self::getInstance();
248
+ static::addInfo('Changing Log level' . $level);
249
+ $log->setLogLevel($level);
250
+ }
251
+
252
+ public static function getLogLevel()
253
+ {
254
+ $log = self::getInstance();
255
+ return $log->getEnv('logLevel');
256
+ }
257
+
258
+ public static function isManualDebug()
259
+ {
260
+ $log = self::getInstance();
261
+ return $log->getEnv('is_manual_request');
262
+ }
263
+
264
+ public static function getLogPath()
265
+ {
266
+ $log = self::getInstance();
267
+ return $log->getEnv('logPath');
268
+ }
269
+
270
+ /** Function to test if the debugger is active
271
+ * @return boolean true when active.
272
+ */
273
+ public static function debugIsActive()
274
+ {
275
+ $log = self::getInstance();
276
+ return $log->getEnv('is_active');
277
+ }
278
+
279
+ protected function monitorHooks()
280
+ {
281
+
282
+ foreach($this->hooks as $hook => $data)
283
+ {
284
+ $numargs = isset($data['numargs']) ? $data['numargs'] : 1;
285
+ $prio = isset($data['priority']) ? $data['priority'] : 10;
286
+
287
+ add_filter($hook, function($value) use ($hook) {
288
+ $args = func_get_args();
289
+ return $this->logHook($hook, $value, $args); }, $prio, $numargs);
290
+ }
291
+ }
292
+
293
+ public function logHook($hook, $value, $args)
294
+ {
295
+ array_shift($args);
296
+ self::addInfo('[Hook] - ' . $hook . ' with ' . var_export($value,true), $args);
297
+ return $value;
298
+ }
299
+
300
+ public function loadView()
301
+ {
302
+ // load either param or class template.
303
+ $template = $this->template;
304
+
305
+ $view = $this->view;
306
+ $view->namespace = $this->namespace;
307
+ $controller = $this;
308
+
309
+ $template_path = __DIR__ . '/' . $this->template . '.php';
310
+ if (file_exists($template_path))
311
+ {
312
+
313
+ include($template_path);
314
+ }
315
+ else {
316
+ self::addError("View $template could not be found in " . $template_path,
317
+ array('class' => get_class($this), 'req' => $_REQUEST));
318
+ }
319
+ }
320
+
321
+
322
+ } // class debugController
build/shortpixel/log/src/view-debug-box.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Debug Box to load Log File
3
+ namespace EnableMediaReplace\ShortPixelLogger;
4
+ wp_enqueue_script( 'jquery-ui-draggable' );
5
+
6
+ ?>
7
+
8
+ <style>
9
+ .sp_debug_wrap
10
+ {
11
+ position: relative;
12
+ clear: both;
13
+ }
14
+ .sp_debug_box
15
+ {
16
+ position: absolute;
17
+ right: 0px;
18
+ top: 50px;
19
+ background-color: #fff;
20
+ width: 150px;
21
+ z-index: 1000000;
22
+ border: 1px solid #000;
23
+
24
+ }
25
+ .sp_debug_box .header
26
+ {
27
+ min-height: 10px;
28
+ background: #000;
29
+ color: #fff;
30
+ padding: 8px
31
+ }
32
+ .sp_debug_box .content_box
33
+ {
34
+ background: #ccc;
35
+ }
36
+ .content_box
37
+ {
38
+ padding: 8px;
39
+ }
40
+ </style>
41
+
42
+ <script language='javascript'>
43
+ jQuery(document).ready(function($)
44
+ {
45
+ $( ".sp_debug_box" ).draggable();
46
+
47
+ });
48
+ </script>
49
+
50
+
51
+ <div class='sp_debug_box'>
52
+ <div class='header'><?php echo $view->namespace ?> Debug Box </div>
53
+ <a target="_blank" href='<?php echo $view->logLink ?>'>Logfile</a>
54
+ <div class='content_box'>
55
+
56
+ </div>
57
+ </div>
build/shortpixel/notices/composer.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "shortpixel/notices",
3
+ "description": "ShortPixel WordPress Notice System",
4
+ "version": "1.1",
5
+ "type": "library",
6
+ "license": "MIT",
7
+ "authors": [
8
+ {
9
+ "name": "Bas",
10
+ "email": "bas@weblogmechanic.com"
11
+ }
12
+ ],
13
+ "minimum-stability": "dev",
14
+ "require": {
15
+ "shortpixel/log" : "1.1.*"
16
+ },
17
+ "repositories": [
18
+ {
19
+ "packagist.org": false,
20
+ "type": "path",
21
+ "url": "../modules/",
22
+ "options": {
23
+ "symlink": true
24
+ }
25
+ }
26
+ ],
27
+
28
+ "autoload": {
29
+ "psr-4": { "ShortPixel\\Notices\\" : "src/" }
30
+ }
31
+ }
build/shortpixel/notices/src/NoticeController.php ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace\Notices;
3
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
4
+
5
+ class NoticeController //extends ShortPixelController
6
+ {
7
+ protected static $notices = array();
8
+ protected static $instance = null;
9
+ protected static $cssHookLoaded = false; // prevent css output more than once.
10
+
11
+ public $notice_count = 0;
12
+
13
+ protected $has_stored = false;
14
+
15
+ protected $notice_option = ''; // The wp_options name for notices here.
16
+
17
+ /** For backward compat. Never call constructor directly. */
18
+ public function __construct()
19
+ {
20
+ // $this->loadModel('notice');
21
+ $ns = __NAMESPACE__;
22
+ $ns = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace
23
+ $this->notice_option = $ns . '-notices';
24
+
25
+ $this->loadNotices();
26
+ //$this->loadConfig();
27
+ }
28
+
29
+ /** Load Notices Config File, if any
30
+ *
31
+ * [ Future Use ]
32
+ */
33
+ public function loadConfig()
34
+ {
35
+ if (file_exists('../notice_config.json'))
36
+ {
37
+ $config = file_get_contents('../notice_config.json');
38
+ $json_config = json_decode($config);
39
+ }
40
+ }
41
+
42
+ public function loadIcons($icons)
43
+ {
44
+ foreach($icons as $name => $icon)
45
+ NoticeModel::setIcon($name, $icon);
46
+ }
47
+
48
+
49
+ protected function loadNotices()
50
+ {
51
+ $notices = get_option($this->notice_option, false);
52
+ $cnotice = (is_array($notices)) ? count($notices) : 0;
53
+ Log::addDebug('Notice Control - #num notices' . $cnotice);
54
+ if ($notices !== false)
55
+ {
56
+ self::$notices = $notices;
57
+ $this->has_stored = true;
58
+ }
59
+ else {
60
+ self::$notices = array();
61
+ $this->has_stored = false;
62
+ }
63
+ $this->countNotices();
64
+ }
65
+
66
+
67
+ public function addNotice($message, $code)
68
+ {
69
+ $notice = new NoticeModel($message, $code);
70
+ self::$notices[] = $notice;
71
+ $this->countNotices();
72
+ Log::addDebug('Adding notice - ', $notice);
73
+ $this->update();
74
+ return $notice;
75
+ }
76
+
77
+ /** Update the notices to store, check what to remove, returns count. */
78
+ public function update()
79
+ {
80
+ if (! is_array(self::$notices) || count(self::$notices) == 0)
81
+ {
82
+ if ($this->has_stored)
83
+ delete_option($this->notice_option);
84
+
85
+ return 0;
86
+ }
87
+
88
+ $new_notices = array();
89
+ foreach(self::$notices as $item)
90
+ {
91
+ if (! $item->isDone() )
92
+ {
93
+ $new_notices[] = $item;
94
+ }
95
+ }
96
+
97
+ update_option($this->notice_option, $new_notices);
98
+ self::$notices = $new_notices;
99
+
100
+ return $this->countNotices();
101
+ }
102
+
103
+ public function countNotices()
104
+ {
105
+ $this->notice_count = count(self::$notices);
106
+ return $this->notice_count;
107
+ }
108
+
109
+
110
+ public function getNotices()
111
+ {
112
+ return self::$notices;
113
+ }
114
+
115
+ public static function getInstance()
116
+ {
117
+ if ( self::$instance === null)
118
+ {
119
+ self::$instance = new NoticeController();
120
+ }
121
+
122
+ return self::$instance;
123
+ }
124
+
125
+ /** Adds a notice, quick and fast method
126
+ * @param String $message The Message you want to notify
127
+ * @param int $code A value of messageType as defined in model
128
+ * @returm Object Instance of noticeModel
129
+ */
130
+
131
+ public static function addNormal($message)
132
+ {
133
+ $noticeController = self::getInstance();
134
+ $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_NORMAL);
135
+ return $notice;
136
+
137
+ }
138
+
139
+ public static function addError($message)
140
+ {
141
+ $noticeController = self::getInstance();
142
+ $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_ERROR);
143
+ return $notice;
144
+
145
+ }
146
+
147
+ public static function addWarning($message)
148
+ {
149
+ $noticeController = self::getInstance();
150
+ $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_WARNING);
151
+ return $notice;
152
+
153
+ }
154
+
155
+ public static function addSuccess($message)
156
+ {
157
+ $noticeController = self::getInstance();
158
+ $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_SUCCESS);
159
+ return $notice;
160
+
161
+ }
162
+
163
+ public function admin_notices()
164
+ {
165
+ if ($this->countNotices() > 0)
166
+ {
167
+ if (! self::$cssHookLoaded)
168
+ {
169
+ add_action('admin_print_footer_scripts', array($this, 'printNoticeStyle'));
170
+ self::$cssHookLoaded = true;
171
+ }
172
+ foreach($this->getNotices() as $notice)
173
+ {
174
+ echo $notice->getForDisplay();
175
+ }
176
+ }
177
+ $this->update(); // puts views, and updates
178
+ }
179
+
180
+ public function printNoticeStyle()
181
+ {
182
+ if (file_exists(__DIR__ . '/css/notices.css'))
183
+ {
184
+ echo '<style>' . file_get_contents(__DIR__ . '/css/notices.css') . '</style>';
185
+ }
186
+ else {
187
+ Log::addDebug('Notices : css/notices.css could not be loaded');
188
+ }
189
+ }
190
+
191
+
192
+
193
+
194
+ }
build/shortpixel/notices/src/NoticeModel.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace\Notices;
3
+
4
+ class NoticeModel //extends ShortPixelModel
5
+ {
6
+ protected $message;
7
+ public $code;
8
+
9
+ protected $viewed = false;
10
+ public $is_persistent = false; // This is a fatal issue, display until something was fixed.
11
+ public $is_removable = true; // if removable, display a notice dialog with red X or so.
12
+ public $messageType = self::NOTICE_NORMAL;
13
+
14
+ public static $icons = array();
15
+
16
+ const NOTICE_NORMAL = 1;
17
+ const NOTICE_ERROR = 2;
18
+ const NOTICE_SUCCESS = 3;
19
+ const NOTICE_WARNING = 4;
20
+
21
+
22
+ public function __construct($message, $messageType = self::NOTICE_NORMAL)
23
+ {
24
+ $this->message = $message;
25
+ $this->messageType = $messageType;
26
+
27
+ }
28
+
29
+ public function isDone()
30
+ {
31
+ if ($this->viewed && ! $this->is_persistent)
32
+ return true;
33
+ else
34
+ return false;
35
+
36
+ }
37
+
38
+ public static function setIcon($notice_type, $icon)
39
+ {
40
+ switch($notice_type)
41
+ {
42
+ case 'error':
43
+ $type = self::NOTICE_ERROR;
44
+ break;
45
+ case 'success':
46
+ $type = self::NOTICE_SUCCESS;
47
+ break;
48
+ case 'warning':
49
+ $type = self::NOTICE_WARNING;
50
+ break;
51
+ case 'normal':
52
+ default:
53
+ $type = self::NOTICE_NORMAL;
54
+ break;
55
+ }
56
+ self::$icons[$type] = $icon;
57
+ }
58
+
59
+ public function getForDisplay()
60
+ {
61
+ $this->viewed = true;
62
+ $class = 'shortpixel notice ';
63
+
64
+ $icon = '';
65
+
66
+ switch($this->messageType)
67
+ {
68
+ case self::NOTICE_ERROR:
69
+ $class .= 'notice-error ';
70
+ $icon = isset(self::$icons[self::NOTICE_ERROR]) ? self::$icons[self::NOTICE_ERROR] : '';
71
+ //$icon = 'scared';
72
+ break;
73
+ case self::NOTICE_SUCCESS:
74
+ $class .= 'notice-success ';
75
+ $icon = isset(self::$icons[self::NOTICE_SUCCESS]) ? self::$icons[self::NOTICE_SUCCESS] : '';
76
+ break;
77
+ case self::NOTICE_WARNING:
78
+ $class .= 'notice-warning ';
79
+ $icon = isset(self::$icons[self::NOTICE_WARNING]) ? self::$icons[self::NOTICE_WARNING] : '';
80
+ break;
81
+ case self::NOTICE_NORMAL:
82
+ $class .= 'notice-info ';
83
+ $icon = isset(self::$icons[self::NOTICE_NORMAL]) ? self::$icons[self::NOTICE_NORMAL] : '';
84
+ break;
85
+ default:
86
+ $class .= 'notice-info ';
87
+ $icon = '';
88
+ break;
89
+ }
90
+
91
+ /*$image = '<img src="' . plugins_url('/shortpixel-image-optimiser/res/img/robo-' . $icon . '.png') . '"
92
+ srcset="' . plugins_url( 'shortpixel-image-optimiser/res/img/robo-' . $icon . '.png' ) . ' 1x, ' . plugins_url( 'shortpixel-image-optimiser/res/img/robo-' . $icon . '@2x.png') . ' 2x" class="short-pixel-notice-icon">';
93
+ */
94
+
95
+ if ($this->is_removable)
96
+ {
97
+ $class .= 'is-dismissible ';
98
+ }
99
+
100
+ if ($this->is_persistent)
101
+ {
102
+ $class .= '';
103
+ }
104
+
105
+ return "<div class='$class'>" . $icon . "<p>" . $this->message . "</p></div>";
106
+
107
+ }
108
+
109
+
110
+
111
+ // @todo Transient save, since that is used in some parts.
112
+ // save
113
+ // load
114
+
115
+
116
+ }
build/shortpixel/notices/src/css/notices.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .shortpixel.notice {
2
+ padding: 8px; }
3
+ .shortpixel.notice img {
4
+ display: inline-block;
5
+ margin: 0 25px 0 0;
6
+ max-height: 50px; }
7
+ .shortpixel.notice .notice-dismiss {
8
+ margin-top: 10px; }
9
+
10
+ /* In-view notice ( not on top, between the options ) - styled after WP notice */
11
+ .view-notice {
12
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
13
+ border: 4px solid #fff;
14
+ padding: 1px 12px; }
15
+ .view-notice p {
16
+ margin: 1em 0 !important; }
17
+ .view-notice.warning {
18
+ border-left-color: #ffb900; }
19
+
20
+ .view-notice-row {
21
+ display: none; }
build/shortpixel/notices/src/css/notices.scss ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .shortpixel.notice
3
+ {
4
+ //padding: 18px;
5
+ //min-height: 50px;
6
+ padding: 8px;
7
+ img
8
+ {
9
+ display:inline-block;
10
+ margin: 0 25px 0 0;
11
+ max-height: 50px;
12
+ }
13
+ .notice-dismiss
14
+ {
15
+ margin-top: 10px;
16
+ }
17
+ }
18
+
19
+ /* In-view notice ( not on top, between the options ) - styled after WP notice */
20
+ .view-notice
21
+ {
22
+
23
+ box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
24
+ border: 4px solid #fff;
25
+
26
+ padding: 1px 12px;
27
+ p {
28
+ margin: 1em 0 !important;
29
+ }
30
+ &.warning
31
+ {
32
+ border-left-color: #ffb900;
33
+ }
34
+ }
35
+
36
+ .view-notice-row
37
+ {
38
+ display: none;
39
+ }
classes/emr-plugin.php CHANGED
@@ -1,19 +1,29 @@
1
  <?php
2
  namespace EnableMediaReplace;
 
 
3
 
4
  // Does what a plugin does.
5
  class EnableMediaReplacePlugin
6
  {
7
 
8
  protected $plugin_path;
 
9
 
10
  public function __construct()
11
  {
12
  $this->plugin_actions(); // init
 
13
 
 
 
 
 
14
 
 
15
  }
16
 
 
17
  public function plugin_actions()
18
  {
19
  $this->plugin_path = plugin_dir_path(EMR_ROOT_FILE);
@@ -51,11 +61,21 @@ class EnableMediaReplacePlugin
51
 
52
  /**
53
  * Initialize this plugin. Called by 'admin_init' hook.
54
- * Only languages files needs loading during init.
55
  */
56
  public function init()
57
  {
58
  load_plugin_textdomain( 'enable-media-replace', false, basename(dirname(EMR_ROOT_FILE) ) . '/languages' );
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
  /** Load EMR views based on request */
@@ -109,7 +129,16 @@ class EnableMediaReplacePlugin
109
  }
110
 
111
  wp_register_script('emr_admin', plugins_url('js/emr_admin.js', EMR_ROOT_FILE), array('jquery'), false, true );
112
- wp_localize_script('emr_admin', 'emr_options', array('dateFormat' => $this->convertdate(get_option( 'date_format' ))));
 
 
 
 
 
 
 
 
 
113
 
114
  }
115
 
@@ -170,7 +199,7 @@ class EnableMediaReplacePlugin
170
  $form_fields["enable-media-replace"] = array(
171
  "label" => esc_html__("Replace media", "enable-media-replace"),
172
  "input" => "html",
173
- "html" => "<p><a class='button-secondary'$link>" . esc_html__("Upload a new file", "enable-media-replace") . "</a></p>", "helps" => esc_html__("To replace the current file, click the link and upload a replacement.", "enable-media-replace")
174
  );
175
 
176
  return $form_fields;
@@ -180,7 +209,6 @@ class EnableMediaReplacePlugin
180
  * @param array $mime_types
181
  * @return array
182
  */
183
-
184
  public function add_mime_types($mime_types)
185
  {
186
  $mime_types['dat'] = 'text/plain'; // Adding .dat extension
@@ -202,7 +230,7 @@ class EnableMediaReplacePlugin
202
  } */
203
  $link = "href=\"$editurl\"";
204
 
205
- $newaction['adddata'] = '<a ' . $link . ' aria-label="' . esc_html__("Replace media", "enable-media-replace") . '" rel="permalink">' . esc_html__("Replace media", "enable-media-replace") . '</a>';
206
  return array_merge($actions,$newaction);
207
  }
208
 
1
  <?php
2
  namespace EnableMediaReplace;
3
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
4
+ use EnableMediaReplace\Notices\NoticeController as Notices;
5
 
6
  // Does what a plugin does.
7
  class EnableMediaReplacePlugin
8
  {
9
 
10
  protected $plugin_path;
11
+ private static $instance;
12
 
13
  public function __construct()
14
  {
15
  $this->plugin_actions(); // init
16
+ }
17
 
18
+ public static function get()
19
+ {
20
+ if (is_null(self::$instance))
21
+ self::$instance = new EnableMediaReplacePlugin();
22
 
23
+ return self::$instance;
24
  }
25
 
26
+
27
  public function plugin_actions()
28
  {
29
  $this->plugin_path = plugin_dir_path(EMR_ROOT_FILE);
61
 
62
  /**
63
  * Initialize this plugin. Called by 'admin_init' hook.
64
+ *
65
  */
66
  public function init()
67
  {
68
  load_plugin_textdomain( 'enable-media-replace', false, basename(dirname(EMR_ROOT_FILE) ) . '/languages' );
69
+
70
+ // Load Submodules
71
+ Log::addDebug('Plugin Init');
72
+ $notices = Notices::getInstance();
73
+
74
+ // Enqueue notices
75
+ add_action('admin_notices', array($notices, 'admin_notices')); // previous page / init time
76
+ add_action('admin_footer', array($notices, 'admin_notices')); // fresh notices between init - end
77
+
78
+ new Externals();
79
  }
80
 
81
  /** Load EMR views based on request */
129
  }
130
 
131
  wp_register_script('emr_admin', plugins_url('js/emr_admin.js', EMR_ROOT_FILE), array('jquery'), false, true );
132
+ $emr_options = array(
133
+ 'dateFormat' => $this->convertdate(get_option( 'date_format' )),
134
+ 'maxfilesize' => wp_max_upload_size(),
135
+
136
+ );
137
+
138
+ if (Log::debugIsActive())
139
+ $emr_options['is_debug'] = true;
140
+
141
+ wp_localize_script('emr_admin', 'emr_options', $emr_options);
142
 
143
  }
144
 
199
  $form_fields["enable-media-replace"] = array(
200
  "label" => esc_html__("Replace media", "enable-media-replace"),
201
  "input" => "html",
202
+ "html" => "<p><a class='button-secondary' $link>" . esc_html__("Upload a new file", "enable-media-replace") . "</a></p>", "helps" => esc_html__("To replace the current file, click the link and upload a replacement.", "enable-media-replace")
203
  );
204
 
205
  return $form_fields;
209
  * @param array $mime_types
210
  * @return array
211
  */
 
212
  public function add_mime_types($mime_types)
213
  {
214
  $mime_types['dat'] = 'text/plain'; // Adding .dat extension
230
  } */
231
  $link = "href=\"$editurl\"";
232
 
233
+ $newaction['adddata'] = '<a ' . $link . ' aria-label="' . esc_attr__("Replace media", "enable-media-replace") . '" rel="permalink">' . esc_html__("Replace media", "enable-media-replace") . '</a>';
234
  return array_merge($actions,$newaction);
235
  }
236
 
classes/externals.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
4
+ use EnableMediaReplace\Notices\NoticeController as Notices;
5
+
6
+
7
+ class Externals
8
+ {
9
+ protected $replaceType = null;
10
+ protected $replaceSearchType = null;
11
+
12
+ protected $messages = array();
13
+
14
+
15
+ public function __construct()
16
+ {
17
+ add_filter('emr_display_replace_type_options', array($this, 'get_replace_type'));
18
+ add_filter('emr_enable_replace_and_search', array($this, 'get_replacesearch_type'));
19
+
20
+ add_action('emr_after_replace_type_options', array($this, 'get_messages'));
21
+
22
+
23
+ $this->check();
24
+ }
25
+
26
+ protected function check()
27
+ {
28
+ if (class_exists('FLBuilder'))
29
+ {
30
+ $this->replaceSearchType = false;
31
+ $this->messages[] = __('Replace and Search feature is not compatible with Beaver Builder.', 'enable-media-replace');
32
+ }
33
+ }
34
+
35
+ public function get_replace_type($bool)
36
+ {
37
+ if ($this->replaceType === null)
38
+ return $bool;
39
+
40
+ return $this->replaceType;
41
+ }
42
+
43
+ public function get_replacesearch_type($bool)
44
+ {
45
+ if ($this->replaceSearchType === null)
46
+ return $bool;
47
+
48
+ return $this->replaceSearchType;
49
+ }
50
+
51
+ public function get_messages()
52
+ {
53
+ foreach($this->messages as $message)
54
+ {
55
+ echo '<span class="nofeature-notice"><p>'. $message . '</p></span>';
56
+ }
57
+
58
+ }
59
+
60
+
61
+
62
+
63
+
64
+ }
classes/file.php CHANGED
@@ -1,6 +1,9 @@
1
  <?php
2
  namespace EnableMediaReplace;
3
 
 
 
 
4
  class emrFile
5
  {
6
 
@@ -36,7 +39,15 @@ class emrFile
36
  // This will *not* be checked, is not meant for permission of validation!
37
  $this->fileMime = (isset($filedata['type'])) ? $filedata['type'] : false;
38
 
39
- // echo "<PRE>"; var_dump($this); echo "</PRE><BR>";
 
 
 
 
 
 
 
 
40
  }
41
 
42
  public function getFullFilePath()
@@ -64,11 +75,21 @@ class emrFile
64
  return $this->fileName;
65
  }
66
 
 
 
 
 
 
67
  public function getFileMime()
68
  {
69
  return $this->fileMime;
70
  }
71
 
 
 
 
 
 
72
 
73
  }
74
 
1
  <?php
2
  namespace EnableMediaReplace;
3
 
4
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
5
+ use EnableMediaReplace\Notices\NoticeController as Notices;
6
+
7
  class emrFile
8
  {
9
 
39
  // This will *not* be checked, is not meant for permission of validation!
40
  $this->fileMime = (isset($filedata['type'])) ? $filedata['type'] : false;
41
 
42
+ }
43
+
44
+ public function checkAndCreateFolder()
45
+ {
46
+ $path = $this->getFilePath();
47
+ if (! is_dir($path) && ! file_exists($path))
48
+ {
49
+ return wp_mkdir_p($path);
50
+ }
51
  }
52
 
53
  public function getFullFilePath()
75
  return $this->fileName;
76
  }
77
 
78
+ public function getFileExtension()
79
+ {
80
+ return $this->extension;
81
+ }
82
+
83
  public function getFileMime()
84
  {
85
  return $this->fileMime;
86
  }
87
 
88
+ public function exists()
89
+ {
90
+ return $this->exists;
91
+ }
92
+
93
 
94
  }
95
 
classes/replacer.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  namespace EnableMediaReplace;
3
  use \EnableMediaReplace\emrFile as File;
 
 
4
 
5
  class Replacer
6
  {
@@ -39,6 +41,7 @@ class Replacer
39
  $source_file = trim(get_attached_file($post_id, apply_filters( 'emr_unfiltered_get_attached_file', true )));
40
 
41
  $this->sourceFile = new File($source_file);
 
42
  $this->source_post = get_post($post_id);
43
  $this->source_is_image = wp_attachment_is('image', $this->source_post);
44
  $this->source_metadata = wp_get_attachment_metadata( $post_id );
@@ -65,6 +68,7 @@ class Replacer
65
  /** Replace the sourceFile with a target
66
  * @param $file String Full Path to the Replacement File. This will usually be an uploaded file in /tmp/
67
  * @param $fileName String The fileName of the uploaded file. This will be used if sourcefile is not to be overwritten.
 
68
  */
69
  public function replaceWith($file, $fileName)
70
  {
@@ -78,18 +82,25 @@ class Replacer
78
 
79
  if (is_null($targetFile))
80
  {
81
- _e('Target File could not be set. The source file might not be there. In case of search and replace, a filter might prevent this', "enable-media-replace");
82
- exit;
83
  }
84
 
 
 
 
 
 
85
  /* @todo See if wp_handle_sideload / wp_handle_upload can be more securely used for this */
86
  $result_moved = move_uploaded_file($file,$targetFile);
87
 
88
  if (false === $result_moved)
89
  {
90
- printf( esc_html__('The uploaded file could not be moved to %1$s , most likely because it could not remove the old images (file permissions) or the upload failed.', "enable-media-replace"), $targetFile );
91
- exit;
92
  }
 
 
93
  $this->targetFile = new File($targetFile);
94
 
95
  if ($this->sourceFile->getPermissions() > 0)
@@ -114,6 +125,7 @@ class Replacer
114
  {
115
  update_attached_file($this->post_id, $filtered['file'] );
116
  $this->targetFile = new File($filtered['file']); // handle as a new file
 
117
  }
118
 
119
  $metadata = wp_generate_attachment_metadata( $this->post_id, $this->targetFile->getFullFilePath() );
@@ -134,6 +146,8 @@ class Replacer
134
  // update post doesn't update GUID on updates.
135
  $wpdb->update( $wpdb->posts, array( 'guid' => $this->target_url), array('ID' => $this->post_id) );
136
  //enable-media-replace-upload-done
 
 
137
  if (is_wp_error($post_id))
138
  {
139
  $errors = $post_id->get_error_messages();
@@ -147,8 +161,10 @@ class Replacer
147
 
148
  if(wp_attachment_is_image($this->post_id))
149
  {
150
- $this->ThumbnailUpdater->setNewMetadata($metadata);
151
- $this->ThumbnailUpdater->updateThumbnails();
 
 
152
  }
153
 
154
  // if all set and done, update the date.
@@ -168,7 +184,8 @@ class Replacer
168
 
169
  protected function getNewTitle()
170
  {
171
- $title = $this->targetFile->getFileName();
 
172
  $meta = $this->target_metadata;
173
 
174
  if (isset($meta['image_meta']))
@@ -194,7 +211,7 @@ class Replacer
194
  $targetPath = null;
195
  if ($this->replaceMode == self::MODE_REPLACE)
196
  {
197
- $targetPath = $this->sourceFile->getFullFilePath(); // overwrite source
198
  }
199
  elseif ($this->replaceMode == self::MODE_SEARCHREPLACE)
200
  {
@@ -202,9 +219,26 @@ class Replacer
202
  $unique = wp_unique_filename($path, $this->targetName);
203
 
204
  $new_filename = apply_filters( 'emr_unique_filename', $unique, $path, $this->post_id );
205
- $targetPath = trailingslashit($path) . $new_filename;
206
  }
207
- return $targetPath;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
 
210
  /** Tries to remove all of the old image, without touching the metadata in database
@@ -212,9 +246,10 @@ class Replacer
212
  */
213
  protected function removeCurrent()
214
  {
215
- $meta = wp_get_attachment_metadata( $this->post_id );
216
  $backup_sizes = get_post_meta( $this->post_id, '_wp_attachment_backup_sizes', true );
217
- $result = wp_delete_attachment_files($this->post_id, $meta, $backup_sizes, $this->sourceFile->getFullFilePath() );
 
218
  }
219
 
220
  /** Handle new dates for the replacement */
@@ -255,7 +290,14 @@ class Replacer
255
  global $wpdb;
256
 
257
  // Search-and-replace filename in post database
258
- $current_base_url = emr_get_match_url( $this->source_url );
 
 
 
 
 
 
 
259
 
260
  /* Search and replace in WP_POSTS */
261
  $posts_sql = $wpdb->remove_placeholder_escape($wpdb->prepare(
@@ -277,8 +319,9 @@ class Replacer
277
  $replace_urls = emr_get_file_urls( $this->target_url, $this->target_metadata );
278
  $replace_urls = array_values(emr_normalize_file_urls( $search_urls, $replace_urls ));
279
 
280
- if ( ! empty( $rs ) ) {
281
 
 
282
  foreach ( $rs AS $rows ) {
283
  $number_of_updates = $number_of_updates + 1;
284
  // replace old URLs with new URLs.
@@ -292,6 +335,9 @@ class Replacer
292
  // echo "$sql <BR>";
293
  $wpdb->query( $sql );
294
  }
 
 
 
295
  foreach ($rsmeta as $row)
296
  {
297
  $number_of_updates++;
@@ -301,8 +347,8 @@ class Replacer
301
  $sql = $wpdb->prepare('UPDATE ' . $wpdb->postmeta . ' SET meta_value = %s WHERE meta_id = %d', $content, $row['meta_id'] );
302
  $wpdb->query($sql);
303
  }
 
304
 
305
- }
306
 
307
  } // doSearchReplace
308
 
1
  <?php
2
  namespace EnableMediaReplace;
3
  use \EnableMediaReplace\emrFile as File;
4
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
5
+ use EnableMediaReplace\Notices\NoticeController as Notices;
6
 
7
  class Replacer
8
  {
41
  $source_file = trim(get_attached_file($post_id, apply_filters( 'emr_unfiltered_get_attached_file', true )));
42
 
43
  $this->sourceFile = new File($source_file);
44
+
45
  $this->source_post = get_post($post_id);
46
  $this->source_is_image = wp_attachment_is('image', $this->source_post);
47
  $this->source_metadata = wp_get_attachment_metadata( $post_id );
68
  /** Replace the sourceFile with a target
69
  * @param $file String Full Path to the Replacement File. This will usually be an uploaded file in /tmp/
70
  * @param $fileName String The fileName of the uploaded file. This will be used if sourcefile is not to be overwritten.
71
+ * @throws RunTimeException Can throw exception if something went wrong with the files.
72
  */
73
  public function replaceWith($file, $fileName)
74
  {
82
 
83
  if (is_null($targetFile))
84
  {
85
+ $ex = __('Target File could not be set. The source file might not be there. In case of search and replace, a filter might prevent this', "enable-media-replace");
86
+ throw new \RuntimeException($ex);
87
  }
88
 
89
+ $targetFileObj = new File($targetFile);
90
+ $result = $targetFileObj->checkAndCreateFolder();
91
+ if ($result === false)
92
+ Log::addError('Directory creation for targetFile failed');
93
+
94
  /* @todo See if wp_handle_sideload / wp_handle_upload can be more securely used for this */
95
  $result_moved = move_uploaded_file($file,$targetFile);
96
 
97
  if (false === $result_moved)
98
  {
99
+ $ex = sprintf( esc_html__('The uploaded file could not be moved to %1$s. This is most likely an issue with permissions, or upload failed.', "enable-media-replace"), $targetFile );
100
+ throw new \RuntimeException($ex);
101
  }
102
+
103
+ // init targetFile.
104
  $this->targetFile = new File($targetFile);
105
 
106
  if ($this->sourceFile->getPermissions() > 0)
125
  {
126
  update_attached_file($this->post_id, $filtered['file'] );
127
  $this->targetFile = new File($filtered['file']); // handle as a new file
128
+ Log::addInfo('WP_Handle_upload filter returned different file', $filtered);
129
  }
130
 
131
  $metadata = wp_generate_attachment_metadata( $this->post_id, $this->targetFile->getFullFilePath() );
146
  // update post doesn't update GUID on updates.
147
  $wpdb->update( $wpdb->posts, array( 'guid' => $this->target_url), array('ID' => $this->post_id) );
148
  //enable-media-replace-upload-done
149
+
150
+ // @todo Replace this one with proper Notices:addError;
151
  if (is_wp_error($post_id))
152
  {
153
  $errors = $post_id->get_error_messages();
161
 
162
  if(wp_attachment_is_image($this->post_id))
163
  {
164
+ $this->ThumbnailUpdater->setNewMetadata($this->target_metadata);
165
+ $result = $this->ThumbnailUpdater->updateThumbnails();
166
+ if (false === $result)
167
+ Log::addWarn('Thumbnail Updater returned false');
168
  }
169
 
170
  // if all set and done, update the date.
184
 
185
  protected function getNewTitle()
186
  {
187
+ // get basename without extension
188
+ $title = basename($this->targetFile->getFileName(), '.' . $this->targetFile->getFileExtension());
189
  $meta = $this->target_metadata;
190
 
191
  if (isset($meta['image_meta']))
211
  $targetPath = null;
212
  if ($this->replaceMode == self::MODE_REPLACE)
213
  {
214
+ $targetFile = $this->sourceFile->getFullFilePath(); // overwrite source
215
  }
216
  elseif ($this->replaceMode == self::MODE_SEARCHREPLACE)
217
  {
219
  $unique = wp_unique_filename($path, $this->targetName);
220
 
221
  $new_filename = apply_filters( 'emr_unique_filename', $unique, $path, $this->post_id );
222
+ $targetFile = trailingslashit($path) . $new_filename;
223
  }
224
+ if (is_dir($targetFile)) // this indicates an error with the source.
225
+ {
226
+ Log::addWarn('TargetFile is directory ' . $targetFile );
227
+ $upload_dir = wp_upload_dir();
228
+ if (isset($upload_dir['path']))
229
+ {
230
+ $targetFile = trailingslashit($upload_dir['path']) . wp_unique_filename($targetFile, $this->targetName);
231
+ }
232
+ else {
233
+ $err = 'EMR could not establish a proper destination for replacement';
234
+ Log::addError($err);
235
+ throw new \RuntimeException($err);
236
+ exit($err); // fallback
237
+
238
+ }
239
+ }
240
+
241
+ return $targetFile;
242
  }
243
 
244
  /** Tries to remove all of the old image, without touching the metadata in database
246
  */
247
  protected function removeCurrent()
248
  {
249
+ $meta = \wp_get_attachment_metadata( $this->post_id );
250
  $backup_sizes = get_post_meta( $this->post_id, '_wp_attachment_backup_sizes', true );
251
+ $result = \wp_delete_attachment_files($this->post_id, $meta, $backup_sizes, $this->sourceFile->getFullFilePath() );
252
+
253
  }
254
 
255
  /** Handle new dates for the replacement */
290
  global $wpdb;
291
 
292
  // Search-and-replace filename in post database
293
+ $current_base_url = emr_get_match_url( $this->source_url);
294
+
295
+ /** Fail-safe if base_url is a whole directory, don't go search/replace */
296
+ if (is_dir($current_base_url))
297
+ {
298
+ Log::addError('Search Replace tried to replace to directory - ' . $current_base_url);
299
+ exit('Fail Safe :: Source Location seems to be a directory.');
300
+ }
301
 
302
  /* Search and replace in WP_POSTS */
303
  $posts_sql = $wpdb->remove_placeholder_escape($wpdb->prepare(
319
  $replace_urls = emr_get_file_urls( $this->target_url, $this->target_metadata );
320
  $replace_urls = array_values(emr_normalize_file_urls( $search_urls, $replace_urls ));
321
 
322
+ Log::addDebug('Replacing references', array($search_urls, $replace_urls));
323
 
324
+ if ( ! empty( $rs ) ) {
325
  foreach ( $rs AS $rows ) {
326
  $number_of_updates = $number_of_updates + 1;
327
  // replace old URLs with new URLs.
335
  // echo "$sql <BR>";
336
  $wpdb->query( $sql );
337
  }
338
+ }
339
+ if (! empty($rsmeta))
340
+ {
341
  foreach ($rsmeta as $row)
342
  {
343
  $number_of_updates++;
347
  $sql = $wpdb->prepare('UPDATE ' . $wpdb->postmeta . ' SET meta_value = %s WHERE meta_id = %d', $content, $row['meta_id'] );
348
  $wpdb->query($sql);
349
  }
350
+ }
351
 
 
352
 
353
  } // doSearchReplace
354
 
classes/uihelper.php ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
4
+ use EnableMediaReplace\Notices\NoticeController as Notices;
5
+
6
+ /* Collection of functions helping the interface being cleaner. */
7
+ class UIHelper
8
+ {
9
+ protected $preview_size = '';
10
+ protected $preview_width = 0;
11
+ protected $preview_height = 0;
12
+
13
+ protected $preview_max_height = 500;
14
+ protected $preview_max_width = 400;
15
+
16
+ protected $full_width = 0;
17
+ protected $full_height = 0;
18
+
19
+ public function __construct()
20
+ {
21
+
22
+ }
23
+
24
+
25
+ public function getFormUrl($attach_id)
26
+ {
27
+ $url = admin_url('upload.php');
28
+ $url = add_query_arg(array(
29
+ 'page' => 'enable-media-replace/enable-media-replace.php',
30
+ 'noheader' => true,
31
+ 'action' => 'media_replace_upload',
32
+ 'attachment_id' => $attach_id,
33
+ ));
34
+
35
+ if (isset($_REQUEST['SHORTPIXEL_DEBUG']))
36
+ {
37
+ $spdebug = $_REQUEST['SHORTPIXEL_DEBUG'];
38
+ if (is_numeric($spdebug))
39
+ $spdebug = intval($spdebug);
40
+ else {
41
+ $spdebug = sanitize_text_field($spdebug);
42
+ }
43
+
44
+ $url = add_query_arg('SHORTPIXEL_DEBUG', $spdebug, $url);
45
+ }
46
+
47
+ return $url;
48
+
49
+ }
50
+
51
+ public function getSuccesRedirect($post_id)
52
+ {
53
+ $url = admin_url('post.php');
54
+ $url = add_query_arg(array('action' => 'edit', 'post' => $post_id), $url);
55
+
56
+ $url = apply_filters('emr_returnurl', $url);
57
+ Log::addDebug('Success URL- ' . $url);
58
+
59
+ return $url;
60
+
61
+ }
62
+
63
+ public function getFailedRedirect($attach_id)
64
+ {
65
+ $url = admin_url('upload.php');
66
+ $url = add_query_arg(array(
67
+ 'page' => 'enable-media-replace/enable-media-replace.php',
68
+ 'action' => 'media_replace',
69
+ 'attachment_id' => $attach_id,
70
+ '_wpnonce' => wp_create_nonce('media_replace'),
71
+ ), $url
72
+ );
73
+
74
+ $url = apply_filters('emr_returnurl_failed', $url);
75
+ Log::addDebug('Failed URL- ' . $url);
76
+ return $url;
77
+ }
78
+
79
+
80
+
81
+ public function setPreviewSizes()
82
+ {
83
+ list($this->preview_size, $this->preview_width, $this->preview_height) = $this->findImageSizeByMax($this->preview_max_width);
84
+ }
85
+
86
+ public function setSourceSizes($attach_id)
87
+ {
88
+ $data = wp_get_attachment_image_src($attach_id, 'full');
89
+ if (is_array($data))
90
+ {
91
+ $this->full_width = $data[1];
92
+ $this->full_height = $data[2];
93
+ }
94
+ }
95
+
96
+ // Returns Preview Image HTML Output.
97
+ public function getPreviewImage($attach_id)
98
+ {
99
+ $data = false;
100
+
101
+ if ($attach_id > 0)
102
+ {
103
+ $data = wp_get_attachment_image_src($attach_id, $this->preview_size);
104
+ $file = get_attached_file($attach_id);
105
+ Log::addDebug('Attached File ' . $file, $data);
106
+
107
+ }
108
+
109
+ $mime_type = get_post_mime_type($attach_id);
110
+
111
+ if (! is_array($data) || ! file_exists($file) )
112
+ {
113
+ // if attachid higher than zero ( exists ) but not the image, fail, that's an error state.
114
+ $icon = ($attach_id < 0) ? '' : 'dashicons-no';
115
+ $is_document = false;
116
+
117
+ $args = array(
118
+ 'width' => $this->preview_width,
119
+ 'height' => $this->preview_height,
120
+ 'is_image' => false,
121
+ 'is_document' => $is_document,
122
+ 'icon' => $icon,
123
+ );
124
+
125
+ // failed, it might be this server doens't support PDF thumbnails. Fallback to File preview.
126
+ if ($mime_type == 'application/pdf')
127
+ {
128
+ return $this->getPreviewFile($attach_id);
129
+ }
130
+
131
+ return $this->getPlaceHolder($args);
132
+ }
133
+
134
+ $url = $data[0];
135
+ $width = $data[1];
136
+ $height = $data[2];
137
+ // preview width, if source if found, should be set to source.
138
+ $this->preview_width = $width;
139
+ $this->preview_height = $height;
140
+
141
+ if ($width > $this->preview_max_width)
142
+ $width = $this->preview_max_width;
143
+ if ($height > $this->preview_max_height)
144
+ $height = $this->preview_max_height;
145
+
146
+ $image = "<img src='$url' width='$width' height='$height' class='image' style='max-width:100%; max-height: 100%;' />";
147
+
148
+ $args = array(
149
+ 'width' => $width,
150
+ 'height' => $height,
151
+ 'image' => $image,
152
+ 'mime_type' => $mime_type,
153
+ );
154
+ $output = $this->getPlaceHolder($args);
155
+ return $output;
156
+ }
157
+
158
+ public function getPreviewError($attach_id)
159
+ {
160
+ $args = array(
161
+ 'width' => $this->preview_width,
162
+ 'height' => $this->preview_height,
163
+ 'icon' => 'dashicons-no',
164
+ 'is_image' => false,
165
+ );
166
+ $output = $this->getPlaceHolder($args);
167
+ return $output;
168
+ }
169
+
170
+ public function getPreviewFile($attach_id)
171
+ {
172
+ if ($attach_id > 0)
173
+ {
174
+ $filepath = get_attached_file($attach_id);
175
+ $filename = basename($filepath);
176
+ }
177
+ else {
178
+ $filename = false;
179
+ }
180
+
181
+ $mime_type = get_post_mime_type($attach_id);
182
+
183
+ $args = array(
184
+ 'width' => 300,
185
+ 'height' => 300,
186
+ 'is_image' => false,
187
+ 'is_document' => true,
188
+ 'layer' => $filename,
189
+ 'mime_type' => $mime_type,
190
+ );
191
+ $output = $this->getPlaceHolder($args);
192
+ return $output;
193
+ }
194
+
195
+ public function findImageSizeByMax($maxwidth)
196
+ {
197
+ $image_sizes = $this->get_image_sizes();
198
+
199
+ $match_width = 0;
200
+ $match_height = 0;
201
+ $match = '';
202
+
203
+ foreach($image_sizes as $sizeName => $sizeItem)
204
+ {
205
+
206
+ $width = $sizeItem['width'];
207
+ if ($width > $match_width && $width <= $maxwidth)
208
+ {
209
+ $match = $sizeName;
210
+ $match_width = $width;
211
+ $match_height = $sizeItem['height'];
212
+ }
213
+ }
214
+ return array($match, $match_width, $match_height);
215
+ }
216
+
217
+ public function getPlaceHolder($args)
218
+ {
219
+ $defaults = array(
220
+ 'width' => 150,
221
+ 'height' => 150,
222
+ 'image' => '',
223
+ 'icon' => 'dashicons-media-document',
224
+ 'layer' => $this->full_width . ' x ' . $this->full_height,
225
+ 'is_image' => true,
226
+ 'is_document' => false,
227
+ 'mime_type' => false,
228
+ );
229
+
230
+ $args = wp_parse_args($args, $defaults);
231
+ $w = $args['width'];
232
+ $h = $args['height'];
233
+
234
+ if ($w < 150) // minimum
235
+ $w = 150;
236
+ if ($h < 150)
237
+ $h = 150;
238
+
239
+ $icon = $args['icon'];
240
+
241
+ if ($args['is_image'])
242
+ {
243
+ $placeholder_class = 'is_image';
244
+ }
245
+ else {
246
+ $placeholder_class = 'not_image';
247
+ }
248
+
249
+ if ($args['is_document'])
250
+ {
251
+ $placeholder_class .= ' is_document';
252
+ }
253
+
254
+ $filetype = '';
255
+ if ($args['mime_type'])
256
+ {
257
+ $filetype = 'data-filetype="' . $args['mime_type'] . '"';
258
+ }
259
+
260
+
261
+ $output = "<div class='image_placeholder $placeholder_class' $filetype style='width:" . $w . "px; height:". $h ."px'> ";
262
+ $output .= $args['image'];
263
+ $output .= "<div class='dashicons $icon'>&nbsp;</div>";
264
+ $output .= "<span class='textlayer'>" . $args['layer'] . "</span>";
265
+ $output .= "</div>";
266
+
267
+ return $output;
268
+ }
269
+
270
+ /**
271
+ * Get size information for all currently-registered image sizes.
272
+ * Directly stolen from - https://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes
273
+ * @global $_wp_additional_image_sizes
274
+ * @uses get_intermediate_image_sizes()
275
+ * @return array $sizes Data for all currently-registered image sizes.
276
+ */
277
+ private function get_image_sizes() {
278
+ global $_wp_additional_image_sizes;
279
+
280
+ $sizes = array();
281
+
282
+ foreach ( get_intermediate_image_sizes() as $_size ) {
283
+ if ( in_array( $_size, array('thumbnail', 'medium', 'medium_large', 'large') ) ) {
284
+ $sizes[ $_size ]['width'] = get_option( "{$_size}_size_w" );
285
+ $sizes[ $_size ]['height'] = get_option( "{$_size}_size_h" );
286
+ } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
287
+ $sizes[ $_size ] = array(
288
+ 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
289
+ 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
290
+ );
291
+ }
292
+ }
293
+
294
+ return $sizes;
295
+ }
296
+
297
+ } // class
css/admin.css CHANGED
@@ -772,14 +772,80 @@
772
  min-height: 350px; }
773
  .emr_upload_form .image_chooser.wrapper .image_previews {
774
  margin: 15px 0; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
775
  .emr_upload_form .option-flex-wrapper {
776
  display: flex; }
777
  .emr_upload_form .replace_type.wrapper {
778
  flex: 1;
779
  border: 1px solid #ccc;
780
  margin: 15px 0; }
781
- .emr_upload_form .replace_type.wrapper label {
782
- font-size: 1.2em; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
  .emr_upload_form .options.wrapper {
784
  flex: 1;
785
  border: 1px solid #ccc;
772
  min-height: 350px; }
773
  .emr_upload_form .image_chooser.wrapper .image_previews {
774
  margin: 15px 0; }
775
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder {
776
+ position: relative;
777
+ display: inline-block;
778
+ margin-right: 25px;
779
+ border: 1px solid #ddd;
780
+ vertical-align: top;
781
+ max-height: 500px; }
782
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder .textlayer {
783
+ font-size: 25px;
784
+ line-height: 25px;
785
+ opacity: 0.7;
786
+ position: absolute;
787
+ color: #ccc;
788
+ left: 48%;
789
+ top: 50%;
790
+ transform: translate(-50%, -50%);
791
+ border: 1px dashed #eee;
792
+ background-color: #333;
793
+ padding: 8px; }
794
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder .dashicons {
795
+ font-size: 60px;
796
+ position: absolute;
797
+ top: 50%;
798
+ margin-top: -30px;
799
+ left: 50%;
800
+ margin-left: -30px;
801
+ opacity: 0.5; }
802
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder.is_image .dashicons::before, .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder.is_image .dashicons {
803
+ display: none; }
804
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder.not_image img {
805
+ display: none; }
806
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder.not_image .textlayer {
807
+ display: none; }
808
+ .emr_upload_form .image_chooser.wrapper .image_previews .image_placeholder.not_image.is_document .textlayer {
809
+ font-size: 18px;
810
+ line-height: 20px;
811
+ display: block; }
812
+ .emr_upload_form .form-error, .emr_upload_form .form-warning {
813
+ background: #fff;
814
+ padding: 8px;
815
+ border-left: 4px solid #ff0000;
816
+ margin: 10px 0;
817
+ display: none; }
818
+ .emr_upload_form .form-error p, .emr_upload_form .form-warning p {
819
+ margin: 0; }
820
+ .emr_upload_form .form-warning {
821
+ border-left: 4px solid #ffb900; }
822
  .emr_upload_form .option-flex-wrapper {
823
  display: flex; }
824
  .emr_upload_form .replace_type.wrapper {
825
  flex: 1;
826
  border: 1px solid #ccc;
827
  margin: 15px 0; }
828
+ .emr_upload_form .replace_type.wrapper .option {
829
+ position: relative;
830
+ z-index: 1; }
831
+ .emr_upload_form .replace_type.wrapper .option label {
832
+ font-size: 1.2em; }
833
+ .emr_upload_form .replace_type.wrapper .option .nofeature-notice {
834
+ border: 1px solid #ccc;
835
+ padding: 8px;
836
+ margin: 0;
837
+ position: absolute;
838
+ left: 0;
839
+ right: 0;
840
+ top: 0;
841
+ bottom: 0;
842
+ opacity: 0.8;
843
+ z-index: 9;
844
+ background: #444; }
845
+ .emr_upload_form .replace_type.wrapper .option .nofeature-notice p {
846
+ text-align: center;
847
+ color: #fff;
848
+ margin: 15px 0; }
849
  .emr_upload_form .options.wrapper {
850
  flex: 1;
851
  border: 1px solid #ccc;
enable-media-replace.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Enable Media Replace
4
  Plugin URI: https://wordpress.org/plugins/enable-media-replace/
5
  Description: Enable replacing media files by uploading a new file in the "Edit Media" section of the WordPress Media Library.
6
- Version: 3.3.1
7
  Author: ShortPixel
8
  Author URI: https://shortpixel.com
9
  Text Domain: enable-media-replace
@@ -24,6 +24,8 @@ http://www.gnu.org/licenses/gpl.html
24
  *
25
  */
26
 
 
 
27
  if ( ! defined( 'ABSPATH' ) ) {
28
  exit; // Exit if accessed directly.
29
  }
@@ -40,10 +42,13 @@ if(!defined("SHORTPIXEL_AFFILIATE_CODE")) {
40
  define("SHORTPIXEL_AFFILIATE_CODE", 'VKG6LYN28044');
41
  }
42
 
 
43
  require_once('classes/replacer.php');
 
44
  require_once('classes/file.php');
45
  require_once('classes/cache.php');
46
  require_once('classes/emr-plugin.php');
 
47
  require_once('thumbnail_updater.php');
48
 
49
- $emr_plugin = new \EnableMediaReplace\EnableMediaReplacePlugin();
3
  Plugin Name: Enable Media Replace
4
  Plugin URI: https://wordpress.org/plugins/enable-media-replace/
5
  Description: Enable replacing media files by uploading a new file in the "Edit Media" section of the WordPress Media Library.
6
+ Version: 3.3.3
7
  Author: ShortPixel
8
  Author URI: https://shortpixel.com
9
  Text Domain: enable-media-replace
24
  *
25
  */
26
 
27
+ namespace EnableMediaReplace;
28
+
29
  if ( ! defined( 'ABSPATH' ) ) {
30
  exit; // Exit if accessed directly.
31
  }
42
  define("SHORTPIXEL_AFFILIATE_CODE", 'VKG6LYN28044');
43
  }
44
 
45
+ require_once('build/shortpixel/autoload.php');
46
  require_once('classes/replacer.php');
47
+ require_once('classes/uihelper.php');
48
  require_once('classes/file.php');
49
  require_once('classes/cache.php');
50
  require_once('classes/emr-plugin.php');
51
+ require_once('classes/externals.php');
52
  require_once('thumbnail_updater.php');
53
 
54
+ $emr_plugin = EnableMediaReplacePlugin::get();
js/emr_admin.js CHANGED
@@ -3,12 +3,39 @@ jQuery(document).ready(function($)
3
  // interface for emr.
4
  var emrIf = new function ()
5
  {
 
 
 
 
 
 
6
 
7
  this.init = function()
8
  {
 
 
 
 
 
 
9
  $('input[name="timestamp_replace"]').on('change', $.proxy(this.checkCustomDate, this));
 
10
  this.checkCustomDate();
11
  this.loadDatePicker();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  },
13
  this.loadDatePicker = function()
14
  {
@@ -28,7 +55,6 @@ jQuery(document).ready(function($)
28
  },
29
  this.checkCustomDate = function()
30
  {
31
- console.log('check');
32
  if ($('input[name="timestamp_replace"]:checked').val() == 3)
33
  this.showCustomDate();
34
  else
@@ -46,26 +72,148 @@ jQuery(document).ready(function($)
46
  $('.custom_date').css('visibility', 'hidden');
47
  });
48
  }
49
- } // emrIf
 
 
 
 
50
 
51
- /*emrIf.
 
 
 
 
 
 
52
 
53
- $('input[name="timestamp_replace"]').on('change',function(e)
54
- {
55
- var target = e.target;
56
- var value = $(e.target).val();
57
- if (value == 3) // custom date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  {
59
- $('.custom_date').css('visibility', 'visible').fadeTo(100, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
- else {
62
- $('.custom_date').fadeTo(100,0,
63
- function ()
64
- {
65
- $('.custom_date').css('visibility', 'hidden');
66
- });
67
  }
68
- });*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  window.enableMediaReplace = emrIf;
71
  window.enableMediaReplace.init();
3
  // interface for emr.
4
  var emrIf = new function ()
5
  {
6
+ var source_type;
7
+ var source_is_image;
8
+ var target_type;
9
+ var target_is_image;
10
+
11
+ var is_debug = false;
12
 
13
  this.init = function()
14
  {
15
+ if ( emr_options.is_debug)
16
+ {
17
+ this.is_debug = true;
18
+ this.debug('EMR Debug is active');
19
+ }
20
+
21
  $('input[name="timestamp_replace"]').on('change', $.proxy(this.checkCustomDate, this));
22
+ $('input[name="userfile"]').on('change', $.proxy(this.handleImage, this));
23
  this.checkCustomDate();
24
  this.loadDatePicker();
25
+
26
+ var source = $('.image_placeholder').first();
27
+ if (typeof( $(source).data('filetype') ) !== 'undefined')
28
+ {
29
+ source_type = $(source).data('filetype');
30
+ this.debug('detected type - ' + source_type);
31
+ }
32
+ if (source.hasClass('is_image'))
33
+ {
34
+ source_is_image = true;
35
+ }
36
+
37
+ this.updateTextLayer(source, false);
38
+
39
  },
40
  this.loadDatePicker = function()
41
  {
55
  },
56
  this.checkCustomDate = function()
57
  {
 
58
  if ($('input[name="timestamp_replace"]:checked').val() == 3)
59
  this.showCustomDate();
60
  else
72
  $('.custom_date').css('visibility', 'hidden');
73
  });
74
  }
75
+ this.handleImage = function(e)
76
+ {
77
+ this.toggleErrors(false);
78
+ var target = e.target;
79
+ var file = target.files[0];
80
 
81
+ if (! target.files || target.files.length <= 0) // FileAPI appears to be not present, handle files on backend.
82
+ {
83
+ if ($('input[name="userfile"]').val().length > 0)
84
+ this.checkSubmit();
85
+ console.log('FileAPI not detected');
86
+ return;
87
+ }
88
 
89
+ var status = this.checkUpload(file);
90
+ this.debug('check upload status ' + status);
91
+
92
+ if (status)
93
+ {
94
+ this.updatePreview(file);
95
+ }
96
+ else {
97
+ this.updatePreview(null);
98
+ }
99
+ this.checkSubmit();
100
+ },
101
+ this.updatePreview = function(file)
102
+ {
103
+ var preview = $('.image_placeholder').last();
104
+
105
+ $(preview).find('img').remove();
106
+ $(preview).removeClass('is_image not_image is_document');
107
+
108
+ if (file !== null) /// file is null when empty, or error
109
  {
110
+ target_is_image = (file.type.indexOf('image') >= 0) ? true : false;
111
+ target_type = file.type;
112
+ }
113
+ // If image, load thumbnail and get dimensions.
114
+ if (file && target_is_image)
115
+ {
116
+ var img = new Image();
117
+ img.src = window.URL.createObjectURL(file);
118
+ self = this;
119
+
120
+ img.setAttribute('style', 'max-width:100%; max-height: 100%;');
121
+ img.addEventListener("load", function () {
122
+ // $(preview).find('.textlayer').text(img.naturalWidth + ' x ' + img.naturalHeight );
123
+ self.updateTextLayer(preview, img.naturalWidth + ' x ' + img.naturalHeight);
124
+ });
125
+
126
+ $(preview).prepend(img);
127
+ $(preview).addClass('is_image');
128
+ }
129
+ else if(file === null)
130
+ {
131
+ $(preview).addClass('not_image');
132
+ $(preview).find('.dashicons').removeClass().addClass('dashicons dashicons-no');
133
+ //$(preview).find('.textlayer').text('');
134
+ this.updateTextLayer(preview, '');
135
+ this.debug('File is null');
136
+ }
137
+ else { // not an image
138
+ $(preview).addClass('not_image is_document');
139
+ $(preview).find('.dashicons').removeClass().addClass('dashicons dashicons-media-document');
140
+ //$(preview).find('.textlayer').text(file.name);
141
+ this.updateTextLayer(preview, file.name);
142
+ this.debug('Not image, media document');
143
  }
144
+
145
+ if (target_type != source_type)
146
+ {
147
+ this.debug(target_type + ' not ' + source_type);
148
+ this.warningFileType();
 
149
  }
150
+ },
151
+ // replace the text, check if text is there ( or hide ), and fix the layout.
152
+ this.updateTextLayer = function (preview, newtext)
153
+ {
154
+ textlayer = $(preview).find('.textlayer');
155
+ textlayer.css('opacity', '0');
156
+ if (newtext !== false)
157
+ textlayer.text(newtext);
158
+
159
+ if (textlayer.text() !== '')
160
+ {
161
+ textlayer.css('opacity', '0.7');
162
+ // textlayer.css('margin-left', '-' + (textlayer.width() / 2 ) + 'px');
163
+ }
164
+
165
+ },
166
+ this.checkSubmit = function()
167
+ {
168
+ var check = ($('input[name="userfile"]').val().length > 0) ? true : false;
169
+
170
+ if (check)
171
+ {
172
+ $('input[type="submit"]').prop('disabled', false);
173
+ }
174
+ else {
175
+ $('input[type="submit"]').prop('disabled', true);
176
+ }
177
+ },
178
+ this.toggleErrors = function(toggle)
179
+ {
180
+ $('.form-error').fadeOut();
181
+ $('.form-warning').fadeOut();
182
+ }
183
+ this.checkUpload = function(fileItem)
184
+ {
185
+ var maxsize = emr_options.maxfilesize;
186
+
187
+ if ($('input[name="userfile"]').val().length <= 0)
188
+ {
189
+ console.info('[EMR] - Upload file value not set in form. Pick a file');
190
+ $('input[name="userfile"]').val('');
191
+ return false;
192
+ }
193
+
194
+ if (fileItem.size > maxsize)
195
+ {
196
+ console.info('[EMR] - File too big for uploading - exceeds upload limits');
197
+ this.errorFileSize(fileItem);
198
+ $('input[name="userfile"]').val('');
199
+ return false;
200
+ }
201
+ return true;
202
+ },
203
+ this.errorFileSize = function(fileItem)
204
+ {
205
+ $('.form-error.filesize').find('.fn').text(fileItem.name);
206
+ $('.form-error.filesize').fadeIn();
207
+ }
208
+ this.warningFileType = function(fileItem)
209
+ {
210
+ $('.form-warning.filetype').fadeIn();
211
+ }
212
+ this.debug = function(message)
213
+ {
214
+ console.debug(message);
215
+ }
216
+ } // emrIf
217
 
218
  window.enableMediaReplace = emrIf;
219
  window.enableMediaReplace.init();
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: ShortPixel
3
  Donate link: https://www.paypal.me/resizeImage
4
  Tags: replace, attachment, media, files, replace image, replace jpg, change media, replace media, image, file
5
- Requires at least: 4.0
6
  Tested up to: 5.2
7
  Requires PHP: 5.4
8
  Stable tag: trunk
@@ -27,16 +27,16 @@ Now you'll be able to replace any uploaded file from the media "edit" view, wher
27
  1. Just replace the file. This option requires you to upload a file of the same type as the one you are replacing. The name of the attachment will stay the same no matter what the file you upload is called.
28
  1. Replace the file, use new file name and update all links. If you check this option, the name and type of the file you are about to upload will replace the old file. All links pointing to the current file will be updated to point to the new file name.
29
 
30
- This plugin is very powerful and a must-have for any larger sites built with WordPress. It now also comes with preview of the replaced image!
31
 
32
  #### Display file modification time
33
 
34
  There is a shortcode available which picks up the file modification date and displays it in a post or a page. The code is:
35
- `[file_modified id=XX format=XXXX]` where the "id" is required and the "format" is optional and defaults to your current WordPress settings for date and time format.
36
 
37
  So `[file_modified id=870]` would display the last time the file with ID 870 was updated on your site. To get the ID for a file, check the URL when editing a file in the media library (see screenshot #4)
38
 
39
- If you want more control over the format used to display the time, you can use the format option, so `[file_modified id=870 format=Y-m-d]` would display the file modification date but not the time. The format string uses [standard PHP date() formatting tags](http://php.net/manual/en/function.date.php).
40
 
41
 
42
  #### Compatible and recommended Plugins =
@@ -47,6 +47,24 @@ If you want more control over the format used to display the time, you can use t
47
 
48
  == Changelog ==
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  = 3.3.1 =
51
 
52
  Release date: 18th June 2019
@@ -133,7 +151,7 @@ Release date: 18th June 2019
133
  = 3.0.3 =
134
  * Scrapped old method of detecting media screen, button to replace media will now show up in more places, yay!
135
  * Made sure the call to get_attached_file() no longer skips filters, in response to several users wishes.
136
- * Suppressed error messages on chmod()
137
  * Added Japanese translation (Thank you, chacomv!)
138
 
139
  = 3.0.2 =
@@ -169,7 +187,7 @@ Release date: 18th June 2019
169
  * Added call to update_attached_file() which should purge changed files for various CDN and cache plugs. Thanks Dylan Barlett for the suggestion! (http://wordpress.org/support/topic/compatibility-with-w3-total-cache)
170
  * Suppressed possible error in new hook added in 2.9.2
171
 
172
- = 2.9.2 =
173
  * Small bug fix
174
  * Added hook for developers to enable purging possible CDN when updating files - thanks rubious for the suggestion!
175
 
@@ -185,14 +203,14 @@ Release date: 18th June 2019
185
  * After uploading, the plugin now takes you back to edit screen instead of library
186
 
187
  = 2.8.2 =
188
- * Made another change to the discovery of media context which will hopefully fix a bug in certain cases. Thanks to "Joolee" at the WordPress.org forums!
189
- * Added a new, supposedly better Russian translation from "Vlad".
190
 
191
  = 2.8.1 =
192
- * Fixed a small bug which could create error messages on some systems when deleting old image files.
193
 
194
  = 2.8 =
195
- * New and safer method for deleting thumbnails when a new image file is uploaded.
196
  * New translations for simplified Chinese (thanks Tunghsiao Liu) and Italian (grazie Marco Chiesi)
197
  * Added method for detecting upload screen to ensure backward compatibility with versions pre 3.5
198
 
@@ -206,13 +224,13 @@ Release date: 18th June 2019
206
  * The "more reliable way" of determining MIME types turned out to be less reliable. Go figure. There seems to be no perfect way of performing a reliable check for MIME-types on an uploaded file that is also truly portable. I have now made checks for the availability of mime_content_type() before using it, using the old method as a fall-back. It is far from beautiful, so if anybody has a better way of doing it, please contact me!
207
 
208
  = 2.5.1 =
209
- * Bug fix - there is now a more reliable way of determining file type on your upload so you can upload PDF files without seeing that pesky "File type does not meet security guidelines" message.
210
  * New translation to Danish - thanks to Michael Bering Petersen!
211
 
212
  = 2.5 =
213
  * Tested with WordPress 3.2.1
214
  * New translation to German - thanks to Martin Lettner!
215
- * New translation to French - thanks to François Collette!
216
 
217
  = 2.4.1 =
218
  * Bug fix for WordPress 3.1 RC. Now properly tested and should be working with 3.1 whenever it finally comes out. :)
@@ -239,7 +257,7 @@ Release date: 18th June 2019
239
  * Replaced popup with inline navigation when replacing media
240
  * Added instructions in admin link under Media
241
 
242
- = 1.4.1 =
243
  * Tested with WordPress 3.0 beta 2
244
 
245
  = 1.4 =
@@ -269,23 +287,23 @@ Quick and easy installation:
269
 
270
  = What does this plugin actually do? =
271
 
272
- This plugin makes it easy to update/replace files that have been uploaded to the WordPress Media Library.
273
 
274
  = How does it work? =
275
 
276
- A new option will be available in the Edit Media view, called "Replace Media". This is where you can upload a new file to replace the old one.
277
 
278
  = I replaced a file, but it didn't change! =
279
 
280
  There are two main reasons this would happen.
281
 
282
- First, make sure you are not viewing a cached version of the file, especially if you replaced an image. Press "Refresh" in your browser to make sure.
283
 
284
- Second, if the file really looks unchanged, make sure WordPress has write permissions to the files in your uploads folder. If you have ever moved your WP installation (maybe when you moved it to a new server), the permissions on your uploaded files are commonly reset so that WordPress no longer has permissions to change the files. If you don't know how to do this, contact your web server operator.
285
 
286
  == Screenshots ==
287
 
288
- 1. The new link in the media library.
289
  2. The replace media-button as seen in the "Edit media" view.
290
  3. The upload options.
291
  4. Get the file ID in the edit file URL
2
  Contributors: ShortPixel
3
  Donate link: https://www.paypal.me/resizeImage
4
  Tags: replace, attachment, media, files, replace image, replace jpg, change media, replace media, image, file
5
+ Requires at least: 4.2
6
  Tested up to: 5.2
7
  Requires PHP: 5.4
8
  Stable tag: trunk
27
  1. Just replace the file. This option requires you to upload a file of the same type as the one you are replacing. The name of the attachment will stay the same no matter what the file you upload is called.
28
  1. Replace the file, use new file name and update all links. If you check this option, the name and type of the file you are about to upload will replace the old file. All links pointing to the current file will be updated to point to the new file name.
29
 
30
+ This plugin is very powerful and a must-have for any larger sites built with WordPress. It now also comes with preview of the replaced image!
31
 
32
  #### Display file modification time
33
 
34
  There is a shortcode available which picks up the file modification date and displays it in a post or a page. The code is:
35
+ `[file_modified id=XX format=XXXX]` where the "id" is required and the "format" is optional and defaults to your current WordPress settings for date and time format.
36
 
37
  So `[file_modified id=870]` would display the last time the file with ID 870 was updated on your site. To get the ID for a file, check the URL when editing a file in the media library (see screenshot #4)
38
 
39
+ If you want more control over the format used to display the time, you can use the format option, so `[file_modified id=870 format=Y-m-d]` would display the file modification date but not the time. The format string uses [standard PHP date() formatting tags](http://php.net/manual/en/function.date.php).
40
 
41
 
42
  #### Compatible and recommended Plugins =
47
 
48
  == Changelog ==
49
 
50
+ = 3.3.3 =
51
+
52
+ Release date: 19th July 2019
53
+ * Fix error "using $this when not in object context" on some PHP versions
54
+
55
+ = 3.3.2 =
56
+
57
+ Release date: 17th July 2019
58
+ * Check if medium size !> 400px, display that one, otherwise smallest.
59
+ * Fixed: Links not updated when using Advanced Custom Fields
60
+ * Fixed: Fails silently when file is too big for upload
61
+ * When source file does not exist, show placeholder instead of failed image load
62
+ * Fixed: Fatal error when replacing images
63
+ * Fixed: Not the right time zone on replace
64
+ * Fixed Beaver Builder incompatibility by not allowing replace with rename.
65
+ * Fixed: Cannot replace non default Wordpress file types, even those allowed to upload [ Media Library Assistant compat ]
66
+ * Fixed: error when trying to remove a file that doesn't exist - because the files are actually on another server
67
+
68
  = 3.3.1 =
69
 
70
  Release date: 18th June 2019
151
  = 3.0.3 =
152
  * Scrapped old method of detecting media screen, button to replace media will now show up in more places, yay!
153
  * Made sure the call to get_attached_file() no longer skips filters, in response to several users wishes.
154
+ * Suppressed error messages on chmod()
155
  * Added Japanese translation (Thank you, chacomv!)
156
 
157
  = 3.0.2 =
187
  * Added call to update_attached_file() which should purge changed files for various CDN and cache plugs. Thanks Dylan Barlett for the suggestion! (http://wordpress.org/support/topic/compatibility-with-w3-total-cache)
188
  * Suppressed possible error in new hook added in 2.9.2
189
 
190
+ = 2.9.2 =
191
  * Small bug fix
192
  * Added hook for developers to enable purging possible CDN when updating files - thanks rubious for the suggestion!
193
 
203
  * After uploading, the plugin now takes you back to edit screen instead of library
204
 
205
  = 2.8.2 =
206
+ * Made another change to the discovery of media context which will hopefully fix a bug in certain cases. Thanks to "Joolee" at the WordPress.org forums!
207
+ * Added a new, supposedly better Russian translation from "Vlad".
208
 
209
  = 2.8.1 =
210
+ * Fixed a small bug which could create error messages on some systems when deleting old image files.
211
 
212
  = 2.8 =
213
+ * New and safer method for deleting thumbnails when a new image file is uploaded.
214
  * New translations for simplified Chinese (thanks Tunghsiao Liu) and Italian (grazie Marco Chiesi)
215
  * Added method for detecting upload screen to ensure backward compatibility with versions pre 3.5
216
 
224
  * The "more reliable way" of determining MIME types turned out to be less reliable. Go figure. There seems to be no perfect way of performing a reliable check for MIME-types on an uploaded file that is also truly portable. I have now made checks for the availability of mime_content_type() before using it, using the old method as a fall-back. It is far from beautiful, so if anybody has a better way of doing it, please contact me!
225
 
226
  = 2.5.1 =
227
+ * Bug fix - there is now a more reliable way of determining file type on your upload so you can upload PDF files without seeing that pesky "File type does not meet security guidelines" message.
228
  * New translation to Danish - thanks to Michael Bering Petersen!
229
 
230
  = 2.5 =
231
  * Tested with WordPress 3.2.1
232
  * New translation to German - thanks to Martin Lettner!
233
+ * New translation to French - thanks to François Collette!
234
 
235
  = 2.4.1 =
236
  * Bug fix for WordPress 3.1 RC. Now properly tested and should be working with 3.1 whenever it finally comes out. :)
257
  * Replaced popup with inline navigation when replacing media
258
  * Added instructions in admin link under Media
259
 
260
+ = 1.4.1 =
261
  * Tested with WordPress 3.0 beta 2
262
 
263
  = 1.4 =
287
 
288
  = What does this plugin actually do? =
289
 
290
+ This plugin makes it easy to update/replace files that have been uploaded to the WordPress Media Library.
291
 
292
  = How does it work? =
293
 
294
+ A new option will be available in the Edit Media view, called "Replace Media". This is where you can upload a new file to replace the old one.
295
 
296
  = I replaced a file, but it didn't change! =
297
 
298
  There are two main reasons this would happen.
299
 
300
+ First, make sure you are not viewing a cached version of the file, especially if you replaced an image. Press "Refresh" in your browser to make sure.
301
 
302
+ Second, if the file really looks unchanged, make sure WordPress has write permissions to the files in your uploads folder. If you have ever moved your WP installation (maybe when you moved it to a new server), the permissions on your uploaded files are commonly reset so that WordPress no longer has permissions to change the files. If you don't know how to do this, contact your web server operator.
303
 
304
  == Screenshots ==
305
 
306
+ 1. The new link in the media library.
307
  2. The replace media-button as seen in the "Edit media" view.
308
  3. The upload options.
309
  4. Get the file ID in the edit file URL
scss/admin.scss CHANGED
@@ -24,7 +24,77 @@
24
  .image_previews
25
  {
26
  margin: 15px 0;
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
 
30
  .option-flex-wrapper
@@ -37,10 +107,39 @@
37
  flex: 1;
38
  border: 1px solid #ccc;
39
  margin: 15px 0;
40
- label
41
  {
42
- font-size: 1.2em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  }
 
44
  }
45
 
46
  .options.wrapper
@@ -130,4 +229,4 @@
130
  line-height: 1.3em; // match size
131
  }
132
  }
133
- }
24
  .image_previews
25
  {
26
  margin: 15px 0;
27
+ .image_placeholder
28
+ {
29
+ position: relative;
30
+ display: inline-block;
31
+ margin-right: 25px;
32
+ border: 1px solid #ddd;
33
+ vertical-align: top;
34
+ max-height: 500px;
35
+ .textlayer
36
+ {
37
+ font-size: 25px;
38
+ line-height: 25px;
39
+ opacity: 0.7;
40
+ position: absolute;
41
+ color: #ccc;
42
+ left: 48%;
43
+ top: 50%;
44
+ transform: translate(-50%, -50%);
45
+ border: 1px dashed #eee;
46
+ background-color: #333;
47
+ padding: 8px;
48
+ //max-width: 100%;
49
+ }
50
+ .dashicons
51
+ {
52
+ font-size: 60px;
53
+ position: absolute;
54
+ top: 50%;
55
+ margin-top: -30px;
56
+ left: 50%;
57
+ margin-left: -30px;
58
+ opacity: 0.5;
59
+
60
+ }
61
+ &.is_image
62
+ {
63
+ .dashicons::before, .dashicons { display: none }
64
+
65
+
66
+ }
67
+ &.not_image
68
+ {
69
+ img { display: none; }
70
+ .textlayer { display: none; }
71
+ &.is_document{
72
+ .textlayer {
73
+ font-size: 18px;
74
+ line-height: 20px;
75
+ display: block;
76
+
77
+ }
78
+ }
79
+ } // not_image
80
+ } // image_placeholder
81
+ } // image_previews
82
+ } // wrapper
83
+
84
+ .form-error, .form-warning
85
+ {
86
+ background: #fff;
87
+ padding: 8px;
88
+ border-left: 4px solid #ff0000;
89
+ // display: inline-block;
90
+ margin: 10px 0;
91
+ display: none;
92
+ p { margin: 0; }
93
+
94
+ }
95
+ .form-warning
96
+ {
97
+ border-left: 4px solid #ffb900;
98
  }
99
 
100
  .option-flex-wrapper
107
  flex: 1;
108
  border: 1px solid #ccc;
109
  margin: 15px 0;
110
+ .option
111
  {
112
+ position: relative;
113
+ z-index: 1;
114
+ &.disabled
115
+ {
116
+ // color: #eee;
117
+ }
118
+ label
119
+ {
120
+ font-size: 1.2em;
121
+ }
122
+ .nofeature-notice
123
+ {
124
+ border: 1px solid #ccc;
125
+ padding: 8px;
126
+ margin: 0;
127
+ position: absolute;
128
+ left: 0;
129
+ right: 0;
130
+ top: 0;
131
+ bottom: 0;
132
+ opacity: 0.8;
133
+ z-index: 9;
134
+ background: #444;
135
+ p {
136
+ text-align: center;
137
+ color: #fff;
138
+ margin: 15px 0;
139
+ }
140
+ }
141
  }
142
+
143
  }
144
 
145
  .options.wrapper
229
  line-height: 1.3em; // match size
230
  }
231
  }
232
+ } // emr_upload_form
thumbnail_updater.php CHANGED
@@ -2,6 +2,9 @@
2
  if ( ! defined( 'ABSPATH' ) )
3
  exit; // Exit if accessed directly.
4
 
 
 
 
5
  /* Simple class for updating thumbnails.
6
  *
7
  *
@@ -60,7 +63,12 @@ class ThumbnailUpdater
60
  if (isset($this->newMeta['sizes'][$sizeName]))
61
  {
62
 
63
- $oldFile = $data['file'];
 
 
 
 
 
64
  $newFile = $this->newMeta['sizes'][$sizeName]['file'];
65
 
66
  // if images are not same size.
@@ -84,6 +92,7 @@ class ThumbnailUpdater
84
  global $wpdb;
85
  $sql = "UPDATE " . $this->post_table . " set post_content = REPLACE(post_content, %s, %s)";
86
 
 
87
  foreach($this->convertArray as $convert_item)
88
  {
89
  $from = $convert_item['imageFrom'];
@@ -112,13 +121,22 @@ class ThumbnailUpdater
112
 
113
  if ( $thisdiff < $diff )
114
  {
115
- $diff = $thisdiff;
116
  $closest_file = $data['file'];
117
- $found_metasize = true;
 
 
 
 
118
  }
119
  }
120
 
121
- $this->convertArray[] = array('imageFrom' => $this->relPath . $oldData['file'], 'imageTo' => $this->relPath . $closest_file);
 
 
 
 
 
 
122
 
123
  }
124
 
2
  if ( ! defined( 'ABSPATH' ) )
3
  exit; // Exit if accessed directly.
4
 
5
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
6
+ use EnableMediaReplace\Notices\NoticeController as Notices;
7
+
8
  /* Simple class for updating thumbnails.
9
  *
10
  *
63
  if (isset($this->newMeta['sizes'][$sizeName]))
64
  {
65
 
66
+ //in some rare cases 'file' is missing
67
+ $oldFile = isset($data['file']) ? $data['file'] : null;
68
+ if(is_array($oldFile)) { $oldFile = $oldFile[0];} // HelpScout case 709692915
69
+ if(empty($oldFile)) {
70
+ return false; //make sure we don't replace in this case as we will break the URLs for all the images in the folder.
71
+ }
72
  $newFile = $this->newMeta['sizes'][$sizeName]['file'];
73
 
74
  // if images are not same size.
92
  global $wpdb;
93
  $sql = "UPDATE " . $this->post_table . " set post_content = REPLACE(post_content, %s, %s)";
94
 
95
+ Log::addDebug('Thumbnail Updater - Converting Thumbnails for sizes', $this->convertArray);
96
  foreach($this->convertArray as $convert_item)
97
  {
98
  $from = $convert_item['imageFrom'];
121
 
122
  if ( $thisdiff < $diff )
123
  {
 
124
  $closest_file = $data['file'];
125
+ if(is_array($closest_file)) { $closest_file = $closest_file[0];} // HelpScout case 709692915
126
+ if(!empty($closest_file)) {
127
+ $diff = $thisdiff;
128
+ $found_metasize = true;
129
+ }
130
  }
131
  }
132
 
133
+ if(empty($closest_file)) return;
134
+ $oldFile = $oldData['file'];
135
+ if(is_array($oldFile)) { $oldFile = $oldFile[0];} // HelpScout case 709692915
136
+ if(empty($oldFile)) {
137
+ return; //make sure we don't replace in this case as we will break the URLs for all the images in the folder.
138
+ }
139
+ $this->convertArray[] = array('imageFrom' => $this->relPath . $oldFile, 'imageTo' => $this->relPath . $closest_file);
140
 
141
  }
142
 
views/popup.php CHANGED
@@ -1,4 +1,11 @@
1
  <?php
 
 
 
 
 
 
 
2
  /**
3
  * Uploadscreen for selecting and uploading new media file
4
  *
@@ -20,6 +27,7 @@ global $wpdb;
20
 
21
  $table_name = $wpdb->prefix . "posts";
22
 
 
23
 
24
  //$sql = "SELECT guid, post_mime_type FROM $table_name WHERE ID = " . (int) $_GET["attachment_id"];
25
  //list($current_filename, $current_filetype) = $wpdb->get_row($sql, ARRAY_N);
@@ -28,10 +36,15 @@ $attachment_id = intval($_GET['attachment_id']);
28
  $attachment = get_post($attachment_id);
29
 
30
  $filepath = get_attached_file($attachment_id); // fullpath
31
- $fileurl = wp_get_attachment_url($attachment_id); //full url
32
-
33
  $filetype = $attachment->post_mime_type;
34
  $filename = basename($filepath);
 
 
 
 
 
 
 
35
 
36
  ?>
37
  <style>
@@ -49,15 +62,15 @@ $filename = basename($filepath);
49
  <h1><?php echo esc_html__("Replace Media Upload", "enable-media-replace"); ?></h1>
50
 
51
  <?php
52
- $url = admin_url( "upload.php?page=enable-media-replace/enable-media-replace.php&noheader=true&action=media_replace_upload&attachment_id=" . $attachment_id );
53
 
 
54
  $formurl = wp_nonce_url( $url, "media_replace_upload" );
55
  if (FORCE_SSL_ADMIN) {
56
  $formurl = str_replace("http:", "https:", $formurl);
57
  }
58
  ?>
59
 
60
- <form enctype="multipart/form-data" method="post" action="<?php echo $formurl; ?>">
61
  <section class='image_chooser wrapper'>
62
  <div class='section-header'> <?php _e('Choose Replacement Image', 'enable-replace-media'); ?></div>
63
 
@@ -95,11 +108,33 @@ $filename = basename($filepath);
95
  <?php } ?>
96
 
97
  <p><?php echo esc_html__("Choose a file to upload from your computer", "enable-media-replace"); ?></p>
 
 
 
98
 
99
- <input type="file" name="userfile" id="userfile" onchange="imageHandle(event);" />
 
 
 
100
  <div class='image_previews'>
101
- <img src="<?php echo $fileurl ?>" width="150px" height="150px" style="object-fit: cover"/>
102
- <img id="previewImage" src="https://via.placeholder.com/150x150" width="150px" height="150px"/>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  </div>
104
 
105
  </section>
@@ -107,30 +142,40 @@ $filename = basename($filepath);
107
  <section class='replace_type wrapper'>
108
  <div class='section-header'> <?php _e('Replacement Options', 'enable-replace-media'); ?></div>
109
 
110
- <?php do_action( 'emr_before_replace_type_options' ); ?>
 
 
111
 
112
 
113
- <?php $s3pluginExist = class_exists('S3_Uploads'); ?>
114
- <?php if ( apply_filters( 'emr_display_replace_type_options', true ) ) : ?>
115
- <?php if ( ! $s3pluginExist) : ?>
 
 
 
116
 
 
 
 
117
 
118
- <label for="replace_type_1"><input CHECKED id="replace_type_1" type="radio" name="replace_type" value="replace"> <?php echo esc_html__("Just replace the file", "enable-media-replace"); ?></label>
119
- <p class="howto"><?php printf( esc_html__("Note: This option requires you to upload a file of the same type (%s) as the one you are replacing. The name of the attachment will stay the same (%s) no matter what the file you upload is called.", "enable-media-replace"), $filetype, $filename ); ?></p>
 
 
 
 
 
 
 
 
120
 
121
- <?php endif; ?>
122
- <?php if ( apply_filters( 'emr_enable_replace_and_search', true ) ) : ?>
123
- <label for="replace_type_2"><input <?php echo $s3pluginExist ? 'CHECKED' : '' ?> id="replace_type_2" type="radio" name="replace_type" value="replace_and_search"> <?php echo __("Replace the file, use new file name and update all links", "enable-media-replace"); ?></label>
124
  <p class="howto"><?php printf( esc_html__("Note: If you check this option, the name and type of the file you are about to upload will replace the old file. All links pointing to the current file (%s) will be updated to point to the new file name.", "enable-media-replace"), $filename ); ?></p>
125
- <p class="howto"><?php echo esc_html__("Please note that if you upload a new image, only embeds/links of the original size image will be replaced in your posts.", "enable-media-replace"); ?></p>
126
- <?php endif; ?>
127
- <?php else : ?>
128
- <?php if ( ! $s3pluginExist) : ?>
129
- <input type="hidden" name="replace_type" value="replace" />
130
- <?php else : ?>
131
- <input type="hidden" name="replace_type" value="replace_and_search" />
132
- <?php endif; ?>
133
- <?php endif; ?>
134
  </section>
135
  <section class='options wrapper'>
136
  <div class='section-header'> <?php _e('Date Options', 'enable-media-replace'); ?></div>
@@ -138,7 +183,7 @@ $filename = basename($filepath);
138
  <?php
139
  $attachment_current_date = date_i18n('d/M/Y H:i', strtotime($attachment->post_date) );
140
  $time = current_time('mysql');
141
- $date = new dateTime($time);
142
  ?>
143
  <p><?php _e('When replacing the media, do you want to:', 'enable-media-replace'); ?></p>
144
  <ul>
@@ -154,7 +199,7 @@ $filename = basename($filepath);
154
 
155
  @ <input type='text' name="custom_hour" class='emr_hour' value="<?php echo $date->format('H') ?>" /> &nbsp;
156
  <input type="text" name="custom_minute" class='emr_minute' value="<?php echo $date->format('i'); ?>" />
157
- <input type="hidden" name="custom_date_formatted" value="" />
158
  </div>
159
  </div>
160
  </section>
@@ -165,37 +210,3 @@ $filename = basename($filepath);
165
  </section>
166
  </form>
167
  </div>
168
- <script>
169
- function imageHandle(event) {
170
- var file = document.getElementById("userfile");
171
- var submit = document.getElementById("submit");
172
- var preview = document.getElementById("previewImage");
173
-
174
- appendPreview(file, preview, event);
175
- enableSubmitButton(file, submit);
176
- }
177
-
178
- function appendPreview(fileSource, preview, event) {
179
- if (fileSource.value) {
180
- var file = fileSource.files[0];
181
- if (file.type.match("image/*")) {
182
- preview.setAttribute("src", window.URL.createObjectURL(file));
183
- preview.setAttribute("style", "object-fit: cover");
184
- } else {
185
- preview.setAttribute("src", "https://dummyimage.com/150x150/ccc/969696.gif&text=File");
186
- preview.removeAttribute("style");
187
- }
188
- } else {
189
- preview.setAttribute("src", "https://via.placeholder.com/150x150");
190
- }
191
- }
192
- function enableSubmitButton(file, submit)
193
- {
194
- if (file.value) {
195
- submit.disabled = false;
196
- submit.removeAttribute("disabled");
197
- } else {
198
- submit.setAttribute("disabled", true);
199
- }
200
- }
201
- </script>
1
  <?php
2
+ namespace EnableMediaReplace;
3
+
4
+ //use \EnableMediaReplace\UIHelper;
5
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
6
+ use EnableMediaReplace\Notices\NoticeController as Notices;
7
+
8
+
9
  /**
10
  * Uploadscreen for selecting and uploading new media file
11
  *
27
 
28
  $table_name = $wpdb->prefix . "posts";
29
 
30
+ Log::addDebug('Load Popup Form View');
31
 
32
  //$sql = "SELECT guid, post_mime_type FROM $table_name WHERE ID = " . (int) $_GET["attachment_id"];
33
  //list($current_filename, $current_filetype) = $wpdb->get_row($sql, ARRAY_N);
36
  $attachment = get_post($attachment_id);
37
 
38
  $filepath = get_attached_file($attachment_id); // fullpath
 
 
39
  $filetype = $attachment->post_mime_type;
40
  $filename = basename($filepath);
41
+ $source_mime = get_post_mime_type($attachment_id);
42
+
43
+ $uiHelper = new UIHelper();
44
+ $uiHelper->setPreviewSizes();
45
+ $uiHelper->setSourceSizes($attachment_id);
46
+
47
+ Log::addDebug('Popup view Data', array('id' => $attachment_id, 'source_mime' => $source_mime, 'filepath' => $filepath));
48
 
49
  ?>
50
  <style>
62
  <h1><?php echo esc_html__("Replace Media Upload", "enable-media-replace"); ?></h1>
63
 
64
  <?php
 
65
 
66
+ $url = $uiHelper->getFormUrl($attachment_id);
67
  $formurl = wp_nonce_url( $url, "media_replace_upload" );
68
  if (FORCE_SSL_ADMIN) {
69
  $formurl = str_replace("http:", "https:", $formurl);
70
  }
71
  ?>
72
 
73
+ <form enctype="multipart/form-data" method="POST" action="<?php echo $formurl; ?>">
74
  <section class='image_chooser wrapper'>
75
  <div class='section-header'> <?php _e('Choose Replacement Image', 'enable-replace-media'); ?></div>
76
 
108
  <?php } ?>
109
 
110
  <p><?php echo esc_html__("Choose a file to upload from your computer", "enable-media-replace"); ?></p>
111
+ <p><?php printf(__('Maximum file size: <strong>%s</strong>','enable-media-replace'), size_format(wp_max_upload_size() ) ) ?></p>
112
+ <div class='form-error filesize'><p><?php printf(__('%s f %s exceeds the maximum upload size for this site.', 'enable-media-replace'), '<span class="fn">', '</span>'); ?></p>
113
+ </div>
114
 
115
+ <div class='form-warning filetype'><p><?php printf(__('Replacement file is not the same filetype. This might cause unexpected issues')); ?></p></div>
116
+
117
+
118
+ <input type="file" name="userfile" id="userfile" />
119
  <div class='image_previews'>
120
+ <?php if (wp_attachment_is('image', $attachment_id) || $source_mime == 'application/pdf')
121
+ {
122
+ echo $uiHelper->getPreviewImage($attachment_id);
123
+ echo $uiHelper->getPreviewImage(-1);
124
+ }
125
+ else {
126
+ if (strlen($filepath) == 0) // check if image in error state.
127
+ {
128
+ echo $uiHelper->getPreviewError(-1);
129
+ echo $uiHelper->getPreviewImage(-1);
130
+ }
131
+ else {
132
+ echo $uiHelper->getPreviewFile($attachment_id);
133
+ echo $uiHelper->getPreviewFile(-1);
134
+ }
135
+
136
+ }
137
+ ?>
138
  </div>
139
 
140
  </section>
142
  <section class='replace_type wrapper'>
143
  <div class='section-header'> <?php _e('Replacement Options', 'enable-replace-media'); ?></div>
144
 
145
+ <?php
146
+ // these are also used in externals, for checks.
147
+ do_action( 'emr_before_replace_type_options' ); ?>
148
 
149
 
150
+ <?php $enabled_search = apply_filters( 'emr_display_replace_type_options', true );
151
+ $search_disabled = (! $enabled_search) ? 'disabled' : '';
152
+ ?>
153
+ <div class='option replace <?php echo $search_disabled ?>'>
154
+ <label for="replace_type_1" ><input CHECKED id="replace_type_1" type="radio" name="replace_type" value="replace" <?php echo $search_disabled ?> > <?php echo esc_html__("Just replace the file", "enable-media-replace"); ?>
155
+ </label>
156
 
157
+ <p class="howto">
158
+ <?php printf( esc_html__("Note: This option requires you to upload a file of the same type (%s) as the one you are replacing. The name of the attachment will stay the same (%s) no matter what the file you upload is called.", "enable-media-replace"), $filetype, $filename ); ?>
159
+ </p>
160
 
161
+ <?php do_action('emr_after_search_type_options'); ?>
162
+ </div>
163
+
164
+ <?php $enabled_replacesearch = apply_filters( 'emr_enable_replace_and_search', true );
165
+ $searchreplace_disabled = (! $enabled_replacesearch) ? 'disabled' : '';
166
+ ?>
167
+
168
+ <div class="option searchreplace <?php echo $searchreplace_disabled ?>">
169
+ <label for="replace_type_2"><input id="replace_type_2" type="radio" name="replace_type" value="replace_and_search" <?php echo $searchreplace_disabled ?> > <?php echo __("Replace the file, use new file name and update all links", "enable-media-replace"); ?>
170
+ </label>
171
 
 
 
 
172
  <p class="howto"><?php printf( esc_html__("Note: If you check this option, the name and type of the file you are about to upload will replace the old file. All links pointing to the current file (%s) will be updated to point to the new file name.", "enable-media-replace"), $filename ); ?></p>
173
+
174
+ <!-- <p class="howto"><?php echo esc_html__("Please note that if you upload a new image, only embeds/links of the original size image will be replaced in your posts.", "enable-media-replace"); ?></p> -->
175
+
176
+ <?php do_action('emr_after_replace_type_options'); ?>
177
+ </div>
178
+
 
 
 
179
  </section>
180
  <section class='options wrapper'>
181
  <div class='section-header'> <?php _e('Date Options', 'enable-media-replace'); ?></div>
183
  <?php
184
  $attachment_current_date = date_i18n('d/M/Y H:i', strtotime($attachment->post_date) );
185
  $time = current_time('mysql');
186
+ $date = new \dateTime($time);
187
  ?>
188
  <p><?php _e('When replacing the media, do you want to:', 'enable-media-replace'); ?></p>
189
  <ul>
199
 
200
  @ <input type='text' name="custom_hour" class='emr_hour' value="<?php echo $date->format('H') ?>" /> &nbsp;
201
  <input type="text" name="custom_minute" class='emr_minute' value="<?php echo $date->format('i'); ?>" />
202
+ <input type="hidden" name="custom_date_formatted" value="<?php echo $date->format('Y-m-d'); ?>" />
203
  </div>
204
  </div>
205
  </section>
210
  </section>
211
  </form>
212
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
views/upload.php CHANGED
@@ -1,7 +1,12 @@
1
  <?php
 
 
2
  if ( ! defined( 'ABSPATH' ) )
3
  exit; // Exit if accessed directly.
4
 
 
 
 
5
  if (!current_user_can('upload_files'))
6
  wp_die( esc_html__('You do not have permission to upload files.', 'enable-media-replace') );
7
 
@@ -22,6 +27,7 @@ $postmeta_table_name = $wpdb->prefix . "postmeta";
22
  * @param string $current_file
23
  * @param array|null $metadta
24
  */
 
25
  function emr_delete_current_files( $current_file, $metadta = null ) {
26
  // Delete old file
27
 
@@ -79,7 +85,7 @@ function emr_delete_current_files( $current_file, $metadta = null ) {
79
  //$mask = $prefix . "-*x*" . $suffix;
80
  //array_map( "unlink", glob( $mask ) );
81
  }
82
- }
83
 
84
  /**
85
  * Maybe remove query string from URL.
@@ -207,19 +213,13 @@ function emr_normalize_file_urls( $old, $new ) {
207
  }
208
 
209
  // Starts processing.
 
210
 
211
  // Get old guid and filetype from DB
212
  $post_id = intval($_POST['ID']); // sanitize, post_id.
213
-
214
  $replacer = new replacer($post_id);
215
 
216
- /*$sql = "SELECT post_mime_type FROM $table_name WHERE ID = '%d'";
217
- $sql = $wpdb->prepare($sql, array($post_id) );
218
- list($current_filetype) = $wpdb->get_row($sql, ARRAY_N); // seems unused as well.
219
- */
220
  // Massage a bunch of vars
221
- //$current_guid = wp_get_attachment_url($post_id); // this is used for search / replace
222
-
223
  $ID = intval($_POST["ID"]); // legacy
224
  $replace_type = isset($_POST["replace_type"]) ? sanitize_text_field($_POST["replace_type"]) : false;
225
  $timestamp_replace = intval($_POST['timestamp_replace']);
@@ -230,6 +230,10 @@ $current_file = preg_replace("|(?<!:)/{2,}|", "/", $current_file); // @todo what
230
  $current_filename = wp_basename($current_file);
231
  $current_metadata = wp_get_attachment_metadata( $post_id );
232
 
 
 
 
 
233
  switch($timestamp_replace)
234
  {
235
  case \EnableMediaReplace\Replacer::TIME_UPDATEALL:
@@ -238,17 +242,31 @@ switch($timestamp_replace)
238
  break;
239
  case \EnableMediaReplace\Replacer::TIME_CUSTOM:
240
  $custom_date = $_POST['custom_date_formatted'];
241
- $custom_hour = $_POST['custom_hour'];
242
- $custom_minute = $_POST['custom_minute'];
243
 
244
  // create a mysql time representation from what we have.
245
- $custom_date = DateTime::createFromFormat('Y-m-d H:i', $custom_date . ' ' . $custom_hour . ':' . $custom_minute );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  $datetime = $custom_date->format("Y-m-d H:i:s");
247
  break;
248
  }
249
 
250
-
251
-
252
  // We have two types: replace / replace_and_search
253
  if ($replace_type == 'replace')
254
  {
@@ -261,22 +279,34 @@ elseif ( 'replace_and_search' == $replace_type && apply_filters( 'emr_enable_rep
261
 
262
  $replacer->setTimeMode($timestamp_replace, $datetime);
263
 
264
-
265
-
266
  if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) {
267
 
 
 
268
  // New method for validating that the uploaded file is allowed, using WP:s internal wp_check_filetype_and_ext() function.
269
  $filedata = wp_check_filetype_and_ext($_FILES["userfile"]["tmp_name"], $_FILES["userfile"]["name"]);
270
 
 
 
 
 
 
 
 
 
 
271
  if ($filedata["ext"] == "") {
272
- echo esc_html__("File type does not meet security guidelines. Try another.", 'enable-media-replace');
273
- exit;
 
 
274
  }
275
 
276
  // Here we have the uploaded file
277
 
278
- $thumbUpdater = new ThumbnailUpdater($ID);
279
- $thumbUpdater->setOldMetadata($current_metadata);
280
 
281
  $new_filename = $_FILES["userfile"]["name"];
282
  //$new_filesize = $_FILES["userfile"]["size"]; // Seems not to be in use.
@@ -288,9 +318,15 @@ if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) {
288
  // Gather all functions that both options do.
289
  do_action('wp_handle_replace', array('post_id' => $post_id));
290
 
291
- $replacer->replaceWith($_FILES["userfile"]["tmp_name"], $new_filename);
292
-
293
- #echo "Updated: " . $number_of_updates;
 
 
 
 
 
 
294
 
295
  $returnurl = admin_url("/post.php?post={$_POST["ID"]}&action=edit&message=1");
296
 
@@ -300,15 +336,17 @@ if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) {
300
  } else {
301
  //TODO Better error handling when no file is selected.
302
  //For now just go back to media management
303
- $returnurl = admin_url("upload.php");
 
 
 
 
304
  }
305
 
306
- if (FORCE_SSL_ADMIN) {
307
- $returnurl = str_replace("http:", "https:", $returnurl);
308
- }
309
 
310
  // Allow developers to override $returnurl
311
- $returnurl = apply_filters('emr_returnurl', $returnurl);
312
-
313
- wp_redirect($returnurl);
314
  ?>
1
  <?php
2
+ namespace EnableMediaReplace;
3
+
4
  if ( ! defined( 'ABSPATH' ) )
5
  exit; // Exit if accessed directly.
6
 
7
+ use EnableMediaReplace\ShortPixelLogger\ShortPixelLogger as Log;
8
+ use EnableMediaReplace\Notices\NoticeController as Notices;
9
+
10
  if (!current_user_can('upload_files'))
11
  wp_die( esc_html__('You do not have permission to upload files.', 'enable-media-replace') );
12
 
27
  * @param string $current_file
28
  * @param array|null $metadta
29
  */
30
+ /* Phased-out, marked for delete.
31
  function emr_delete_current_files( $current_file, $metadta = null ) {
32
  // Delete old file
33
 
85
  //$mask = $prefix . "-*x*" . $suffix;
86
  //array_map( "unlink", glob( $mask ) );
87
  }
88
+ } */
89
 
90
  /**
91
  * Maybe remove query string from URL.
213
  }
214
 
215
  // Starts processing.
216
+ $uihelper = new UIHelper();
217
 
218
  // Get old guid and filetype from DB
219
  $post_id = intval($_POST['ID']); // sanitize, post_id.
 
220
  $replacer = new replacer($post_id);
221
 
 
 
 
 
222
  // Massage a bunch of vars
 
 
223
  $ID = intval($_POST["ID"]); // legacy
224
  $replace_type = isset($_POST["replace_type"]) ? sanitize_text_field($_POST["replace_type"]) : false;
225
  $timestamp_replace = intval($_POST['timestamp_replace']);
230
  $current_filename = wp_basename($current_file);
231
  $current_metadata = wp_get_attachment_metadata( $post_id );
232
 
233
+
234
+ $redirect_error = $uihelper->getFailedRedirect($post_id);
235
+ $redirect_success = $uihelper->getSuccesRedirect($post_id);
236
+
237
  switch($timestamp_replace)
238
  {
239
  case \EnableMediaReplace\Replacer::TIME_UPDATEALL:
242
  break;
243
  case \EnableMediaReplace\Replacer::TIME_CUSTOM:
244
  $custom_date = $_POST['custom_date_formatted'];
245
+ $custom_hour = str_pad($_POST['custom_hour'],2,0, STR_PAD_LEFT);
246
+ $custom_minute = str_pad($_POST['custom_minute'], 2, 0, STR_PAD_LEFT);
247
 
248
  // create a mysql time representation from what we have.
249
+ Log::addDebug($_POST);
250
+ Log::addDebug('Custom Date - ' . $custom_date . ' ' . $custom_hour . ':' . $custom_minute );
251
+ $custom_date = \DateTime::createFromFormat('Y-m-d G:i', $custom_date . ' ' . $custom_hour . ':' . $custom_minute );
252
+ if ($custom_date === false)
253
+ {
254
+
255
+ wp_safe_redirect($redirect_error);
256
+ $errors = \DateTime::getLastErrors();
257
+ $error = '';
258
+ if (isset($errors['errors']))
259
+ {
260
+ $error = implode(',', $errors['errors']);
261
+ }
262
+ Notices::addError(sprintf(__('Invalid Custom Date. Please custom date values (%s)', 'enable-media-replace'), $error));
263
+
264
+ exit();
265
+ }
266
  $datetime = $custom_date->format("Y-m-d H:i:s");
267
  break;
268
  }
269
 
 
 
270
  // We have two types: replace / replace_and_search
271
  if ($replace_type == 'replace')
272
  {
279
 
280
  $replacer->setTimeMode($timestamp_replace, $datetime);
281
 
282
+ /** Check if file is uploaded properly **/
 
283
  if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) {
284
 
285
+ Log::addDebug($_FILES['userfile']);
286
+
287
  // New method for validating that the uploaded file is allowed, using WP:s internal wp_check_filetype_and_ext() function.
288
  $filedata = wp_check_filetype_and_ext($_FILES["userfile"]["tmp_name"], $_FILES["userfile"]["name"]);
289
 
290
+ Log::addDebug('Data after check', $filedata);
291
+ if (isset($_FILES['userfile']['error']) && $_FILES['userfile']['error'] > 0)
292
+ {
293
+ $e = new RunTimeException('File Uploaded Failed');
294
+ Notices::addError($e->getMessage());
295
+ wp_safe_redirect($redirect_error);
296
+ exit();
297
+ }
298
+
299
  if ($filedata["ext"] == "") {
300
+
301
+ Notices::addError(esc_html__("File type does not meet security guidelines. Try another.", 'enable-media-replace') );
302
+ wp_safe_redirect($redirect_error);
303
+ exit();
304
  }
305
 
306
  // Here we have the uploaded file
307
 
308
+ //$thumbUpdater = new ThumbnailUpdater($ID);
309
+ //$thumbUpdater->setOldMetadata($current_metadata);
310
 
311
  $new_filename = $_FILES["userfile"]["name"];
312
  //$new_filesize = $_FILES["userfile"]["size"]; // Seems not to be in use.
318
  // Gather all functions that both options do.
319
  do_action('wp_handle_replace', array('post_id' => $post_id));
320
 
321
+ try
322
+ {
323
+ $replacer->replaceWith($_FILES["userfile"]["tmp_name"], $new_filename);
324
+ }
325
+ catch(\RunTimeException $e)
326
+ {
327
+ Log::addError($e->getMessage());
328
+ exit($e->getMessage());
329
+ }
330
 
331
  $returnurl = admin_url("/post.php?post={$_POST["ID"]}&action=edit&message=1");
332
 
336
  } else {
337
  //TODO Better error handling when no file is selected.
338
  //For now just go back to media management
339
+ //$returnurl = admin_url("upload.php");
340
+ Log::addInfo('Failed. Redirecting - '. $redirect_error);
341
+ Notices::addError(__('File Upload seems to have failed. No files were returned by system','enable-media-replace'));
342
+ wp_safe_redirect($redirect_error);
343
+ exit();
344
  }
345
 
346
+ Notices::addSuccess(__('File successfully replaced'));
 
 
347
 
348
  // Allow developers to override $returnurl
349
+ //$returnurl = apply_filters('emr_returnurl', $returnurl);
350
+ wp_redirect($redirect_success);
351
+ exit();
352
  ?>