Enable Media Replace - Version 3.3.0

Version Description

  • When replacing an image and changing the name, Search / Replace is now also done on the meta_value of postmeta.
  • Replace PDF thumbnails too
  • Copy title from EXIF
  • RTL View incorporated into the CSS
  • wp_handle_upload filter should be treated as such (and not as action)
  • Use wp_attached_file instead of the GUID
  • Fix: replace missing file
  • Fix: aphostrophe breaking the upload
  • Fix: broken "before" image
  • Fix: update properly the date
  • Fix: errors for non-image items in Media Library
  • Fix: empty admin menu item created
  • Refactored all the code
Download this release

Release Info

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

Code changes from version 3.2.9 to 3.3.0

classes/cache.php ADDED
@@ -0,0 +1,121 @@
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+
4
+ class emrCache
5
+ {
6
+ protected $has_supercache = false; // supercache seems to replace quite fine, without our help. @todo Test if this is needed
7
+ protected $has_w3tc = false;
8
+ protected $has_wpengine = false;
9
+ protected $has_fastestcache = false;
10
+ protected $has_siteground = false;
11
+
12
+ public function __construct()
13
+ {
14
+
15
+ }
16
+
17
+ /** Checks which cache plugins are active on the moment a flush is needed */
18
+ public function checkCaches()
19
+ {
20
+ if ( function_exists( 'w3tc_pgcache_flush' ) )
21
+ $this->has_w3tc = true;
22
+
23
+ if ( function_exists('wp_cache_clean_cache') )
24
+ $this->has_supercache = true;
25
+
26
+ if ( class_exists( 'WpeCommon' ) )
27
+ $this->has_wpengine = true;
28
+
29
+ global $wp_fastest_cache;
30
+ if ( method_exists( 'WpFastestCache', 'deleteCache' ) && !empty( $wp_fastest_cache ) )
31
+ $this->has_fastestcache = true;
32
+
33
+ // SG SuperCacher
34
+ if (function_exists('sg_cachepress_purge_cache')) {
35
+ $this->has_siteground = true;
36
+ }
37
+
38
+ // @todo WpRocket?
39
+ // @todo BlueHost Caching?
40
+ }
41
+
42
+ /* Tries to flush cache there were we have issues
43
+ *
44
+ * @param Array $args Argument Array to provide data.
45
+ */
46
+ public function flushCache($args)
47
+ {
48
+ $defaults = array(
49
+ 'flush_mode' => 'post',
50
+ 'post_id' => 0,
51
+ );
52
+
53
+ $args = wp_parse_args($args, $defaults);
54
+ $post_id = $args['post_id']; // can be zero!
55
+
56
+ // important - first check the available cache plugins
57
+ $this->checkCaches();
58
+
59
+ // general WP
60
+ if ($post_id > 0)
61
+ clean_post_cache($post_id);
62
+ else
63
+ wp_cache_flush();
64
+
65
+ /* Verified working without.
66
+ if ($this->has_supercache)
67
+ $this->removeSuperCache();
68
+ */
69
+ if ($this->has_w3tc)
70
+ $this->removeW3tcCache();
71
+
72
+ if ($this->has_wpengine)
73
+ $this->removeWpeCache();
74
+
75
+ if ($this->has_siteground)
76
+ $this->removeSiteGround();
77
+
78
+ if ($this->has_fastestcache)
79
+ $this->removeFastestCache();
80
+
81
+ }
82
+
83
+ protected function removeSuperCache()
84
+ {
85
+ global $file_prefix, $supercachedir;
86
+ if ( empty( $supercachedir ) && function_exists( 'get_supercache_dir' ) ) {
87
+ $supercachedir = get_supercache_dir();
88
+ }
89
+ wp_cache_clean_cache( $file_prefix );
90
+ }
91
+
92
+ protected function removeW3tcCache()
93
+ {
94
+ w3tc_pgcache_flush();
95
+ }
96
+
97
+ protected function removeWpeCache()
98
+ {
99
+ if ( method_exists( 'WpeCommon', 'purge_memcached' ) ) {
100
+ WpeCommon::purge_memcached();
101
+ }
102
+ if ( method_exists( 'WpeCommon', 'clear_maxcdn_cache' ) ) {
103
+ WpeCommon::clear_maxcdn_cache();
104
+ }
105
+ if ( method_exists( 'WpeCommon', 'purge_varnish_cache' ) ) {
106
+ WpeCommon::purge_varnish_cache();
107
+ }
108
+ }
109
+
110
+ protected function removeFastestCache()
111
+ {
112
+ global $wp_fastest_cache;
113
+ $wp_fastest_cache->deleteCache();
114
+ }
115
+
116
+ protected function removeSiteGround()
117
+ {
118
+ sg_cachepress_purge_cache();
119
+ }
120
+
121
+ }
classes/emr-plugin.php ADDED
@@ -0,0 +1,293 @@
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);
20
+ $this->plugin_url = plugin_dir_url(EMR_ROOT_FILE);
21
+
22
+ // init plugin
23
+ add_action('admin_menu', array($this,'menu'));
24
+ add_action('admin_init', array($this,'init'));
25
+ add_action('admin_enqueue_scripts', array($this,'admin_scripts'));
26
+
27
+ // content filters
28
+ add_filter('attachment_fields_to_edit', array($this, 'attachment_editor'), 10, 2);
29
+ add_filter('media_row_actions', array($this,'add_media_action'), 10, 2);
30
+ add_action('attachment_submitbox_misc_actions', array($this,'admin_date_replaced_media_on_edit_media_screen'), 91 );
31
+ add_filter('upload_mimes', array($this,'add_mime_types'), 1, 1);
32
+
33
+ // notices
34
+ add_action('admin_notices', array($this,'display_notices'));
35
+ add_action('network_admin_notices', array($this,'display_network_notices'));
36
+ add_action('wp_ajax_emr_dismiss_notices', array($this,'dismiss_notices'));
37
+
38
+ // shortcode
39
+ add_shortcode('file_modified', array($this, 'get_modified_date'));
40
+
41
+ }
42
+
43
+ /**
44
+ * Register this file in WordPress so we can call it with a ?page= GET var.
45
+ * To suppress it in the menu we give it an empty menu title.
46
+ */
47
+ public function menu()
48
+ {
49
+ add_submenu_page(null, esc_html__("Replace media", "enable-media-replace"), esc_html__("Replace media", "enable-media-replace"), 'upload_files', 'enable-media-replace/enable-media-replace', array($this, 'route'));
50
+ }
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 */
62
+ public function route()
63
+ {
64
+ global $plugin_page;
65
+ switch($plugin_page)
66
+ {
67
+ case 'enable-media-replace/enable-media-replace.php':
68
+ $action = isset($_GET['action']) ? sanitize_text_field($_GET['action']) : '';
69
+ wp_enqueue_style('emr_style');
70
+ wp_enqueue_script('jquery-ui-datepicker');
71
+ wp_enqueue_style('jquery-ui-datepicker');
72
+ wp_enqueue_script('emr_admin');
73
+
74
+ if (! check_admin_referer( $action, '_wpnonce') )
75
+ {
76
+ die('Invalid Nonce');
77
+ }
78
+
79
+ // @todo Later this should be move to it's own controller, and built view from there.
80
+ if ( $action == 'media_replace' ) {
81
+ if ( array_key_exists("attachment_id", $_GET) && intval($_GET["attachment_id"]) > 0) {
82
+ require_once($this->plugin_path . "views/popup.php"); // warning variables like $action be overwritten here.
83
+ }
84
+ }
85
+ elseif ( $action == 'media_replace_upload' ) {
86
+ require_once($this->plugin_path . 'views/upload.php');
87
+ }
88
+ else {
89
+ exit('Something went wrong loading page, please try again');
90
+ }
91
+
92
+ break;
93
+ }
94
+
95
+ }
96
+
97
+ /** register styles and scripts
98
+ *
99
+ * Nothing should ever by -enqueued- here, just registered.
100
+ */
101
+ public function admin_scripts()
102
+ {
103
+ if (is_rtl())
104
+ {
105
+ wp_register_style('emr_style', plugins_url('css/admin.rtl.css', EMR_ROOT_FILE) );
106
+ }
107
+ else {
108
+ wp_register_style('emr_style', plugins_url('css/admin.css', EMR_ROOT_FILE) );
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
+
116
+ /** Utility function for the Jquery UI Datepicker */
117
+ function convertdate( $sFormat ) {
118
+ switch( $sFormat ) {
119
+ //Predefined WP date formats
120
+ case 'F j, Y':
121
+ return( 'MM dd, yy' );
122
+ break;
123
+ case 'Y/m/d':
124
+ return( 'yy/mm/dd' );
125
+ break;
126
+ case 'm/d/Y':
127
+ return( 'mm/dd/yy' );
128
+ break;
129
+ case 'd/m/Y':
130
+ default:
131
+ return( 'dd/mm/yy' );
132
+ break;
133
+ }
134
+ }
135
+
136
+ /** Get the URL to the media replace page
137
+ * @param $attach_id The attachment ID to replace
138
+ * @return Admin URL to the page.
139
+ */
140
+ protected function getMediaReplaceURL($attach_id)
141
+ {
142
+ $url = admin_url( "upload.php");
143
+ $url = add_query_arg(array(
144
+ 'page' => 'enable-media-replace/enable-media-replace.php',
145
+ 'action' => 'media_replace',
146
+ 'attachment_id' => $attach_id,
147
+ ), $url);
148
+
149
+ return $url;
150
+
151
+ }
152
+
153
+ /**
154
+ * Add some new fields to the attachment edit panel.
155
+ * @param array form fields edit panel
156
+ * @return array form fields with enable-media-replace fields added
157
+ */
158
+ public function attachment_editor($form_fields, $post)
159
+ {
160
+ $url = $this->getMediaReplaceURL($post->ID);
161
+
162
+ $action = "media_replace";
163
+ $editurl = wp_nonce_url( $url, $action );
164
+
165
+ /* Unneeded - admin_url already checks for force_ssl_admin ( in set_scheme function )
166
+ if (FORCE_SSL_ADMIN) {
167
+ $editurl = str_replace("http:", "https:", $editurl);
168
+ } */
169
+ $link = "href=\"$editurl\"";
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;
177
+ }
178
+
179
+ /**
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
187
+ return $mime_types;
188
+ }
189
+
190
+ /**
191
+ * Function called by filter 'media_row_actions'
192
+ * Enables linking to EMR straight from the media library
193
+ */
194
+ public function add_media_action( $actions, $post) {
195
+ $url = $this->getMediaReplaceURL($post->ID);
196
+ $action = "media_replace";
197
+ $editurl = wp_nonce_url( $url, $action );
198
+
199
+ /* See above, not needed.
200
+ if (FORCE_SSL_ADMIN) {
201
+ $editurl = str_replace("http:", "https:", $editurl);
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
+
209
+
210
+ public function display_notices() {
211
+ $current_screen = get_current_screen();
212
+
213
+ $crtScreen = function_exists("get_current_screen") ? get_current_screen() : (object)array("base" => false);
214
+
215
+ if(current_user_can( 'activate_plugins' ) && !get_option( 'emr_news') && !is_plugin_active('shortpixel-image-optimiser/wp-shortpixel.php')
216
+ && ($crtScreen->base == "upload" || $crtScreen->base == "plugins")
217
+ //for network installed plugins, don't display the message on subsites.
218
+ && !(function_exists('is_multisite') && is_multisite() && is_plugin_active_for_network('enable-media-replace/enable-media-replace.php') && !is_main_site()))
219
+ {
220
+ require_once($this->plugin_path . '/views/notice.php');
221
+ }
222
+ }
223
+
224
+ public function display_network_notices() {
225
+ if(current_user_can( 'activate_plugins' ) && !get_option( 'emr_news') && !is_plugin_active_for_network('shortpixel-image-optimiser/wp-shortpixel.php')) {
226
+ require_once( str_replace("enable-media-replace.php", "notice.php", __FILE__) );
227
+ }
228
+ }
229
+
230
+ /* Ajax function to dismiss notice */
231
+ public function dismiss_notices() {
232
+ update_option( 'emr_news', true);
233
+ exit(json_encode(array("Status" => 0)));
234
+ }
235
+
236
+ /** Outputs the replaced date of the media on the edit_attachment screen
237
+ *
238
+ * @param $post Obj Post Object
239
+ */
240
+ function admin_date_replaced_media_on_edit_media_screen($post) {
241
+ $post_id = $post->ID;
242
+
243
+ if ( $post->post_modified == $post->post_date ) {
244
+ return;
245
+ }
246
+
247
+ $modified = date_i18n( __( 'M j, Y @ H:i' ) , strtotime( $post->post_modified ) );
248
+
249
+ ?>
250
+ <div class="misc-pub-section curtime">
251
+ <span id="timestamp"><?php echo esc_html__( 'Revised', 'enable-media-replace' ); ?>: <b><?php echo $modified; ?></b></span>
252
+ </div>
253
+ <?php
254
+ }
255
+
256
+ /**
257
+ * Shorttag function to show the media file modification date/time.
258
+ * @param array shorttag attributes
259
+ * @return string content / replacement shorttag
260
+ * @todo Note this returns the wrong date, ie. server date not corrected for timezone. Function could be removed altogether, not sure about purpose.
261
+ */
262
+ public function get_modified_date($atts) {
263
+ $id=0;
264
+ $format= '';
265
+
266
+ extract(shortcode_atts(array(
267
+ 'id' => '',
268
+ 'format' => get_option('date_format') . " " . get_option('time_format'),
269
+ ), $atts));
270
+
271
+ if ($id == '') return false;
272
+
273
+ // Get path to file
274
+ $current_file = get_attached_file($id);
275
+
276
+ if ( ! file_exists( $current_file ) ) {
277
+ return false;
278
+ }
279
+
280
+ // Get file modification time
281
+ $filetime = filemtime($current_file);
282
+
283
+ if ( false !== $filetime ) {
284
+ // do date conversion
285
+ return date( $format, $filetime );
286
+ }
287
+
288
+ return false;
289
+ }
290
+
291
+
292
+
293
+ } // class
classes/file.php ADDED
@@ -0,0 +1,76 @@
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+
4
+ class emrFile
5
+ {
6
+
7
+ protected $file; // the full file w/ path.
8
+ protected $extension;
9
+ protected $fileName;
10
+ protected $filePath;
11
+ protected $fileURL;
12
+ protected $fileMime;
13
+ protected $permissions = 0;
14
+
15
+ protected $exists = false;
16
+
17
+ public function __construct($file)
18
+ {
19
+ clearstatcache($file);
20
+ // file can not exist i.e. crashed files replacement and the lot.
21
+ if ( file_exists($file))
22
+ {
23
+ $this->exists = true;
24
+ }
25
+
26
+ $this->file = $file;
27
+ $fileparts = pathinfo($file);
28
+
29
+ $this->fileName = isset($fileparts['basename']) ? $fileparts['basename'] : '';
30
+ $this->filePath = isset($fileparts['dirname']) ? $fileparts['dirname'] : '';
31
+ $this->extension = isset($fileparts['extension']) ? $fileparts['extension'] : '';
32
+ if ($this->exists) // doesn't have to be.
33
+ $this->permissions = fileperms($file) & 0777;
34
+
35
+ $filedata = wp_check_filetype_and_ext($this->file, $this->fileName);
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()
43
+ {
44
+ return $this->file;
45
+ }
46
+
47
+ public function getPermissions()
48
+ {
49
+ return $this->permissions;
50
+ }
51
+
52
+ public function setPermissions($permissions)
53
+ {
54
+ @chmod($this->file, $permissions);
55
+ }
56
+
57
+ public function getFilePath()
58
+ {
59
+ return $this->filePath;
60
+ }
61
+
62
+ public function getFileName()
63
+ {
64
+ return $this->fileName;
65
+ }
66
+
67
+ public function getFileMime()
68
+ {
69
+ return $this->fileMime;
70
+ }
71
+
72
+
73
+ }
74
+
75
+
76
+ ?>
classes/replacer.php ADDED
@@ -0,0 +1,309 @@
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+ use \EnableMediaReplace\emrFile as File;
4
+
5
+ class Replacer
6
+ {
7
+ protected $post_id;
8
+
9
+ // everything source is the attachment being replaced
10
+ protected $sourceFile; // File Object
11
+ protected $source_post; // wpPost;
12
+ protected $source_is_image;
13
+ protected $source_metadata;
14
+ protected $source_url;
15
+
16
+ // everything target is what will be.
17
+ protected $targetFile;
18
+ protected $targetName;
19
+ protected $target_metadata;
20
+ protected $target_url;
21
+
22
+ protected $replaceMode = null;
23
+ protected $timeMode = null;
24
+ protected $datetime = null;
25
+
26
+ protected $ThumbnailUpdater; // class
27
+
28
+ const MODE_REPLACE = 1;
29
+ const MODE_SEARCHREPLACE = 2;
30
+
31
+ const TIME_UPDATEALL = 1;
32
+ const TIME_UPDATEMODIFIED = 2;
33
+ const TIME_CUSTOM = 3;
34
+
35
+ public function __construct($post_id)
36
+ {
37
+ $this->post_id = $post_id;
38
+
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 );
45
+ $this->source_url = wp_get_attachment_url($post_id);
46
+
47
+ $this->ThumbnailUpdater = new \ThumbnailUpdater($post_id);
48
+ $this->ThumbnailUpdater->setOldMetadata($this->source_metadata);
49
+ }
50
+
51
+ public function setMode($mode)
52
+ {
53
+ $this->replaceMode = $mode;
54
+ }
55
+
56
+ public function setTimeMode($mode, $datetime = 0)
57
+ {
58
+ if ($datetime == 0)
59
+ $datetime = current_time('mysql');
60
+
61
+ $this->datetime = $datetime;
62
+ $this->timeMode = $mode;
63
+ }
64
+
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
+ {
71
+ global $wpdb;
72
+ //$this->targetFile = new File($file);
73
+ $this->targetName = $fileName;
74
+ //$this->targetFile = new File($file); // this will point to /tmp!
75
+
76
+ $this->removeCurrent(); // tries to remove the current files.
77
+ $targetFile = $this->getTargetFile();
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)
96
+ chmod( $targetFile, $this->sourceFile->getPermissions() ); // restore permissions
97
+ else {
98
+ // 'Setting permissions failed';
99
+ }
100
+
101
+ // update the file attached. This is required for wp_get_attachment_url to work.
102
+ update_attached_file($this->post_id, $this->targetFile->getFullFilePath() );
103
+ $this->target_url = wp_get_attachment_url($this->post_id);
104
+
105
+ // Run the filter, so other plugins can hook if needed.
106
+ $filtered = apply_filters( 'wp_handle_upload', array(
107
+ 'file' => $this->targetFile->getFullFilePath(),
108
+ 'url' => $this->target_url,
109
+ 'type' => $this->targetFile->getFileMime(),
110
+ ), 'sideload');
111
+
112
+ // check if file changed during filter. Set changed to attached file meta properly.
113
+ if (isset($filtered['file']) && $filtered['file'] != $this->targetFile->getFullFilePath() )
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() );
120
+ wp_update_attachment_metadata( $this->post_id, $metadata );
121
+ $this->target_metadata = $metadata;
122
+
123
+ if ($this->replaceMode == self::MODE_SEARCHREPLACE)
124
+ {
125
+ $title = $this->getNewTitle();
126
+
127
+ $update_ar = array('ID' => $this->post_id);
128
+ $update_ar['post_title'] = $title;
129
+ $update_ar['post_name'] = sanitize_title($title);
130
+ // $update_ar['guid'] = wp_get_attachment_url($this->post_id);
131
+ $update_ar['post_mime_type'] = $this->targetFile->getFileMime();
132
+ $post_id = \wp_update_post($update_ar, true);
133
+
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();
140
+ foreach ($errors as $error) {
141
+ echo $error;
142
+ }
143
+ }
144
+ $this->doSearchReplace();
145
+ do_action("enable-media-replace-upload-done", $this->target_url, $this->source_url);
146
+ }
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.
155
+ // This must be done after wp_update_posts
156
+ $this->updateDate(); // updates the date.
157
+
158
+ // Give the caching a kick. Off pending specifics.
159
+ $cache_args = array(
160
+ 'flush_mode' => 'post',
161
+ 'post_id' => $this->post_id,
162
+ );
163
+
164
+ $cache = new emrCache();
165
+ $cache->flushCache($cache_args);
166
+
167
+ }
168
+
169
+ protected function getNewTitle()
170
+ {
171
+ $title = $this->targetFile->getFileName();
172
+ $meta = $this->target_metadata;
173
+
174
+ if (isset($meta['image_meta']))
175
+ {
176
+ if (isset($meta['image_meta']['title']))
177
+ {
178
+ if (strlen($meta['image_meta']['title']) > 0)
179
+ {
180
+ $title = $meta['image_meta']['title'];
181
+ }
182
+ }
183
+ }
184
+
185
+ // Thanks Jonas Lundman (http://wordpress.org/support/topic/add-filter-hook-suggestion-to)
186
+ $title = apply_filters( 'enable_media_replace_title', $title );
187
+
188
+ return $title;
189
+ }
190
+
191
+ /** Returns a full target path to place to new file. Including the file name! **/
192
+ protected function getTargetFile()
193
+ {
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
+ {
201
+ $path = $this->sourceFile->getFilePath();
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
211
+ * This might fail on certain files, but this is not an indication of success ( remove might fail, but overwrite can still work)
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 */
221
+ protected function updateDate()
222
+ {
223
+ global $wpdb;
224
+ $post_date = $this->datetime;
225
+ $post_date_gmt = get_gmt_from_date($post_date);
226
+
227
+ $update_ar = array('ID' => $this->post_id);
228
+ if ($this->timeMode == static::TIME_UPDATEALL || $this->timeMode == static::TIME_CUSTOM)
229
+ {
230
+ $update_ar['post_date'] = $post_date;
231
+ $update_ar['post_date_gmt'] = $post_date_gmt;
232
+ }
233
+ else {
234
+ //$update_ar['post_date'] = 'post_date';
235
+ // $update_ar['post_date_gmt'] = 'post_date_gmt';
236
+ }
237
+ $update_ar['post_modified'] = $post_date;
238
+ $update_ar['post_modified_gmt'] = $post_date_gmt;
239
+
240
+ $updated = $wpdb->update( $wpdb->posts, $update_ar , array('ID' => $this->post_id) );
241
+
242
+ wp_cache_delete($this->post_id, 'posts');
243
+
244
+
245
+ /* $sql = $wpdb->prepare(
246
+ "UPDATE $table_name SET post_date = '$post_date', post_date_gmt = '$post_date_gmt' WHERE ID = %d;",
247
+ $ID
248
+ );
249
+ $wpdb->query($sql); */
250
+ }
251
+
252
+
253
+ protected function doSearchReplace()
254
+ {
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(
262
+ "SELECT ID, post_content FROM $wpdb->posts WHERE post_status = 'publish' AND post_content LIKE %s;",
263
+ '%' . $current_base_url . '%'));
264
+
265
+ //INNER JOIN ' . $wpdb->posts . ' on ' . $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id
266
+
267
+ $postmeta_sql = 'SELECT meta_id, post_id, meta_value FROM ' . $wpdb->postmeta . '
268
+ WHERE post_id in (SELECT ID from '. $wpdb->posts . ' where post_status = "publish") AND meta_value like %s ';
269
+ $postmeta_sql = $wpdb->remove_placeholder_escape($wpdb->prepare($postmeta_sql, '%' . $current_base_url . '%'));
270
+
271
+ $rsmeta = $wpdb->get_results($postmeta_sql, ARRAY_A);
272
+ $rs = $wpdb->get_results( $posts_sql, ARRAY_A );
273
+
274
+ $number_of_updates = 0;
275
+
276
+ $search_urls = emr_get_file_urls( $this->source_url, $this->source_metadata );
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.
285
+ $post_content = $rows["post_content"];
286
+ $post_content = str_replace( $search_urls, $replace_urls, $post_content );
287
+
288
+ $sql = $wpdb->prepare(
289
+ "UPDATE $wpdb->posts SET post_content = %s WHERE ID = %d;",
290
+ array($post_content, $rows["ID"])
291
+ );
292
+ // echo "$sql <BR>";
293
+ $wpdb->query( $sql );
294
+ }
295
+ foreach ($rsmeta as $row)
296
+ {
297
+ $number_of_updates++;
298
+ $content = $row['meta_value'];
299
+ $content = str_replace($search_urls, $replace_urls, $content);
300
+
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
+
309
+ } // class
css/admin.css ADDED
@@ -0,0 +1,834 @@
1
+ .ui-widget-content {
2
+ border: 1px solid #dddddd;
3
+ background: #ffffff;
4
+ color: #333333; }
5
+
6
+ .ui-widget-overlay {
7
+ position: fixed;
8
+ top: 0;
9
+ left: 0;
10
+ width: 100%;
11
+ height: 100%; }
12
+
13
+ .ui-datepicker {
14
+ width: 17em;
15
+ padding: .2em .2em 0;
16
+ display: none; }
17
+
18
+ .ui-datepicker .ui-datepicker-header {
19
+ position: relative;
20
+ padding: .2em 0; }
21
+
22
+ .ui-datepicker .ui-datepicker-prev,
23
+ .ui-datepicker .ui-datepicker-next {
24
+ position: absolute;
25
+ top: 2px;
26
+ width: 1.8em;
27
+ height: 1.8em; }
28
+
29
+ .ui-datepicker .ui-datepicker-prev-hover,
30
+ .ui-datepicker .ui-datepicker-next-hover {
31
+ top: 1px; }
32
+
33
+ .ui-datepicker .ui-datepicker-prev {
34
+ left: 2px; }
35
+
36
+ .ui-datepicker .ui-datepicker-next {
37
+ right: 2px; }
38
+
39
+ .ui-datepicker .ui-datepicker-prev-hover {
40
+ left: 1px; }
41
+
42
+ .ui-datepicker .ui-datepicker-next-hover {
43
+ right: 1px; }
44
+
45
+ .ui-datepicker .ui-datepicker-prev span,
46
+ .ui-datepicker .ui-datepicker-next span {
47
+ display: block;
48
+ position: absolute;
49
+ left: 50%;
50
+ margin-left: -8px;
51
+ top: 50%;
52
+ margin-top: -8px; }
53
+
54
+ .ui-datepicker .ui-datepicker-title {
55
+ margin: 0 2.3em;
56
+ line-height: 1.8em;
57
+ text-align: center; }
58
+
59
+ .ui-datepicker .ui-datepicker-title select {
60
+ font-size: 1em;
61
+ margin: 1px 0; }
62
+
63
+ .ui-datepicker select.ui-datepicker-month,
64
+ .ui-datepicker select.ui-datepicker-year {
65
+ width: 45%; }
66
+
67
+ .ui-datepicker table {
68
+ width: 100%;
69
+ font-size: .9em;
70
+ border-collapse: collapse;
71
+ margin: 0 0 .4em; }
72
+
73
+ .ui-datepicker th {
74
+ padding: .7em .3em;
75
+ text-align: center;
76
+ font-weight: bold;
77
+ border: 0; }
78
+
79
+ .ui-datepicker td {
80
+ border: 0;
81
+ padding: 1px; }
82
+
83
+ .ui-datepicker td span,
84
+ .ui-datepicker td a {
85
+ display: block;
86
+ padding: .2em;
87
+ text-align: center;
88
+ text-decoration: none; }
89
+
90
+ .ui-datepicker .ui-datepicker-buttonpane {
91
+ background-image: none;
92
+ margin: .7em 0 0 0;
93
+ padding: 0 .2em;
94
+ border-left: 0;
95
+ border-right: 0;
96
+ border-bottom: 0; }
97
+
98
+ .ui-datepicker .ui-datepicker-buttonpane button {
99
+ float: right;
100
+ margin: .5em .2em .4em;
101
+ cursor: pointer;
102
+ padding: .2em .6em .3em .6em;
103
+ width: auto;
104
+ overflow: visible; }
105
+
106
+ .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
107
+ float: left; }
108
+
109
+ /* with multiple calendars */
110
+ .ui-datepicker.ui-datepicker-multi {
111
+ width: auto; }
112
+
113
+ .ui-datepicker-multi .ui-datepicker-group {
114
+ float: left; }
115
+
116
+ .ui-datepicker-multi .ui-datepicker-group table {
117
+ width: 95%;
118
+ margin: 0 auto .4em; }
119
+
120
+ .ui-datepicker-multi-2 .ui-datepicker-group {
121
+ width: 50%; }
122
+
123
+ .ui-datepicker-multi-3 .ui-datepicker-group {
124
+ width: 33.3%; }
125
+
126
+ .ui-datepicker-multi-4 .ui-datepicker-group {
127
+ width: 25%; }
128
+
129
+ .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
130
+ .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
131
+ border-left-width: 0; }
132
+
133
+ .ui-datepicker-multi .ui-datepicker-buttonpane {
134
+ clear: left; }
135
+
136
+ .ui-datepicker-row-break {
137
+ clear: both;
138
+ width: 100%;
139
+ font-size: 0; }
140
+
141
+ /* RTL support */
142
+ .ui-datepicker-rtl {
143
+ direction: rtl; }
144
+
145
+ .ui-datepicker-rtl .ui-datepicker-prev {
146
+ right: 2px;
147
+ left: auto; }
148
+
149
+ .ui-datepicker-rtl .ui-datepicker-next {
150
+ left: 2px;
151
+ right: auto; }
152
+
153
+ .ui-datepicker-rtl .ui-datepicker-prev:hover {
154
+ right: 1px;
155
+ left: auto; }
156
+
157
+ .ui-datepicker-rtl .ui-datepicker-next:hover {
158
+ left: 1px;
159
+ right: auto; }
160
+
161
+ .ui-datepicker-rtl .ui-datepicker-buttonpane {
162
+ clear: right; }
163
+
164
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button {
165
+ float: left; }
166
+
167
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
168
+ .ui-datepicker-rtl .ui-datepicker-group {
169
+ float: right; }
170
+
171
+ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
172
+ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
173
+ border-right-width: 0;
174
+ border-left-width: 1px; }
175
+
176
+ /* Icons */
177
+ .ui-datepicker .ui-icon {
178
+ display: block;
179
+ text-indent: -99999px;
180
+ overflow: hidden;
181
+ background-repeat: no-repeat;
182
+ left: .5em;
183
+ top: .3em; }
184
+
185
+ .ui-icon {
186
+ width: 16px;
187
+ height: 16px; }
188
+
189
+ .ui-icon,
190
+ .ui-widget-content .ui-icon {
191
+ background-image: url("../img/ui-icons_444444_256x240.png"); }
192
+
193
+ .ui-widget-header .ui-icon {
194
+ background-image: url("../img/ui-icons_444444_256x240.png"); }
195
+
196
+ .ui-state-hover .ui-icon,
197
+ .ui-state-focus .ui-icon,
198
+ .ui-button:hover .ui-icon,
199
+ .ui-button:focus .ui-icon {
200
+ background-image: url("../img/ui-icons_555555_256x240.png"); }
201
+
202
+ .ui-state-active .ui-icon,
203
+ .ui-button:active .ui-icon {
204
+ background-image: url("../img/ui-icons_ffffff_256x240.png"); }
205
+
206
+ .ui-state-highlight .ui-icon,
207
+ .ui-button .ui-state-highlight.ui-icon {
208
+ background-image: url("../img/ui-icons_777620_256x240.png"); }
209
+
210
+ /* positioning */
211
+ .ui-icon-blank {
212
+ background-position: 16px 16px; }
213
+
214
+ .ui-icon-caret-1-n {
215
+ background-position: 0 0; }
216
+
217
+ .ui-icon-caret-1-ne {
218
+ background-position: -16px 0; }
219
+
220
+ .ui-icon-caret-1-e {
221
+ background-position: -32px 0; }
222
+
223
+ .ui-icon-caret-1-se {
224
+ background-position: -48px 0; }
225
+
226
+ .ui-icon-caret-1-s {
227
+ background-position: -65px 0; }
228
+
229
+ .ui-icon-caret-1-sw {
230
+ background-position: -80px 0; }
231
+
232
+ .ui-icon-caret-1-w {
233
+ background-position: -96px 0; }
234
+
235
+ .ui-icon-caret-1-nw {
236
+ background-position: -112px 0; }
237
+
238
+ .ui-icon-caret-2-n-s {
239
+ background-position: -128px 0; }
240
+
241
+ .ui-icon-caret-2-e-w {
242
+ background-position: -144px 0; }
243
+
244
+ .ui-icon-triangle-1-n {
245
+ background-position: 0 -16px; }
246
+
247
+ .ui-icon-triangle-1-ne {
248
+ background-position: -16px -16px; }
249
+
250
+ .ui-icon-triangle-1-e {
251
+ background-position: -32px -16px; }
252
+
253
+ .ui-icon-triangle-1-se {
254
+ background-position: -48px -16px; }
255
+
256
+ .ui-icon-triangle-1-s {
257
+ background-position: -65px -16px; }
258
+
259
+ .ui-icon-triangle-1-sw {
260
+ background-position: -80px -16px; }
261
+
262
+ .ui-icon-triangle-1-w {
263
+ background-position: -96px -16px; }
264
+
265
+ .ui-icon-triangle-1-nw {
266
+ background-position: -112px -16px; }
267
+
268
+ .ui-icon-triangle-2-n-s {
269
+ background-position: -128px -16px; }
270
+
271
+ .ui-icon-triangle-2-e-w {
272
+ background-position: -144px -16px; }
273
+
274
+ .ui-icon-arrow-1-n {
275
+ background-position: 0 -32px; }
276
+
277
+ .ui-icon-arrow-1-ne {
278
+ background-position: -16px -32px; }
279
+
280
+ .ui-icon-arrow-1-e {
281
+ background-position: -32px -32px; }
282
+
283
+ .ui-icon-arrow-1-se {
284
+ background-position: -48px -32px; }
285
+
286
+ .ui-icon-arrow-1-s {
287
+ background-position: -65px -32px; }
288
+
289
+ .ui-icon-arrow-1-sw {
290
+ background-position: -80px -32px; }
291
+
292
+ .ui-icon-arrow-1-w {
293
+ background-position: -96px -32px; }
294
+
295
+ .ui-icon-arrow-1-nw {
296
+ background-position: -112px -32px; }
297
+
298
+ .ui-icon-arrow-2-n-s {
299
+ background-position: -128px -32px; }
300
+
301
+ .ui-icon-arrow-2-ne-sw {
302
+ background-position: -144px -32px; }
303
+
304
+ .ui-icon-arrow-2-e-w {
305
+ background-position: -160px -32px; }
306
+
307
+ .ui-icon-arrow-2-se-nw {
308
+ background-position: -176px -32px; }
309
+
310
+ .ui-icon-arrowstop-1-n {
311
+ background-position: -192px -32px; }
312
+
313
+ .ui-icon-arrowstop-1-e {
314
+ background-position: -208px -32px; }
315
+
316
+ .ui-icon-arrowstop-1-s {
317
+ background-position: -224px -32px; }
318
+
319
+ .ui-icon-arrowstop-1-w {
320
+ background-position: -240px -32px; }
321
+
322
+ .ui-icon-arrowthick-1-n {
323
+ background-position: 1px -48px; }
324
+
325
+ .ui-icon-arrowthick-1-ne {
326
+ background-position: -16px -48px; }
327
+
328
+ .ui-icon-arrowthick-1-e {
329
+ background-position: -32px -48px; }
330
+
331
+ .ui-icon-arrowthick-1-se {
332
+ background-position: -48px -48px; }
333
+
334
+ .ui-icon-arrowthick-1-s {
335
+ background-position: -64px -48px; }
336
+
337
+ .ui-icon-arrowthick-1-sw {
338
+ background-position: -80px -48px; }
339
+
340
+ .ui-icon-arrowthick-1-w {
341
+ background-position: -96px -48px; }
342
+
343
+ .ui-icon-arrowthick-1-nw {
344
+ background-position: -112px -48px; }
345
+
346
+ .ui-icon-arrowthick-2-n-s {
347
+ background-position: -128px -48px; }
348
+
349
+ .ui-icon-arrowthick-2-ne-sw {
350
+ background-position: -144px -48px; }
351
+
352
+ .ui-icon-arrowthick-2-e-w {
353
+ background-position: -160px -48px; }
354
+
355
+ .ui-icon-arrowthick-2-se-nw {
356
+ background-position: -176px -48px; }
357
+
358
+ .ui-icon-arrowthickstop-1-n {
359
+ background-position: -192px -48px; }
360
+
361
+ .ui-icon-arrowthickstop-1-e {
362
+ background-position: -208px -48px; }
363
+
364
+ .ui-icon-arrowthickstop-1-s {
365
+ background-position: -224px -48px; }
366
+
367
+ .ui-icon-arrowthickstop-1-w {
368
+ background-position: -240px -48px; }
369
+
370
+ .ui-icon-arrowreturnthick-1-w {
371
+ background-position: 0 -64px; }
372
+
373
+ .ui-icon-arrowreturnthick-1-n {
374
+ background-position: -16px -64px; }
375
+
376
+ .ui-icon-arrowreturnthick-1-e {
377
+ background-position: -32px -64px; }
378
+
379
+ .ui-icon-arrowreturnthick-1-s {
380
+ background-position: -48px -64px; }
381
+
382
+ .ui-icon-arrowreturn-1-w {
383
+ background-position: -64px -64px; }
384
+
385
+ .ui-icon-arrowreturn-1-n {
386
+ background-position: -80px -64px; }
387
+
388
+ .ui-icon-arrowreturn-1-e {
389
+ background-position: -96px -64px; }
390
+
391
+ .ui-icon-arrowreturn-1-s {
392
+ background-position: -112px -64px; }
393
+
394
+ .ui-icon-arrowrefresh-1-w {
395
+ background-position: -128px -64px; }
396
+
397
+ .ui-icon-arrowrefresh-1-n {
398
+ background-position: -144px -64px; }
399
+
400
+ .ui-icon-arrowrefresh-1-e {
401
+ background-position: -160px -64px; }
402
+
403
+ .ui-icon-arrowrefresh-1-s {
404
+ background-position: -176px -64px; }
405
+
406
+ .ui-icon-arrow-4 {
407
+ background-position: 0 -80px; }
408
+
409
+ .ui-icon-arrow-4-diag {
410
+ background-position: -16px -80px; }
411
+
412
+ .ui-icon-extlink {
413
+ background-position: -32px -80px; }
414
+
415
+ .ui-icon-newwin {
416
+ background-position: -48px -80px; }
417
+
418
+ .ui-icon-refresh {
419
+ background-position: -64px -80px; }
420
+
421
+ .ui-icon-shuffle {
422
+ background-position: -80px -80px; }
423
+
424
+ .ui-icon-transfer-e-w {
425
+ background-position: -96px -80px; }
426
+
427
+ .ui-icon-transferthick-e-w {
428
+ background-position: -112px -80px; }
429
+
430
+ .ui-icon-folder-collapsed {
431
+ background-position: 0 -96px; }
432
+
433
+ .ui-icon-folder-open {
434
+ background-position: -16px -96px; }
435
+
436
+ .ui-icon-document {
437
+ background-position: -32px -96px; }
438
+
439
+ .ui-icon-document-b {
440
+ background-position: -48px -96px; }
441
+
442
+ .ui-icon-note {
443
+ background-position: -64px -96px; }
444
+
445
+ .ui-icon-mail-closed {
446
+ background-position: -80px -96px; }
447
+
448
+ .ui-icon-mail-open {
449
+ background-position: -96px -96px; }
450
+
451
+ .ui-icon-suitcase {
452
+ background-position: -112px -96px; }
453
+
454
+ .ui-icon-comment {
455
+ background-position: -128px -96px; }
456
+
457
+ .ui-icon-person {
458
+ background-position: -144px -96px; }
459
+
460
+ .ui-icon-print {
461
+ background-position: -160px -96px; }
462
+
463
+ .ui-icon-trash {
464
+ background-position: -176px -96px; }
465
+
466
+ .ui-icon-locked {
467
+ background-position: -192px -96px; }
468
+
469
+ .ui-icon-unlocked {
470
+ background-position: -208px -96px; }
471
+
472
+ .ui-icon-bookmark {
473
+ background-position: -224px -96px; }
474
+
475
+ .ui-icon-tag {
476
+ background-position: -240px -96px; }
477
+
478
+ .ui-icon-home {
479
+ background-position: 0 -112px; }
480
+
481
+ .ui-icon-flag {
482
+ background-position: -16px -112px; }
483
+
484
+ .ui-icon-calendar {
485
+ background-position: -32px -112px; }
486
+
487
+ .ui-icon-cart {
488
+ background-position: -48px -112px; }
489
+
490
+ .ui-icon-pencil {
491
+ background-position: -64px -112px; }
492
+
493
+ .ui-icon-clock {
494
+ background-position: -80px -112px; }
495
+
496
+ .ui-icon-disk {
497
+ background-position: -96px -112px; }
498
+
499
+ .ui-icon-calculator {
500
+ background-position: -112px -112px; }
501
+
502
+ .ui-icon-zoomin {
503
+ background-position: -128px -112px; }
504
+
505
+ .ui-icon-zoomout {
506
+ background-position: -144px -112px; }
507
+
508
+ .ui-icon-search {
509
+ background-position: -160px -112px; }
510
+
511
+ .ui-icon-wrench {
512
+ background-position: -176px -112px; }
513
+
514
+ .ui-icon-gear {
515
+ background-position: -192px -112px; }
516
+
517
+ .ui-icon-heart {
518
+ background-position: -208px -112px; }
519
+
520
+ .ui-icon-star {
521
+ background-position: -224px -112px; }
522
+
523
+ .ui-icon-link {
524
+ background-position: -240px -112px; }
525
+
526
+ .ui-icon-cancel {
527
+ background-position: 0 -128px; }
528
+
529
+ .ui-icon-plus {
530
+ background-position: -16px -128px; }
531
+
532
+ .ui-icon-plusthick {
533
+ background-position: -32px -128px; }
534
+
535
+ .ui-icon-minus {
536
+ background-position: -48px -128px; }
537
+
538
+ .ui-icon-minusthick {
539
+ background-position: -64px -128px; }
540
+
541
+ .ui-icon-close {
542
+ background-position: -80px -128px; }
543
+
544
+ .ui-icon-closethick {
545
+ background-position: -96px -128px; }
546
+
547
+ .ui-icon-key {
548
+ background-position: -112px -128px; }
549
+
550
+ .ui-icon-lightbulb {
551
+ background-position: -128px -128px; }
552
+
553
+ .ui-icon-scissors {
554
+ background-position: -144px -128px; }
555
+
556
+ .ui-icon-clipboard {
557
+ background-position: -160px -128px; }
558
+
559
+ .ui-icon-copy {
560
+ background-position: -176px -128px; }
561
+
562
+ .ui-icon-contact {
563
+ background-position: -192px -128px; }
564
+
565
+ .ui-icon-image {
566
+ background-position: -208px -128px; }
567
+
568
+ .ui-icon-video {
569
+ background-position: -224px -128px; }
570
+
571
+ .ui-icon-script {
572
+ background-position: -240px -128px; }
573
+
574
+ .ui-icon-alert {
575
+ background-position: 0 -144px; }
576
+
577
+ .ui-icon-info {
578
+ background-position: -16px -144px; }
579
+
580
+ .ui-icon-notice {
581
+ background-position: -32px -144px; }
582
+
583
+ .ui-icon-help {
584
+ background-position: -48px -144px; }
585
+
586
+ .ui-icon-check {
587
+ background-position: -64px -144px; }
588
+
589
+ .ui-icon-bullet {
590
+ background-position: -80px -144px; }
591
+
592
+ .ui-icon-radio-on {
593
+ background-position: -96px -144px; }
594
+
595
+ .ui-icon-radio-off {
596
+ background-position: -112px -144px; }
597
+
598
+ .ui-icon-pin-w {
599
+ background-position: -128px -144px; }
600
+
601
+ .ui-icon-pin-s {
602
+ background-position: -144px -144px; }
603
+
604
+ .ui-icon-play {
605
+ background-position: 0 -160px; }
606
+
607
+ .ui-icon-pause {
608
+ background-position: -16px -160px; }
609
+
610
+ .ui-icon-seek-next {
611
+ background-position: -32px -160px; }
612
+
613
+ .ui-icon-seek-prev {
614
+ background-position: -48px -160px; }
615
+
616
+ .ui-icon-seek-end {
617
+ background-position: -64px -160px; }
618
+
619
+ .ui-icon-seek-start {
620
+ background-position: -80px -160px; }
621
+
622
+ /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
623
+ .ui-icon-seek-first {
624
+ background-position: -80px -160px; }
625
+
626
+ .ui-icon-stop {
627
+ background-position: -96px -160px; }
628
+
629
+ .ui-icon-eject {
630
+ background-position: -112px -160px; }
631
+
632
+ .ui-icon-volume-off {
633
+ background-position: -128px -160px; }
634
+
635
+ .ui-icon-volume-on {
636
+ background-position: -144px -160px; }
637
+
638
+ .ui-icon-power {
639
+ background-position: 0 -176px; }
640
+
641
+ .ui-icon-signal-diag {
642
+ background-position: -16px -176px; }
643
+
644
+ .ui-icon-signal {
645
+ background-position: -32px -176px; }
646
+
647
+ .ui-icon-battery-0 {
648
+ background-position: -48px -176px; }
649
+
650
+ .ui-icon-battery-1 {
651
+ background-position: -64px -176px; }
652
+
653
+ .ui-icon-battery-2 {
654
+ background-position: -80px -176px; }
655
+
656
+ .ui-icon-battery-3 {
657
+ background-position: -96px -176px; }
658
+
659
+ .ui-icon-circle-plus {
660
+ background-position: 0 -192px; }
661
+
662
+ .ui-icon-circle-minus {
663
+ background-position: -16px -192px; }
664
+
665
+ .ui-icon-circle-close {
666
+ background-position: -32px -192px; }
667
+
668
+ .ui-icon-circle-triangle-e {
669
+ background-position: -48px -192px; }
670
+
671
+ .ui-icon-circle-triangle-s {
672
+ background-position: -64px -192px; }
673
+
674
+ .ui-icon-circle-triangle-w {
675
+ background-position: -80px -192px; }
676
+
677
+ .ui-icon-circle-triangle-n {
678
+ background-position: -96px -192px; }
679
+
680
+ .ui-icon-circle-arrow-e {
681
+ background-position: -112px -192px; }
682
+
683
+ .ui-icon-circle-arrow-s {
684
+ background-position: -128px -192px; }
685
+
686
+ .ui-icon-circle-arrow-w {
687
+ background-position: -144px -192px; }
688
+
689
+ .ui-icon-circle-arrow-n {
690
+ background-position: -160px -192px; }
691
+
692
+ .ui-icon-circle-zoomin {
693
+ background-position: -176px -192px; }
694
+
695
+ .ui-icon-circle-zoomout {
696
+ background-position: -192px -192px; }
697
+
698
+ .ui-icon-circle-check {
699
+ background-position: -208px -192px; }
700
+
701
+ .ui-icon-circlesmall-plus {
702
+ background-position: 0 -208px; }
703
+
704
+ .ui-icon-circlesmall-minus {
705
+ background-position: -16px -208px; }
706
+
707
+ .ui-icon-circlesmall-close {
708
+ background-position: -32px -208px; }
709
+
710
+ .ui-icon-squaresmall-plus {
711
+ background-position: -48px -208px; }
712
+
713
+ .ui-icon-squaresmall-minus {
714
+ background-position: -64px -208px; }
715
+
716
+ .ui-icon-squaresmall-close {
717
+ background-position: -80px -208px; }
718
+
719
+ .ui-icon-grip-dotted-vertical {
720
+ background-position: 0 -224px; }
721
+
722
+ .ui-icon-grip-dotted-horizontal {
723
+ background-position: -16px -224px; }
724
+
725
+ .ui-icon-grip-solid-vertical {
726
+ background-position: -32px -224px; }
727
+
728
+ .ui-icon-grip-solid-horizontal {
729
+ background-position: -48px -224px; }
730
+
731
+ .ui-icon-gripsmall-diagonal-se {
732
+ background-position: -64px -224px; }
733
+
734
+ .ui-icon-grip-diagonal-se {
735
+ background-position: -80px -224px; }
736
+
737
+ /* Corner radius */
738
+ .ui-corner-all,
739
+ .ui-corner-top,
740
+ .ui-corner-left,
741
+ .ui-corner-tl {
742
+ border-top-left-radius: 3px; }
743
+
744
+ .ui-corner-all,
745
+ .ui-corner-top,
746
+ .ui-corner-right,
747
+ .ui-corner-tr {
748
+ border-top-right-radius: 3px; }
749
+
750
+ .ui-corner-all,
751
+ .ui-corner-bottom,
752
+ .ui-corner-left,
753
+ .ui-corner-bl {
754
+ border-bottom-left-radius: 3px; }
755
+
756
+ .ui-corner-all,
757
+ .ui-corner-bottom,
758
+ .ui-corner-right,
759
+ .ui-corner-br {
760
+ border-bottom-right-radius: 3px; }
761
+
762
+ .emr_upload_form .wrapper {
763
+ margin: 15px 0;
764
+ padding: 18px;
765
+ border: 1px solid #ccc; }
766
+ .emr_upload_form .wrapper .section-header {
767
+ font-size: 18px;
768
+ border-bottom: 1px solid #ccc;
769
+ padding: 6px 0;
770
+ margin: 0 0 15px 0; }
771
+ .emr_upload_form .image_chooser.wrapper {
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;
786
+ padding: 15px;
787
+ margin: 15px 0 15px 35px; }
788
+ .emr_upload_form .options.wrapper .custom_date .emr_datepicker {
789
+ width: 150px; }
790
+ .emr_upload_form .options.wrapper .custom_date .emr_hour, .emr_upload_form .options.wrapper .custom_date .emr_minute {
791
+ width: 45px; }
792
+ .emr_upload_form .options.wrapper ul li input {
793
+ margin-right: 8px; }
794
+ .emr_upload_form .options.wrapper .option label {
795
+ vertical-align: top; }
796
+ .emr_upload_form .options.wrapper .small {
797
+ font-size: 10px;
798
+ vertical-align: top;
799
+ margin-left: 8px; }
800
+ .emr_upload_form .options.wrapper .custom_date {
801
+ margin: 8px 0 0 25px;
802
+ visibility: hidden;
803
+ opacity: 0; }
804
+ .emr_upload_form .options.wrapper .custom_date span.field-title {
805
+ display: inline-block;
806
+ margin-bottom: 4px;
807
+ color: #444;
808
+ font-size: 12px;
809
+ width: 100%;
810
+ text-align: left;
811
+ vertical-align: middle;
812
+ line-height: 26px; }
813
+ .emr_upload_form .options.wrapper .custom_date span.field-title::before {
814
+ font-size: 20px;
815
+ vertical-align: top;
816
+ margin-right: 4px; }
817
+ .emr_upload_form .form_controls.wrapper {
818
+ clear: both;
819
+ margin: 8px 0 15px 0;
820
+ border: 0;
821
+ padding: 0; }
822
+ .emr_upload_form .form_controls.wrapper .button {
823
+ padding-left: 20px;
824
+ padding-right: 20px; }
825
+ .emr_upload_form .shortpixel-notice {
826
+ background: #fff;
827
+ width: 250px;
828
+ min-height: 270px;
829
+ border: 1px solid #ccc;
830
+ padding: 15px;
831
+ margin: 0 0 10px;
832
+ float: right; }
833
+ .emr_upload_form .shortpixel-notice h3 {
834
+ line-height: 1.3em; }
css/admin.rtl.css ADDED
@@ -0,0 +1,834 @@
1
+ .ui-widget-content {
2
+ border: 1px solid #dddddd;
3
+ background: #ffffff;
4
+ color: #333333; }
5
+
6
+ .ui-widget-overlay {
7
+ position: fixed;
8
+ top: 0;
9
+ right: 0;
10
+ width: 100%;
11
+ height: 100%; }
12
+
13
+ .ui-datepicker {
14
+ width: 17em;
15
+ padding: .2em .2em 0;
16
+ display: none; }
17
+
18
+ .ui-datepicker .ui-datepicker-header {
19
+ position: relative;
20
+ padding: .2em 0; }
21
+
22
+ .ui-datepicker .ui-datepicker-prev,
23
+ .ui-datepicker .ui-datepicker-next {
24
+ position: absolute;
25
+ top: 2px;
26
+ width: 1.8em;
27
+ height: 1.8em; }
28
+
29
+ .ui-datepicker .ui-datepicker-prev-hover,
30
+ .ui-datepicker .ui-datepicker-next-hover {
31
+ top: 1px; }
32
+
33
+ .ui-datepicker .ui-datepicker-prev {
34
+ right: 2px; }
35
+
36
+ .ui-datepicker .ui-datepicker-next {
37
+ left: 2px; }
38
+
39
+ .ui-datepicker .ui-datepicker-prev-hover {
40
+ right: 1px; }
41
+
42
+ .ui-datepicker .ui-datepicker-next-hover {
43
+ left: 1px; }
44
+
45
+ .ui-datepicker .ui-datepicker-prev span,
46
+ .ui-datepicker .ui-datepicker-next span {
47
+ display: block;
48
+ position: absolute;
49
+ right: 50%;
50
+ margin-right: -8px;
51
+ top: 50%;
52
+ margin-top: -8px; }
53
+
54
+ .ui-datepicker .ui-datepicker-title {
55
+ margin: 0 2.3em;
56
+ line-height: 1.8em;
57
+ text-align: center; }
58
+
59
+ .ui-datepicker .ui-datepicker-title select {
60
+ font-size: 1em;
61
+ margin: 1px 0; }
62
+
63
+ .ui-datepicker select.ui-datepicker-month,
64
+ .ui-datepicker select.ui-datepicker-year {
65
+ width: 45%; }
66
+
67
+ .ui-datepicker table {
68
+ width: 100%;
69
+ font-size: .9em;
70
+ border-collapse: collapse;
71
+ margin: 0 0 .4em; }
72
+
73
+ .ui-datepicker th {
74
+ padding: .7em .3em;
75
+ text-align: center;
76
+ font-weight: bold;
77
+ border: 0; }
78
+
79
+ .ui-datepicker td {
80
+ border: 0;
81
+ padding: 1px; }
82
+
83
+ .ui-datepicker td span,
84
+ .ui-datepicker td a {
85
+ display: block;
86
+ padding: .2em;
87
+ text-align: center;
88
+ text-decoration: none; }
89
+
90
+ .ui-datepicker .ui-datepicker-buttonpane {
91
+ background-image: none;
92
+ margin: .7em 0 0 0;
93
+ padding: 0 .2em;
94
+ border-right: 0;
95
+ border-left: 0;
96
+ border-bottom: 0; }
97
+
98
+ .ui-datepicker .ui-datepicker-buttonpane button {
99
+ float: left;
100
+ margin: .5em .2em .4em;
101
+ cursor: pointer;
102
+ padding: .2em .6em .3em .6em;
103
+ width: auto;
104
+ overflow: visible; }
105
+
106
+ .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
107
+ float: right; }
108
+
109
+ /* with multiple calendars */
110
+ .ui-datepicker.ui-datepicker-multi {
111
+ width: auto; }
112
+
113
+ .ui-datepicker-multi .ui-datepicker-group {
114
+ float: right; }
115
+
116
+ .ui-datepicker-multi .ui-datepicker-group table {
117
+ width: 95%;
118
+ margin: 0 auto .4em; }
119
+
120
+ .ui-datepicker-multi-2 .ui-datepicker-group {
121
+ width: 50%; }
122
+
123
+ .ui-datepicker-multi-3 .ui-datepicker-group {
124
+ width: 33.3%; }
125
+
126
+ .ui-datepicker-multi-4 .ui-datepicker-group {
127
+ width: 25%; }
128
+
129
+ .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
130
+ .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
131
+ border-right-width: 0; }
132
+
133
+ .ui-datepicker-multi .ui-datepicker-buttonpane {
134
+ clear: right; }
135
+
136
+ .ui-datepicker-row-break {
137
+ clear: both;
138
+ width: 100%;
139
+ font-size: 0; }
140
+
141
+ /* RTL support */
142
+ .ui-datepicker-rtl {
143
+ direction: ltr; }
144
+
145
+ .ui-datepicker-rtl .ui-datepicker-prev {
146