Media Cleaner - Version 4.6.2

Version Description

  • Add: Added an option to only scan the thumbnails and ignore the base files.
  • Add: ACF Repeater support.
  • Update: Improved the code and the performance. Scan is now done differently, using the DB.
  • Fix: Debug logs weren't logging (and enhanced them a bit).
  • Notice: That's a big release :) Please help me by giving me a nice review, here: https://wordpress.org/support/plugin/meow-lightbox/reviews/?rate=5#new-post.
Download this release

Release Info

Developer TigrouMeow
Plugin Icon 128x128 Media Cleaner
Version 4.6.2
Comparing to
See all releases

Code changes from version 4.5.8 to 4.6.2

Files changed (9) hide show
  1. admin.php +395 -0
  2. checkers.php +48 -0
  3. common/admin.css +142 -142
  4. common/admin.php +21 -4
  5. core.php +369 -296
  6. custom_checkers.php +20 -0
  7. media-cleaner.php +6 -9
  8. readme.txt +13 -15
  9. scan.php +167 -0
admin.php ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ include "common/admin.php";
4
+
5
+ class Meow_WPMC_Admin extends MeowApps_Admin {
6
+
7
+ public $core;
8
+
9
+ public function __construct( $prefix, $mainfile, $domain ) {
10
+ parent::__construct( $prefix, $mainfile, $domain );
11
+ add_action( 'admin_menu', array( $this, 'app_menu' ) );
12
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
13
+ }
14
+
15
+ function admin_notices() {
16
+
17
+ $mediasBuffer = get_option( 'wpmc_medias_buffer', null );
18
+ $postsBuffer = get_option( 'wpmc_posts_buffer', null );
19
+ $analysisBuffer = get_option( 'wpmc_analysis_buffer', null );
20
+ $delay = get_option( 'wpmc_delay', null );
21
+
22
+ if ( !is_numeric( $mediasBuffer ) || $mediasBuffer < 1 )
23
+ update_option( 'wpmc_medias_buffer', 100 );
24
+ if ( !is_numeric( $postsBuffer ) || $postsBuffer < 1 )
25
+ update_option( 'wpmc_posts_buffer', 5 );
26
+ if ( !is_numeric( $analysisBuffer ) || $analysisBuffer < 1 )
27
+ update_option( 'wpmc_analysis_buffer', 100 );
28
+ if ( !is_numeric( $delay ) )
29
+ update_option( 'wpmc_delay', 100 );
30
+
31
+ if ( !$this->is_registered() && get_option( 'wpmc_method', 'media' ) == 'files' ) {
32
+ _e( "<div class='error'><p>The Pro version is required to scan files. You can <a target='_blank' href='http://meowapps.com/media-cleaner'>get a serial for the Pro version here</a>.</p></div>", 'media-cleaner' );
33
+ }
34
+ }
35
+
36
+ function common_url( $file ) {
37
+ return trailingslashit( plugin_dir_url( __FILE__ ) ) . 'common/' . $file;
38
+ }
39
+
40
+ function app_menu() {
41
+
42
+ // SUBMENU > Settings
43
+ add_submenu_page( 'meowapps-main-menu', 'Media Cleaner', 'Media Cleaner', 'manage_options',
44
+ 'wpmc_settings-menu', array( $this, 'admin_settings' ) );
45
+
46
+ // SUBMENU > Settings > Settings (Scanning)
47
+ add_settings_section( 'wpmc_settings', null, null, 'wpmc_settings-menu' );
48
+ add_settings_field( 'wpmc_method', "Method",
49
+ array( $this, 'admin_method_callback' ),
50
+ 'wpmc_settings-menu', 'wpmc_settings' );
51
+ add_settings_field( 'wpmc_media_library', "Media Library",
52
+ array( $this, 'admin_media_library_callback' ),
53
+ 'wpmc_settings-menu', 'wpmc_settings' );
54
+ add_settings_field( 'wpmc_posts', "Posts",
55
+ array( $this, 'admin_posts_callback' ),
56
+ 'wpmc_settings-menu', 'wpmc_settings' );
57
+ add_settings_field( 'wpmc_postmeta', "Post Meta",
58
+ array( $this, 'admin_postmeta_callback' ),
59
+ 'wpmc_settings-menu', 'wpmc_settings' );
60
+ add_settings_field( 'wpmc_widgets', "Widgets",
61
+ array( $this, 'admin_widgets_callback' ),
62
+ 'wpmc_settings-menu', 'wpmc_settings' );
63
+ // add_settings_field( 'wpmc_shortcode', "Shortcodes<br />(Pro)",
64
+ // array( $this, 'admin_shortcode_callback' ),
65
+ // 'wpmc_settings-menu', 'wpmc_settings' );
66
+ // add_settings_field( 'wpmc_background', "Background CSS<br />(Pro)",
67
+ // array( $this, 'admin_background_callback' ),
68
+ // 'wpmc_settings-menu', 'wpmc_settings' );
69
+ add_settings_field( 'wpmc_debuglogs', "Logs",
70
+ array( $this, 'admin_debuglogs_callback' ),
71
+ 'wpmc_settings-menu', 'wpmc_settings', array( "Enable" ) );
72
+
73
+ // SUBMENU > Settings > Filters
74
+ add_settings_section( 'wpmc_filters_settings', null, null, 'wpmc_filters_settings-menu' );
75
+ add_settings_field( 'wpmc_thumbnails_only', "Thumbnails Only",
76
+ array( $this, 'admin_thumbnails_only_callback' ),
77
+ 'wpmc_filters_settings-menu', 'wpmc_filters_settings' );
78
+
79
+ // SUBMENU > Settings > UI
80
+ add_settings_section( 'wpmc_ui_settings', null, null, 'wpmc_ui_settings-menu' );
81
+ add_settings_field( 'wpmc_hide_thumbnails', "Thumbnails",
82
+ array( $this, 'admin_hide_thumbnails_callback' ),
83
+ 'wpmc_ui_settings-menu', 'wpmc_ui_settings' );
84
+ add_settings_field( 'wpmc_hide_warning', "Warning Message",
85
+ array( $this, 'admin_hide_warning_callback' ),
86
+ 'wpmc_ui_settings-menu', 'wpmc_ui_settings' );
87
+
88
+ // SUBMENU > Settings > Advanced
89
+ add_settings_section( 'wpmc_advanced_settings', null, null, 'wpmc_advanced_settings-menu' );
90
+ add_settings_field( 'wpmc_medias_buffer', "Medias Buffer",
91
+ array( $this, 'admin_medias_buffer_callback' ),
92
+ 'wpmc_advanced_settings-menu', 'wpmc_advanced_settings' );
93
+ add_settings_field( 'wpmc_posts_buffer', "Posts Buffer",
94
+ array( $this, 'admin_posts_buffer_callback' ),
95
+ 'wpmc_advanced_settings-menu', 'wpmc_advanced_settings' );
96
+ add_settings_field( 'wpmc_analysis_buffer', "Analysis Buffer",
97
+ array( $this, 'admin_analysis_buffer_callback' ),
98
+ 'wpmc_advanced_settings-menu', 'wpmc_advanced_settings' );
99
+ add_settings_field( 'wpmc_delay', "Delay (in ms)",
100
+ array( $this, 'admin_delay_callback' ),
101
+ 'wpmc_advanced_settings-menu', 'wpmc_advanced_settings' );
102
+
103
+ // SETTINGS
104
+ register_setting( 'wpmc_settings', 'wpmc_method' );
105
+ register_setting( 'wpmc_settings', 'wpmc_posts' );
106
+ // register_setting( 'wpmc_settings', 'wpmc_shortcode' );
107
+ // register_setting( 'wpmc_settings', 'wpmc_background' );
108
+ register_setting( 'wpmc_settings', 'wpmc_widgets' );
109
+ register_setting( 'wpmc_settings', 'wpmc_media_library' );
110
+ register_setting( 'wpmc_settings', 'wpmc_postmeta' );
111
+ register_setting( 'wpmc_settings', 'wpmc_debuglogs' );
112
+
113
+
114
+ register_setting( 'wpmc_filters_settings', 'wpmc_thumbnails_only' );
115
+
116
+ register_setting( 'wpmc_ui_settings', 'wpmc_hide_thumbnails' );
117
+ register_setting( 'wpmc_ui_settings', 'wpmc_hide_warning' );
118
+
119
+ register_setting( 'wpmc_advanced_settings', 'wpmc_medias_buffer' );
120
+ register_setting( 'wpmc_advanced_settings', 'wpmc_posts_buffer' );
121
+ register_setting( 'wpmc_advanced_settings', 'wpmc_analysis_buffer' );
122
+ register_setting( 'wpmc_advanced_settings', 'wpmc_delay' );
123
+ }
124
+
125
+ function admin_medias_buffer_callback( $args ) {
126
+ $value = get_option( 'wpmc_medias_buffer', 100 );
127
+ $html = '<input type="number" style="width: 100%;" id="wpmc_medias_buffer" name="wpmc_medias_buffer" value="' . $value . '" />';
128
+ $html .= '<br /><span class="description">The number of media entries to read at a time. This is fast, so the value should be between 50 and 1000.</label>';
129
+ echo $html;
130
+ }
131
+
132
+ function admin_posts_buffer_callback( $args ) {
133
+ $value = get_option( 'wpmc_posts_buffer', 5 );
134
+ $html = '<input type="number" style="width: 100%;" id="wpmc_posts_buffer" name="wpmc_posts_buffer" value="' . $value . '" />';
135
+ $html .= '<br /><span class="description">The number of posts (and any other post types) to analyze at a time. This is the most intense part of the process. Recommended value is between 1 (slow server) and 20 (excellent server).</label>';
136
+ echo $html;
137
+ }
138
+
139
+ function admin_analysis_buffer_callback( $args ) {
140
+ $value = get_option( 'wpmc_analysis_buffer', 100 );
141
+ $html = '<input type="number" style="width: 100%;" id="wpmc_analysis_buffer" name="wpmc_analysis_buffer" value="' . $value . '" />';
142
+ $html .= '<br /><span class="description">The number of media entries or files to analyze at a time. This is the main part of the process, but is is much faster than analyzing each post. Recommended value is between 20 (slow server) and 1000 (excellent server).</label>';
143
+ echo $html;
144
+ }
145
+
146
+ function admin_delay_callback( $args ) {
147
+ $value = get_option( 'wpmc_delay', 100 );
148
+ $html = '<input type="number" style="width: 100%;" id="wpmc_delay" name="wpmc_delay" value="' . $value . '" />';
149
+ $html .= '<br /><span class="description">Time to wait between each request (in milliseconds). The overall process is intensive so this gives the chance to your server to chill out a bit. A very good server doesn\'t need it, but a slow/shared hosting might even reject requests if they are too fast and frequent. Recommended value is actually 0, 100 for safety, 2000 or 5000 if your hosting is kind of cheap.</label>';
150
+ echo $html;
151
+ }
152
+
153
+ function admin_settings() {
154
+ ?>
155
+ <div class="wrap">
156
+ <?php
157
+ echo $this->display_title( "Media Cleaner" );
158
+ ?>
159
+ <div class="meow-section meow-group">
160
+ <div class="meow-box meow-col meow-span_2_of_2">
161
+ <h3>How to use</h3>
162
+ <div class="inside">
163
+ <?php echo _e( "You can choose two kind of methods, analyzing your Media Library for images which are not in used, or in your Filesystem for images which aren't registered in the Media Library or not in used. <b>Those checks can be very expensive in term of resources and might fail so you might want to play with those options depending on your install and what you need.</b> Check the <a target=\"_blank\" href=\"//meowapps.com/media-cleaner/tutorial/\">tutorial</a> for more information.", 'media-cleaner' ); ?>
164
+ <p class="submit">
165
+ <a class="button button-primary" href="upload.php?page=media-cleaner"><?php echo _e( "Access Media Cleaner Dashboard", 'media-cleaner' ); ?></a>
166
+ </p>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <div class="meow-section meow-group">
172
+
173
+ <div class="meow-col meow-span_1_of_2">
174
+
175
+ <div class="meow-box">
176
+ <h3>Scanning</h3>
177
+ <div class="inside">
178
+ <form method="post" action="options.php">
179
+ <?php settings_fields( 'wpmc_settings' ); ?>
180
+ <?php do_settings_sections( 'wpmc_settings-menu' ); ?>
181
+ <?php submit_button(); ?>
182
+ </form>
183
+ </div>
184
+ </div>
185
+
186
+ <div class="meow-box">
187
+ <h3>Filters</h3>
188
+ <div class="inside">
189
+ <form method="post" action="options.php">
190
+ <?php settings_fields( 'wpmc_filters_settings' ); ?>
191
+ <?php do_settings_sections( 'wpmc_filters_settings-menu' ); ?>
192
+ <?php submit_button(); ?>
193
+ </form>
194
+ </div>
195
+
196
+ </div>
197
+
198
+ </div>
199
+
200
+ <div class="meow-col meow-span_1_of_2">
201
+ <?php $this->display_serialkey_box( "https://meowapps.com/media-cleaner/" ); ?>
202
+
203
+ <div class="meow-box">
204
+ <h3>UI</h3>
205
+ <div class="inside">
206
+ <form method="post" action="options.php">
207
+ <?php settings_fields( 'wpmc_ui_settings' ); ?>
208
+ <?php do_settings_sections( 'wpmc_ui_settings-menu' ); ?>
209
+ <?php submit_button(); ?>
210
+ </form>
211
+ </div>
212
+ </div>
213
+
214
+ <div class="meow-box">
215
+ <h3>Advanced</h3>
216
+ <div class="inside">
217
+ <form method="post" action="options.php">
218
+ <?php settings_fields( 'wpmc_advanced_settings' ); ?>
219
+ <?php do_settings_sections( 'wpmc_advanced_settings-menu' ); ?>
220
+ <?php submit_button(); ?>
221
+ </form>
222
+ </div>
223
+ </div>
224
+
225
+ <!--
226
+ <?php if ( get_option( 'wpmc_shortcode', false ) ): ?>
227
+ <div class="meow-box">
228
+ <h3>Shortcodes</h3>
229
+ <div class="inside"><small>
230
+ <p>Here are the shortcodes registered in your WordPress by your theme and other plugins.</p>
231
+ <?php
232
+ global $shortcode_tags;
233
+ try {
234
+ if ( is_array( $shortcode_tags ) ) {
235
+ $my_shortcodes = array();
236
+ foreach ( $shortcode_tags as $sc )
237
+ if ( $sc != '__return_false' ) {
238
+ if ( is_string( $sc ) )
239
+ array_push( $my_shortcodes, str_replace( '_shortcode', '', (string)$sc ) );
240
+ }
241
+ $my_shortcodes = implode( ', ', $my_shortcodes );
242
+ }
243
+ }
244
+ catch (Exception $e) {
245
+ $my_shortcodes = "";
246
+ }
247
+ echo $my_shortcodes;
248
+ ?>
249
+ </small></div>
250
+ </div>
251
+ <?php endif; ?>
252
+ -->
253
+
254
+ </div>
255
+
256
+ </div>
257
+ </div>
258
+ <?php
259
+ }
260
+
261
+
262
+
263
+ /*
264
+ OPTIONS CALLBACKS
265
+ */
266
+
267
+ function admin_method_callback( $args ) {
268
+ $value = get_option( 'wpmc_method', 'media' );
269
+ $html = '<select id="wpmc_method" name="wpmc_method">
270
+ <option ' . selected( 'media', $value, false ) . 'value="media">Media Library</option>
271
+ <option ' . disabled( $this->is_registered(), false, false ) . ' ' . selected( 'files', $value, false ) . 'value="files">Filesystem (Pro)</option>
272
+ </select><small><br />' . __( 'Check the <a target="_blank" href="//meowapps.com/media-cleaner/tutorial/">tutorial</a> for more information.', 'media-cleaner' ) . '</small>';
273
+ echo $html;
274
+ }
275
+
276
+
277
+ // function admin_shortcode_callback( $args ) {
278
+ // $value = get_option( 'wpmc_shortcode', null );
279
+ // $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_shortcode" name="wpmc_shortcode" value="1" ' .
280
+ // checked( 1, get_option( 'wpmc_shortcode' ), false ) . '/>';
281
+ // $html .= '<label>Resolve</label><br /><small>The shortcodes you are using in your <b>posts</b> and/or <b>widgets</b> (depending on your options) will be resolved and analyzed. You don\'t need to have this option enabled for the WP Gallery (as it is covered by the Galleries option).</small>';
282
+ // echo $html;
283
+ // }
284
+
285
+ // function admin_background_callback( $args ) {
286
+ // $value = get_option( 'wpmc_background', null );
287
+ // $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_background" name="wpmc_background" value="1" ' .
288
+ // checked( 1, get_option( 'wpmc_background' ), false ) . '/>';
289
+ // $html .= '<label>Analyze</label><br /><small>When parsing HTML, the CSS inline background will also be analyzed. A few page builders are using this.</small>';
290
+ // echo $html;
291
+ // }
292
+
293
+ function admin_debuglogs_callback( $args ) {
294
+ $debuglogs = get_option( 'wpmc_debuglogs' );
295
+ $clearlogs = isset ( $_GET[ 'clearlogs' ] ) ? $_GET[ 'clearlogs' ] : 0;
296
+ if ( $clearlogs && file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
297
+ unlink( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' );
298
+ }
299
+ $html = '<input type="checkbox" id="wpmc_debuglogs" name="wpmc_debuglogs" value="1" ' .
300
+ checked( 1, $debuglogs, false ) . '/>';
301
+ $html .= '<label for="wpmc_debuglogs"> ' . $args[0] . '</label><br>';
302
+ $html .= '<small>' . __( 'Creates an internal log file, for debugging purposes.', 'media-cleaner' );
303
+ if ( $debuglogs && !file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
304
+ if ( !$this->core->log( "Testing the logging feature. It works!" ) ) {
305
+ $html .= sprintf( __( '<br /><b>Cannot create the logging file. Logging will not work. The plugin as a whole might not be able to work neither.</b>', 'media-cleaner' ), plugin_dir_url( __FILE__ ) );
306
+ }
307
+ }
308
+ if ( file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
309
+ $html .= sprintf( __( '<br />The <a target="_blank" href="%smedia-cleaner.log">log file</a> is available. You can also <a href="?page=wpmc_settings-menu&clearlogs=true">clear</a> it.', 'media-cleaner' ), plugin_dir_url( __FILE__ ) );
310
+ }
311
+ $html .= '</small>';
312
+ echo $html;
313
+ }
314
+
315
+ function admin_media_library_callback( $args ) {
316
+ $value = get_option( 'wpmc_media_library', true );
317
+ $html = '<input type="checkbox" id="wpmc_media_library" name="wpmc_media_library" value="1" ' .
318
+ disabled( get_option( 'wpmc_method', 'media' ) == 'files', false, false ) . ' ' .
319
+ checked( 1, get_option( 'wpmc_media_library' ), false ) . '/>';
320
+ $html .= '<label>Check</label><br /><small>Checks if the file is linked to a media. Only makes sense with the Filesystem scan.</small>';
321
+ echo $html;
322
+ }
323
+
324
+ function admin_posts_callback( $args ) {
325
+ $value = get_option( 'wpmc_posts', true );
326
+ $html = '<input type="checkbox" id="wpmc_posts" name="wpmc_posts" value="1" ' .
327
+ checked( 1, get_option( 'wpmc_posts' ), false ) . '/>';
328
+ $html .= '<label>Analyze</label><br /><small>Check if the media/file is used by any post types.</small>';
329
+ echo $html;
330
+ }
331
+
332
+ function admin_postmeta_callback( $args ) {
333
+ $value = get_option( 'wpmc_postmeta', true );
334
+ $html = '<input type="checkbox" id="wpmc_postmeta" name="wpmc_postmeta" value="1" ' .
335
+ checked( 1, get_option( 'wpmc_postmeta' ), false ) . '/>';
336
+ $html .= '<label>Analyze</label><br /><small>Checks if the media/file is used in the meta.</small>';
337
+ echo $html;
338
+ }
339
+
340
+ function admin_widgets_callback( $args ) {
341
+ $value = get_option( 'wpmc_widgets', false );
342
+ $html = '<input type="checkbox" id="wpmc_widgets" name="wpmc_widgets" value="1" ' .
343
+ checked( 1, get_option( 'wpmc_widgets' ), false ) . '/>';
344
+ $html .= '<label>Analyze</label><br /><small>Checks if the media/file is used by any widget.</small>';
345
+ echo $html;
346
+ }
347
+
348
+ function admin_hide_thumbnails_callback( $args ) {
349
+ $value = get_option( 'wpmc_hide_thumbnails', null );
350
+ $html = '<input type="checkbox" id="wpmc_hide_thumbnails" name="wpmc_hide_thumbnails" value="1" ' .
351
+ checked( 1, get_option( 'wpmc_hide_thumbnails' ), false ) . '/>';
352
+ $html .= '<label>Hide</label><br /><small>If you prefer not to see the thumbnails.</small>';
353
+ echo $html;
354
+ }
355
+
356
+ function admin_hide_warning_callback( $args ) {
357
+ $value = get_option( 'wpmc_hide_warning', null );
358
+ $html = '<input type="checkbox" id="wpmc_hide_warning" name="wpmc_hide_warning" value="1" ' .
359
+ checked( 1, get_option( 'wpmc_hide_warning' ), false ) . '/>';
360
+ $html .= '<label>Hide</label><br /><small>Have you read it twice? If yes, hide it :)</small>';
361
+ echo $html;
362
+ }
363
+
364
+ function admin_thumbnails_only_callback( $args ) {
365
+ $value = get_option( 'wpmc_thumbnails_only', false );
366
+ $html = '<input type="checkbox" id="wpmc_thumbnails_only" name="wpmc_thumbnails_only" value="1" ' .
367
+ disabled( get_option( 'wpmc_method', 'media' ) == 'files', false, false ) . ' ' .
368
+ checked( 1, get_option( 'wpmc_thumbnails_only' ), false ) . '/>';
369
+ $html .= '<label>Enable</label><br /><small>Restrict the filesystem scan to thumbnails (files containing the resolution). If none of the checks above are selected, you will get the list of all the thumbnails and be able to remove them.</small>';
370
+ echo $html;
371
+ }
372
+
373
+ /**
374
+ *
375
+ * GET / SET OPTIONS (TO REMOVE)
376
+ *
377
+ */
378
+
379
+ function old_getoption( $option, $section, $default = '' ) {
380
+ $options = get_option( $section );
381
+ if ( isset( $options[$option] ) ) {
382
+ if ( $options[$option] == "off" ) {
383
+ return false;
384
+ }
385
+ if ( $options[$option] == "on" ) {
386
+ return true;
387
+ }
388
+ return $options[$option];
389
+ }
390
+ return $default;
391
+ }
392
+
393
+ }
394
+
395
+ ?>
checkers.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Meow_WPMC_Checkers {
4
+
5
+ private $core;
6
+
7
+ public function __construct( $core ) {
8
+ $this->core = $core;
9
+ }
10
+
11
+ function check( $file, $mediaId ) {
12
+ global $wpdb;
13
+ if ( !empty( $mediaId ) ) {
14
+ $res = $this->check_media( $mediaId );
15
+ if ($res)
16
+ return $res;
17
+ }
18
+ if ( !empty( $file ) )
19
+ return $this->check_file( $file );
20
+ }
21
+
22
+ function check_file( $file ) {
23
+ global $wpdb;
24
+ $table = $wpdb->prefix . "mclean_refs";
25
+ // Is this make the results better?
26
+ //$file = $this->core->wpmc_clean_uploaded_filename( $file );
27
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT originType FROM $table WHERE mediaUrl = %s", $file ) );
28
+ if ( empty( $row ) )
29
+ return false;
30
+ $this->core->log( "File {$file} found as {$row->originType}" );
31
+ $this->core->last_analysis = $row->originType;
32
+ return true;
33
+ }
34
+
35
+ function check_media( $mediaId ) {
36
+ global $wpdb;
37
+ $table = $wpdb->prefix . "mclean_refs";
38
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT originType FROM $table WHERE mediaId = %d", $mediaId ) );
39
+ if ( empty( $row ) )
40
+ return false;
41
+ $this->core->log( "Media {$mediaId} found as {$row->originType}" );
42
+ $this->core->last_analysis = $row->originType;
43
+ return true;
44
+ }
45
+
46
+ }
47
+
48
+ ?>
common/admin.css CHANGED
@@ -1,164 +1,164 @@
1
  /* MEOW BOX (SETTINGS BOX) */
2
 
3
  .meow-box {
4
- box-sizing: border-box;
5
- border: 1px solid #e5e5e5;
6
- box-shadow: 2px 2px 1px rgba(0,0,0,.02);
7
- background: #fff;
8
- color: #444;
9
- margin-bottom: 15px;
10
- font-size: 13px !important;
11
- border-top-right-radius: 8px;
12
  }
13
 
14
  .meow-box input, .meow-box th, .meow-box label, .meow-box select {
15
- font-size: 13px !important;
16
  }
17
 
18
  .meow-box small {
19
- font-size: 12px !important;
20
  }
21
 
22
  .meow-box h3 {
23
- font-size: 13px;
24
- padding: 4px 12px;
25
- margin: 0;
26
- background: #3c3c3c;
27
- color: #ffffff;
28
- text-transform: uppercase;
29
- border-top-right-radius: 8px;
30
- /*border-bottom: 1px solid #eee;*/
31
  }
32
 
33
  .meow-box h3 .dashicons {
34
- position: relative;
35
- top: 0px;
36
- margin-right: 5px;
37
  }
38
 
39
  .meow-box .pro_info {
40
- padding: 5px;
41
- margin: 10px -10px 5px -10px;
42
- font-size: 11px;
43
- line-height: 13px;
44
  }
45
 
46
  .meow-box .pro_info.enabled {
47
- background: #4482d2;
48
- border-left: 5px solid #4482d2;
49
- color: white;
50
  }
51
 
52
  .meow-box .pro_info.disabled {
53
- background: #96555b;
54
- border-left: 5px solid #632329;
55
- color: white;
56
  }
57
 
58
  .meow-box .pro_info.disabled a {
59
- background: #96555b;
60
- color: red;
61
- text-decoration: none;
62
  }
63
 
64
  .meow-box .inside {
65
- margin: 10px;
66
  }
67
 
68
  .meow-box th {
69
- padding: 10px 10px 10px 0px;
70
- width: 22%;
71
  }
72
 
73
  .meow-box td {
74
- padding: 10px 10px;
75
  }
76
 
77
  .meow-box p.submit {
78
- text-align: right;
79
- margin: 10px -10px -10px -10px;
80
- padding: 7px 10px 10px 0px !important;
81
- border-top: 1px solid #eee !important;
82
- max-width: inherit;
83
- background: rgba(125, 125, 125, 0.04);
84
- border-radius: 0px;
85
  }
86
 
87
  .meow-box [type="text"], .meow-box select {
88
- width: 100%;
89
  }
90
 
91
  /* CONTROLS INSIDE A COLUMN (LABEL ON THE LEFT, VALUE ON THE RIGHT) */
92
  .meow-box td [type="text"], .meow-box td [type="checkbox"], .meow-box td select {
93
- margin-top: -3px;
94
  }
95
 
96
  .meow-header-ad {
97
- float: right;
98
  }
99
 
100
  /* BUTTONS */
101
 
102
  .meow-button-xs {
103
- font-size: 10px !important;
104
- height: 20px !important;
105
- line-height: 18px !important;
106
- position: relative !important;
107
- top: 1px !important;
108
- text-align: center !important
109
  }
110
 
111
  /* MODAL */
112
 
113
- #meow-modal-info-backdrop {
114
- background: rgba(0, 0, 0, 0.75);
115
- position: fixed;
116
- top: 0px;
117
- bottom: 0px;
118
- right: 0px;
119
- left: 0px;
120
- z-index: 10000;
121
- }
122
-
123
- #meow-modal-info {
124
- background: white;
125
- box-shadow: 0px 0px 5px black;
126
- padding: 15px;
127
- overflow-y: scroll;
128
- position: fixed;
129
- z-index: 10000;
130
- left: 100px;
131
- right: 100px;
132
- top: 50px;
133
- bottom: 50px;
134
- }
135
-
136
- #meow-modal-info h3 {
137
- height: 25px;
138
- border-bottom: 2px solid #808080;
139
- }
140
-
141
- #meow-modal-info td {
142
- text-align: center;
143
- font-size: 11px;
144
- border: 1px solid #D3DCFF;
145
- padding: 10px 15px;
146
- background: #EFF8FF;
147
- }
148
-
149
- #meow-modal-info .close {
150
- float: right;
151
- font-size: 18px;
152
- font-weight: bold;
153
- font-family: Verdana;
154
- cursor: pointer;
155
- }
156
-
157
- #meow-modal-info .loading {
158
- background-color: #F2F2F2;
159
- text-align: center;
160
- padding-top: 10px;
161
- background-size: 32px 32px;
162
  }
163
 
164
  #meow-modal-info .meow-sized-image {
@@ -191,106 +191,106 @@
191
  }
192
 
193
  .meow-sized-images:after {
194
- clear: both;
195
- content:""; display:table;
196
  }
197
 
198
  .meow-sized-images + span {
199
- position: relative;
200
- top: -12px;
201
  }
202
 
203
  /* MEOW COLORS */
204
 
205
  .meow-bk-blue {
206
  background: #3C82C7 !important;
207
- color: white;
208
  }
209
 
210
  .meow-bk-orange {
211
  background: #f1900e !important;
212
- color: white;
213
  }
214
 
215
  .meow-bk-red {
216
  background: #c53a47 !important;
217
- color: white;
218
  }
219
 
220
  .meow-bk-gray {
221
  background: gray !important;
222
- color: white;
223
  }
224
 
225
  .meow-bk-green {
226
  background: #2b9463 !important;
227
- color: white;
228
  }
229
 
230
  .meow-bk-black {
231
- background: #3c3c3c !important;
232
- color: white;
233
  }
234
 
235
  .meow-bk-purple {
236
- background: #984c96 !important;
237
- color: white;
238
  }
239
 
240
  /* DASHBOARD */
241
 
242
  .meow-dashboard .meow-box li {
243
- border-bottom: 1px solid #eee;
244
- padding: 0px 10px 10px 10px;
245
  }
246
 
247
  .meow-dashboard .meow-box li:last-child {
248
- border: none;
249
- padding-bottom: 0px;
250
  }
251
 
252
  .meow-button-xs .dashicons {
253
- font-size: 18px !important;
254
  }
255
 
256
  .meow-button-xs.updating-message:before {
257
- margin-top: 0px !important;
258
  }
259
 
260
  .meow-button-xs.updating-message * {
261
- display: none;
262
  }
263
 
264
  #phpinfo {
265
- font-size: 11px;
266
  }
267
 
268
  #phpinfo .e {
269
- padding: 5px;
270
- background: lightgray;
271
  }
272
 
273
  #phpinfo .h th {
274
- padding: 5px;
275
- color: white;
276
- background: gray;
277
- text-align: left;
278
- font-size: 14px !important;
279
  }
280
 
281
  #phpinfo h1 {
282
- padding: 10px 0px;
283
- font-weight: bold;
284
  }
285
 
286
  #phpinfo h2 {
287
- padding: 10px 0px;
288
- font-weight: bold;
289
- font-size: 20px;
290
  }
291
 
292
  #error_log {
293
- font-size: 12px;
294
  }
295
 
296
  /* ROWS AND COLUMNS */
@@ -314,9 +314,9 @@
314
  .meow-span_1_of_2 { width: 49.2%; }
315
 
316
  @media only screen and (max-width: 480px) {
317
- .meow-col { margin: 0 0 0px 0;}
318
- .meow-span_3_of_3, .meow-span_2_of_3, .meow-span_1_of_3 { width: 100%; }
319
- .meow-span_2_of_2, .meow-span_1_of_2 { width: 100%; }
320
- .meow-header-ad { display: none !important; }
321
- .meow-box [type="text"] { width: 100% !important; }
322
  }
1
  /* MEOW BOX (SETTINGS BOX) */
2
 
3
  .meow-box {
4
+ box-sizing: border-box;
5
+ border: 1px solid #e5e5e5;
6
+ box-shadow: 2px 2px 1px rgba(0,0,0,.02);
7
+ background: #fff;
8
+ color: #444;
9
+ margin-bottom: 15px;
10
+ font-size: 13px !important;
11
+ border-top-right-radius: 8px;
12
  }
13
 
14
  .meow-box input, .meow-box th, .meow-box label, .meow-box select {
15
+ font-size: 13px !important;
16
  }
17
 
18
  .meow-box small {
19
+ font-size: 12px !important;
20
  }
21
 
22
  .meow-box h3 {
23
+ font-size: 13px;
24
+ padding: 4px 12px;
25
+ margin: 0;
26
+ background: #3c3c3c;
27
+ color: #ffffff;
28
+ text-transform: uppercase;
29
+ border-top-right-radius: 8px;
30
+ /*border-bottom: 1px solid #eee;*/
31
  }
32
 
33
  .meow-box h3 .dashicons {
34
+ position: relative;
35
+ top: 0px;
36
+ margin-right: 5px;
37
  }
38
 
39
  .meow-box .pro_info {
40
+ padding: 5px;
41
+ margin: 10px -10px 5px -10px;
42
+ font-size: 11px;
43
+ line-height: 13px;
44
  }
45
 
46
  .meow-box .pro_info.enabled {
47
+ background: #4482d2;
48
+ border-left: 5px solid #4482d2;
49
+ color: white;
50
  }
51
 
52
  .meow-box .pro_info.disabled {
53
+ background: #96555b;
54
+ border-left: 5px solid #632329;
55
+ color: white;
56
  }
57
 
58
  .meow-box .pro_info.disabled a {
59
+ background: #96555b;
60
+ color: red;
61
+ text-decoration: none;
62
  }
63
 
64
  .meow-box .inside {
65
+ margin: 10px;
66
  }
67
 
68
  .meow-box th {
69
+ padding: 10px 10px 10px 0px;
70
+ width: 22%;
71
  }
72
 
73
  .meow-box td {
74
+ padding: 10px 10px;
75
  }
76
 
77
  .meow-box p.submit {
78
+ text-align: right;
79
+ margin: 10px -10px -10px -10px;
80
+ padding: 7px 10px 10px 0px !important;
81
+ border-top: 1px solid #eee !important;
82
+ max-width: inherit;
83
+ background: rgba(125, 125, 125, 0.04);
84
+ border-radius: 0px;
85
  }
86
 
87
  .meow-box [type="text"], .meow-box select {
88
+ width: 100%;
89
  }
90
 
91
  /* CONTROLS INSIDE A COLUMN (LABEL ON THE LEFT, VALUE ON THE RIGHT) */
92
  .meow-box td [type="text"], .meow-box td [type="checkbox"], .meow-box td select {
93
+ margin-top: -3px;
94
  }
95
 
96
  .meow-header-ad {
97
+ float: right;
98
  }
99
 
100
  /* BUTTONS */
101
 
102
  .meow-button-xs {
103
+ font-size: 10px !important;
104
+ height: 20px !important;
105
+ line-height: 18px !important;
106
+ position: relative !important;
107
+ top: 1px !important;
108
+ text-align: center !important
109
  }
110
 
111
  /* MODAL */
112
 
113
+ #meow-modal-info-backdrop {
114
+ background: rgba(0, 0, 0, 0.75);
115
+ position: fixed;
116
+ top: 0px;
117
+ bottom: 0px;
118
+ right: 0px;
119
+ left: 0px;
120
+ z-index: 10000;
121
+ }
122
+
123
+ #meow-modal-info {
124
+ background: white;
125
+ box-shadow: 0px 0px 5px black;
126
+ padding: 15px;
127
+ overflow-y: scroll;
128
+ position: fixed;
129
+ z-index: 10000;
130
+ left: 100px;
131
+ right: 100px;
132
+ top: 50px;
133
+ bottom: 50px;
134
+ }
135
+
136
+ #meow-modal-info h3 {
137
+ height: 25px;
138
+ border-bottom: 2px solid #808080;
139
+ }
140
+
141
+ #meow-modal-info td {
142
+ text-align: center;
143
+ font-size: 11px;
144
+ border: 1px solid #D3DCFF;
145
+ padding: 10px 15px;
146
+ background: #EFF8FF;
147
+ }
148
+
149
+ #meow-modal-info .close {
150
+ float: right;
151
+ font-size: 18px;
152
+ font-weight: bold;
153
+ font-family: Verdana;
154
+ cursor: pointer;
155
+ }
156
+
157
+ #meow-modal-info .loading {
158
+ background-color: #F2F2F2;
159
+ text-align: center;
160
+ padding-top: 10px;
161
+ background-size: 32px 32px;
162
  }
163
 
164
  #meow-modal-info .meow-sized-image {
191
  }
192
 
193
  .meow-sized-images:after {
194
+ clear: both;
195
+ content:""; display:table;
196
  }
197
 
198
  .meow-sized-images + span {
199
+ position: relative;
200
+ top: -12px;
201
  }
202
 
203
  /* MEOW COLORS */
204
 
205
  .meow-bk-blue {
206
  background: #3C82C7 !important;
207
+ color: white;
208
  }
209
 
210
  .meow-bk-orange {
211
  background: #f1900e !important;
212
+ color: white;
213
  }
214
 
215
  .meow-bk-red {
216
  background: #c53a47 !important;
217
+ color: white;
218
  }
219
 
220
  .meow-bk-gray {
221
  background: gray !important;
222
+ color: white;
223
  }
224
 
225
  .meow-bk-green {
226
  background: #2b9463 !important;
227
+ color: white;
228
  }
229
 
230
  .meow-bk-black {
231
+ background: #3c3c3c !important;
232
+ color: white;
233
  }
234
 
235
  .meow-bk-purple {
236
+ background: #984c96 !important;
237
+ color: white;
238
  }
239
 
240
  /* DASHBOARD */
241
 
242
  .meow-dashboard .meow-box li {
243
+ border-bottom: 1px solid #eee;
244
+ padding: 0px 10px 10px 10px;
245
  }
246
 
247
  .meow-dashboard .meow-box li:last-child {
248
+ border: none;
249
+ padding-bottom: 0px;
250
  }
251
 
252
  .meow-button-xs .dashicons {
253
+ font-size: 18px !important;
254
  }
255
 
256
  .meow-button-xs.updating-message:before {
257
+ margin-top: 0px !important;
258
  }
259
 
260
  .meow-button-xs.updating-message * {
261
+ display: none;
262
  }
263
 
264
  #phpinfo {
265
+ font-size: 11px;
266
  }
267
 
268
  #phpinfo .e {
269
+ padding: 5px;
270
+ background: lightgray;
271
  }
272
 
273
  #phpinfo .h th {
274
+ padding: 5px;
275
+ color: white;
276
+ background: gray;
277
+ text-align: left;
278
+ font-size: 14px !important;
279
  }
280
 
281
  #phpinfo h1 {
282
+ padding: 10px 0px;
283
+ font-weight: bold;
284
  }
285
 
286
  #phpinfo h2 {
287
+ padding: 10px 0px;
288
+ font-weight: bold;
289
+ font-size: 20px;
290
  }
291
 
292
  #error_log {
293
+ font-size: 12px;
294
  }
295
 
296
  /* ROWS AND COLUMNS */
314
  .meow-span_1_of_2 { width: 49.2%; }
315
 
316
  @media only screen and (max-width: 480px) {
317
+ .meow-col { margin: 0 0 0px 0;}
318
+ .meow-span_3_of_3, .meow-span_2_of_3, .meow-span_1_of_3 { width: 100%; }
319
+ .meow-span_2_of_2, .meow-span_1_of_2 { width: 100%; }
320
+ .meow-header-ad { display: none !important; }
321
+ .meow-box [type="text"] { width: 100% !important; }
322
  }
common/admin.php CHANGED
@@ -57,7 +57,7 @@ if ( !class_exists( 'MeowApps_Admin' ) ) {
57
  $rating_date = get_option( $this->prefix . '_rating_date' );
58
  if ( empty( $rating_date ) ) {
59
  $two_months = strtotime( '+2 months' );
60
- $six_months = strtotime( '+6 months' );
61
  $rating_date = mt_rand( $two_months, $six_months );
62
  update_option( $this->prefix . '_rating_date', $rating_date, false );
63
  }
@@ -73,18 +73,18 @@ if ( !class_exists( 'MeowApps_Admin' ) ) {
73
  return;
74
  }
75
  else if ( isset( $_POST[$this->prefix . '_never_remind_me'] ) ) {
76
- $twenty_years = strtotime( '+20 years' );
77
  update_option( $this->prefix . '_rating_date', $twenty_years, false );
78
  return;
79
  }
80
  else if ( isset( $_POST[$this->prefix . '_did_it'] ) ) {
81
- $twenty_years = strtotime( '+100 years' );
82
  update_option( $this->prefix . '_rating_date', $twenty_years, false );
83
  return;
84
  }
85
  $rating_date = get_option( $this->prefix . '_rating_date' );
86
  echo '<div class="notice notice-success" data-rating-date="' . date( 'Y-m-d', $rating_date ) . '">';
87
- echo '<p style="font-size: 100%;">You have been using <b>' . $this->nice_name_from_file( $this->mainfile ) . '</b> for some time now. If you enjoy it, could you share your thoughts and give the developers a sweet spike of motivation? In that case, please: <a target="_blank" href="https://wordpress.org/support/plugin/' . $this->nice_short_url_from_file( $this->mainfile ) . '/reviews/?rate=5#new-post">review it</a>. Thank you :)';
88
  echo '<p>
89
  <form method="post" action="" style="float: right;">
90
  <input type="hidden" name="' . $this->prefix . '_never_remind_me" value="true">
@@ -382,8 +382,25 @@ if ( !class_exists( 'MeowApps_Admin' ) ) {
382
  </ul>
383
  </div>
384
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  </div>
386
 
 
387
  <?php
388
 
389
  }
57
  $rating_date = get_option( $this->prefix . '_rating_date' );
58
  if ( empty( $rating_date ) ) {
59
  $two_months = strtotime( '+2 months' );
60
+ $six_months = strtotime( '+4 months' );
61
  $rating_date = mt_rand( $two_months, $six_months );
62
  update_option( $this->prefix . '_rating_date', $rating_date, false );
63
  }
73
  return;
74
  }
75
  else if ( isset( $_POST[$this->prefix . '_never_remind_me'] ) ) {
76
+ $twenty_years = strtotime( '+5 years' );
77
  update_option( $this->prefix . '_rating_date', $twenty_years, false );
78
  return;
79
  }
80
  else if ( isset( $_POST[$this->prefix . '_did_it'] ) ) {
81
+ $twenty_years = strtotime( '+10 years' );
82
  update_option( $this->prefix . '_rating_date', $twenty_years, false );
83
  return;
84
  }
85
  $rating_date = get_option( $this->prefix . '_rating_date' );
86
  echo '<div class="notice notice-success" data-rating-date="' . date( 'Y-m-d', $rating_date ) . '">';
87
+ echo '<p style="font-size: 100%;">You have been using <b>' . $this->nice_name_from_file( $this->mainfile ) . '</b> for some time now. Thank you! Could you kindly share your opinion with me, along with, maybe, features you would like to see implemented? Then, please <a style="font-weight: bold; color: #b926ff;" target="_blank" href="https://wordpress.org/support/plugin/' . $this->nice_short_url_from_file( $this->mainfile ) . '/reviews/?rate=5#new-post">write a little review</a>. That will also bring me joy and motivation, and I will get back to you :) <u>In the case you already have written a review</u>, please check again. Many reviews got removed from WordPress recently.';
88
  echo '<p>
89
  <form method="post" action="" style="float: right;">
90
  <input type="hidden" name="' . $this->prefix . '_never_remind_me" value="true">
382
  </ul>
383
  </div>
384
  </div>
385
+
386
+ <div class="meow-box meow-col meow-span_1_of_3">
387
+ <h3><span class="dashicons dashicons-admin-tools"></span> Post Types (used by this install)</h3>
388
+ <div class="inside">
389
+ <?php
390
+ global $wpdb;
391
+ // Maybe we could avoid to check more post_types.
392
+ // SELECT post_type, COUNT(*) FROM `wp_posts` GROUP BY post_type
393
+ $types = $wpdb->get_results( "SELECT post_type as 'type', COUNT(*) as 'count' FROM $wpdb->posts GROUP BY post_type" );
394
+ $result = array();
395
+ foreach( $types as $type )
396
+ array_push( $result, "{$type->type} ({$type->count})" );
397
+ echo implode( $result, ', ' );
398
+ ?>
399
+ </div>
400
+ </div>
401
  </div>
402
 
403
+
404
  <?php
405
 
406
  }
core.php CHANGED
@@ -6,8 +6,9 @@ class Meow_WPMC_Core {
6
  public $admin = null;
7
  public $last_analysis = null;
8
  public $last_analysis_ids = null;
9
- public static $transient_life = 604800; // 7 days
10
  private $regex_file = '/[A-Za-z0-9-_,\s]+[.]{1}(MIMETYPES)/';
 
 
11
 
12
  public function __construct( $admin ) {
13
  $this->admin = $admin;
@@ -28,10 +29,11 @@ class Meow_WPMC_Core {
28
  }
29
 
30
  function admin_init() {
 
31
  $types = "jpg|jpeg|jpe|gif|png|tiff|bmp|csv|pdf|xls|xlsx|doc|docx|tiff|mp3|mp4|wav|lua";
32
  $this->regex_file = str_replace( "MIMETYPES", $types, $this->regex_file );
33
- require( 'wpmc_scan.php' );
34
- require( 'wpmc_checkers.php' );
35
  new MeowApps_WPMC_Scan( $this );
36
  $this->checkers = new Meow_WPMC_Checkers( $this );
37
  }
@@ -45,11 +47,6 @@ class Meow_WPMC_Core {
45
  }
46
 
47
  function display_metabox( $post ) {
48
- $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
49
- if ( !is_array( $posts_images_urls ) ) {
50
- echo "You need to run a Media Library scan first.";
51
- return;
52
- }
53
  $this->log( "Media Edit > Checking Media #{$post->ID}" );
54
  $success = $this->wpmc_check_media( $post->ID, true );
55
  $this->log( "Success $success\n" );
@@ -91,7 +88,7 @@ class Meow_WPMC_Core {
91
  echo "Found in widget.";
92
  }
93
  else {
94
- echo $this->last_analysis;
95
  }
96
  }
97
  else {
@@ -157,26 +154,218 @@ class Meow_WPMC_Core {
157
  die();
158
  }
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  function wp_ajax_wpmc_scan_do () {
161
  // For debug, to pretend there is a timeout
162
- // header("HTTP/1.0 408 Request Timeout");
163
- // exit;
 
 
164
  ob_start();
165
  $type = $_POST['type'];
166
  $data = $_POST['data'];
 
167
  $success = 0;
168
  foreach ( $data as $piece ) {
 
169
  if ( $type == 'file' ) {
170
  $this->log( "Check File: {$piece}" );
171
  $result = ( apply_filters( 'wpmc_check_file', true, $piece ) ? 1 : 0 );
172
  $this->log( "Success " . $result . "\n" );
173
  $success += $result;
174
- } elseif ( $type == 'media' ) {
 
175
  $this->log( "Checking Media #{$piece}" );
176
  $result = ( $this->wpmc_check_media( $piece ) ? 1 : 0 );
177
  $this->log( "Success " . $result . "\n" );
178
  $success += $result;
179
  }
 
180
  }
181
  ob_end_clean();
182
  echo json_encode(
@@ -191,7 +380,7 @@ class Meow_WPMC_Core {
191
 
192
  function wp_ajax_wpmc_get_all_deleted () {
193
  global $wpdb;
194
- $table_name = $wpdb->prefix . "wpmcleaner";
195
  $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
196
  echo json_encode(
197
  array(
@@ -206,7 +395,7 @@ class Meow_WPMC_Core {
206
  function wp_ajax_wpmc_get_all_issues () {
207
  global $wpdb;
208
  $isTrash = ( isset( $_POST['isTrash'] ) && $_POST['isTrash'] == 1 ) ? true : false;
209
- $table_name = $wpdb->prefix . "wpmcleaner";
210
  if ( $isTrash )
211
  $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
212
  else
@@ -237,7 +426,7 @@ class Meow_WPMC_Core {
237
  }
238
  else if ( !empty( $m ) ) {
239
  // If it's a string, maybe it's a file (with an extension)
240
- if ( preg_match($this->regex_file, $m ) )
241
  array_push( $urls, $m );
242
  }
243
  }
@@ -311,15 +500,23 @@ class Meow_WPMC_Core {
311
  array_push( $results, $src );
312
  }
313
 
314
- // if ( get_option( 'wpmc_background', false ) ) {
315
- preg_match_all( "/url\(\'?\"?((https?:\/\/)?[^\\&\#\[\] \"\?]+\.(jpe?g|gif|png))\'?\"?/", $html, $res );
316
- //error_log( print_r( $res, 1 ) );
317
- if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
318
- foreach ( $res[1] as $url ) {
319
- array_push( $results, $this->wpmc_clean_url( $url ) );
320
- }
321
  }
322
- // }
 
 
 
 
 
 
 
 
 
323
 
324
  return $results;
325
  }
@@ -369,217 +566,6 @@ class Meow_WPMC_Core {
369
  }
370
  }
371
 
372
- function wp_ajax_wpmc_prepare_do() {
373
- $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
374
- $limitsize = get_option( 'wpmc_posts_buffer', 5 );
375
- if ( empty( $limit ) )
376
- $this->wpmc_reset_issues();
377
-
378
- $method = get_option( 'wpmc_method', 'media' );
379
- $check_library = get_option(' wpmc_media_library', true );
380
- $check_postmeta = get_option( 'wpmc_postmeta', false );
381
- $check_posts = get_option( 'wpmc_posts', false );
382
- $check_widgets = get_option( 'wpmc_widgets', false );
383
- if ( $method == 'media' && !$check_posts && !$check_postmeta && !$check_widgets ) {
384
- echo json_encode( array(
385
- 'results' => array(),
386
- 'success' => true,
387
- 'finished' => true,
388
- 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
389
- ) );
390
- die();
391
- }
392
- if ( $method == 'files' && $check_library && !$check_posts && !$check_postmeta && !$check_widgets ) {
393
- echo json_encode( array(
394
- 'results' => array(),
395
- 'success' => true,
396
- 'finished' => true,
397
- 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
398
- ) );
399
- die();
400
- }
401
-
402
- global $wpdb;
403
- // Maybe we could avoid to check more post_types.
404
- // SELECT post_type, COUNT(*) FROM `wp_posts` GROUP BY post_type
405
- $posts = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
406
- WHERE p.post_status != 'inherit'
407
- AND p.post_status != 'trash'
408
- AND p.post_type != 'attachment'
409
- AND p.post_type NOT LIKE '%acf-%'
410
- AND p.post_type NOT LIKE '%edd_%'
411
- AND p.post_type != 'shop_order'
412
- AND p.post_type != 'shop_order_refund'
413
- AND p.post_type != 'nav_menu_item'
414
- AND p.post_type != 'revision'
415
- AND p.post_type != 'auto-draft'
416
- LIMIT %d, %d", $limit, $limitsize
417
- )
418
- );
419
-
420
- $found = array();
421
-
422
- if ( empty( $limit ) ) {
423
- $theme_ids = array();
424
- $theme_urls = array();
425
- $this->get_images_from_themes( $theme_ids, $theme_urls );
426
- set_transient( "wpmc_theme_ids", $theme_ids, Meow_WPMC_Core::$transient_life );
427
- set_transient( "wpmc_theme_urls", $theme_urls, Meow_WPMC_Core::$transient_life );
428
- $found['wpmc_theme_ids'] = $theme_ids;
429
- $found['wpmc_theme_urls'] = $theme_urls;
430
- }
431
-
432
- // Only on Start: Analyze Widgets
433
- if ( get_option( 'wpmc_widgets', false ) && empty( $limit ) ) {
434
- $widgets_ids = array();
435
- $widgets_urls = array();
436
- $this->get_images_from_widgets( $widgets_ids, $widgets_urls );
437
- set_transient( "wpmc_widgets_ids", $widgets_ids, Meow_WPMC_Core::$transient_life );
438
- set_transient( "wpmc_widgets_urls", $widgets_urls, Meow_WPMC_Core::$transient_life );
439
- $found['wpmc_widgets_ids'] = $widgets_ids;
440
- $found['wpmc_widgets_urls'] = $widgets_urls;
441
- }
442
-
443
- // Only on Start: Analyze WooCommerce Categories Images
444
- if ( class_exists( 'WooCommerce' ) && empty( $limit ) ) {
445
- $metas = $wpdb->get_col( "SELECT meta_value
446
- FROM $wpdb->termmeta
447
- WHERE meta_key LIKE '%thumbnail_id%'"
448
- );
449
- if ( count( $metas ) > 0 ) {
450
- $postmeta_images_ids = get_transient( "wpmc_postmeta_images_ids" );
451
- if ( empty( $postmeta_images_ids ) )
452
- $postmeta_images_ids = array();
453
- foreach ( $metas as $meta )
454
- if ( is_numeric( $meta ) && $meta > 0 )
455
- array_push( $postmeta_images_ids, $meta );
456
- set_transient( "wpmc_postmeta_images_ids", $postmeta_images_ids, Meow_WPMC_Core::$transient_life );
457
- $found['wpmc_postmeta_images_ids'] = $postmeta_images_ids;
458
- }
459
- }
460
-
461
- // Analyze Posts
462
- foreach ( $posts as $post ) {
463
-
464
- // Get HTML for this post
465
- $html = get_post_field( 'post_content', $post );
466
- $html = do_shortcode( $html );
467
- $html = wp_make_content_images_responsive( $html );
468
-
469
- // Run the scanners
470
- if ( $check_postmeta )
471
- do_action( 'wpmc_scan_postmeta', $post );
472
- if ( $check_posts )
473
- do_action( "wpmc_scan_post", $html, $post );
474
- }
475
- $finished = count( $posts ) < $limitsize;
476
- if ( $finished ) {
477
- $found = array();
478
-
479
- $theme_urls = get_transient( "wpmc_theme_urls" );
480
- $theme_ids = get_transient( "wpmc_theme_ids" );
481
- $widgets_urls = get_transient( "wpmc_widgets_urls" );
482
- $widgets_ids = get_transient( "wpmc_widgets_ids" );
483
- $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
484
- $posts_images_ids = get_transient( "wpmc_posts_images_ids" );
485
- $postmeta_images_urls = get_transient( "wpmc_postmeta_images_urls" );
486
- $postmeta_images_ids = get_transient( "wpmc_postmeta_images_ids" );
487
- $postmeta_images_acf_urls = get_transient( "wpmc_postmeta_images_acf_urls" );
488
- $postmeta_images_acf_ids = get_transient( "wpmc_postmeta_images_acf_ids" );
489
- $posts_images_vc = get_transient( "wpmc_posts_images_visualcomposer" );
490
- $galleries_images_urls = get_transient( "wpmc_galleries_images_urls" );
491
- $galleries_images_vc = get_transient( "wpmc_galleries_images_visualcomposer" );
492
- $galleries_images_fb = get_transient( "wpmc_galleries_images_fusionbuilder" );
493
- $galleries_images_wc = get_transient( "wpmc_galleries_images_woocommerce" );
494
- $galleries_images_et = get_transient( "wpmc_galleries_images_divi" );
495
-
496
- $found['theme_urls'] = is_array( $theme_urls ) ? array_unique( $theme_urls ) : array();
497
- $found['widgets_urls'] = is_array( $widgets_urls ) ? array_unique( $widgets_urls ) : array();
498
- $found['posts_images_urls'] = is_array( $posts_images_urls ) ? array_unique( $posts_images_urls ) : array();
499
- $found['postmeta_images_urls'] = is_array( $postmeta_images_urls ) ? array_unique( $postmeta_images_urls ) : array();
500
- $found['postmeta_images_acf_urls'] = is_array( $postmeta_images_acf_urls ) ? array_unique( $postmeta_images_acf_urls ) : array();
501
- $found['galleries_images_urls'] = is_array( $galleries_images_urls ) ? array_unique( $galleries_images_urls ) : array();
502
-
503
- $found['theme_ids'] = is_array( $theme_ids ) ? array_unique( $theme_ids ) : array();
504
- $found['widgets_ids'] = is_array( $widgets_ids ) ? array_unique( $widgets_ids ) : array();
505
- $found['posts_images_ids'] = is_array( $posts_images_ids ) ? array_unique( $posts_images_ids ) : array();
506
- $found['postmeta_images_ids'] = is_array( $postmeta_images_ids ) ? array_unique( $postmeta_images_ids ) : array();
507
- $found['postmeta_images_acf_ids'] = is_array( $postmeta_images_acf_ids ) ? array_unique( $postmeta_images_acf_ids ) : array();
508
- $found['posts_images_vc'] = is_array( $posts_images_vc ) ? array_unique( $posts_images_vc ) : array();
509
- $found['galleries_images_vc'] = is_array( $galleries_images_vc ) ? array_unique( $galleries_images_vc ) : array();
510
- $found['galleries_images_fb'] = is_array( $galleries_images_fb ) ? array_unique( $galleries_images_fb ) : array();
511
- $found['galleries_images_wc'] = is_array( $galleries_images_wc ) ? array_unique( $galleries_images_wc ) : array();
512
- $found['galleries_images_et'] = is_array( $galleries_images_et ) ? array_unique( $galleries_images_et ) : array();
513
-
514
- // For safety, remove the resolutions...
515
- // That will match more files, especially the sizes created before, used before, but not part of the
516
- // media metadata anymore.
517
-
518
- // ADD AN OPTION "CHECK SKIP RESOLUTION" (DEFAULT TRUE)
519
- $method = get_option( 'wpmc_method', 'media' );
520
- if ( $method == 'media' ) {
521
- // All URLs should be without resolution to make sure it matches Media
522
- array_walk( $found['theme_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
523
- array_walk( $found['widgets_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
524
- array_walk( $found['posts_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
525
- array_walk( $found['postmeta_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
526
- array_walk( $found['postmeta_images_acf_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
527
- array_walk( $found['galleries_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
528
- }
529
- else {
530
- // We need both filename without resolution and filename with resolution, it's important
531
- // to make sure the original file is not deleted if a size exists for it
532
- $clone = $found['theme_urls'];
533
- array_walk( $found['theme_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
534
- $found['theme_urls'] = array_merge( $clone, $found['theme_urls'] );
535
- $clone = $found['widgets_urls'];
536
- array_walk( $found['widgets_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
537
- $found['widgets_urls'] = array_merge( $clone, $found['widgets_urls'] );
538
- $clone = $found['posts_images_urls'];
539
- array_walk( $found['posts_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
540
- $found['posts_images_urls'] = array_merge( $clone, $found['posts_images_urls'] );
541
- $clone = $found['postmeta_images_urls'];
542
- array_walk( $found['postmeta_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
543
- $found['postmeta_images_urls'] = array_merge( $clone, $found['postmeta_images_urls'] );
544
- $clone = $found['postmeta_images_acf_urls'];
545
- array_walk( $found['postmeta_images_acf_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
546
- $found['postmeta_images_acf_urls'] = array_merge( $clone, $found['postmeta_images_acf_urls'] );
547
- $clone = $found['galleries_images_urls'];
548
- array_walk( $found['galleries_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
549
- $found['galleries_images_urls'] = array_merge( $clone, $found['galleries_images_urls'] );
550
- }
551
-
552
- set_transient( "wpmc_theme_urls", $found['theme_urls'], Meow_WPMC_Core::$transient_life );
553
- set_transient( "wpmc_theme_ids", $found['theme_ids'], Meow_WPMC_Core::$transient_life );
554
- set_transient( "wpmc_widgets_urls", $found['widgets_urls'], Meow_WPMC_Core::$transient_life );
555
- set_transient( "wpmc_widgets_ids", $found['widgets_ids'], Meow_WPMC_Core::$transient_life );
556
- set_transient( "wpmc_posts_images_urls", $found['posts_images_urls'], Meow_WPMC_Core::$transient_life );
557
- set_transient( "wpmc_posts_images_ids", $found['posts_images_ids'], Meow_WPMC_Core::$transient_life );
558
- set_transient( "wpmc_postmeta_images_urls", $found['postmeta_images_urls'], Meow_WPMC_Core::$transient_life );
559
- set_transient( "wpmc_postmeta_images_ids", $found['postmeta_images_ids'], Meow_WPMC_Core::$transient_life );
560
- set_transient( "wpmc_postmeta_images_acf_urls", $found['postmeta_images_acf_urls'], Meow_WPMC_Core::$transient_life );
561
- set_transient( "wpmc_postmeta_images_acf_ids", $found['postmeta_images_acf_ids'], Meow_WPMC_Core::$transient_life );
562
- set_transient( "wpmc_posts_images_visualcomposer", $found['posts_images_vc'], Meow_WPMC_Core::$transient_life );
563
- set_transient( "wpmc_galleries_images_visualcomposer", $found['galleries_images_vc'], Meow_WPMC_Core::$transient_life );
564
- set_transient( "wpmc_galleries_images_fusionbuilder", $found['galleries_images_fb'], Meow_WPMC_Core::$transient_life );
565
- set_transient( "wpmc_galleries_images_woocommerce", $found['galleries_images_wc'], Meow_WPMC_Core::$transient_life );
566
- set_transient( "wpmc_galleries_images_divi", $found['galleries_images_et'], Meow_WPMC_Core::$transient_life );
567
- set_transient( "wpmc_galleries_images_urls", $found['galleries_images_urls'], Meow_WPMC_Core::$transient_life );
568
- }
569
- if ( $finished && get_option( 'wpmc_debuglogs', false ) ) {
570
- $this->log( print_r( $found, true ) );
571
- }
572
- echo json_encode(
573
- array(
574
- 'success' => true,
575
- 'finished' => $finished,
576
- 'limit' => $limit + $limitsize,
577
- 'found' => $found,
578
- 'message' => __( "Posts checked.", 'media-cleaner' ) )
579
- );
580
- die();
581
- }
582
-
583
  function log( $data, $force = false ) {
584
  if ( !get_option( 'wpmc_debuglogs', false ) && !$force )
585
  return;
@@ -646,14 +632,6 @@ class Meow_WPMC_Core {
646
  return trailingslashit( $upload_folder['basedir'] ) . 'wpmc-trash';
647
  }
648
 
649
- function wpmc_check_db() {
650
- global $wpdb;
651
- $tbl_m = $wpdb->prefix . 'wpmcleaner';
652
- if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = '%s' AND table_name = '%s';", $wpdb->dbname, $tbl_m ) ) ) {
653
- wpmc_activate();
654
- }
655
- }
656
-
657
  /**
658
  *
659
  * DELETE / SCANNING / RESET
@@ -680,7 +658,7 @@ class Meow_WPMC_Core {
680
 
681
  function wpmc_recover( $id ) {
682
  global $wpdb;
683
- $table_name = $wpdb->prefix . "wpmcleaner";
684
  $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
685
  $issue->path = stripslashes( $issue->path );
686
 
@@ -770,7 +748,7 @@ class Meow_WPMC_Core {
770
 
771
  function wpmc_ignore( $id ) {
772
  global $wpdb;
773
- $table_name = $wpdb->prefix . "wpmcleaner";
774
  $has = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE id = %d AND ignored = 1", $id ) );
775
  if ( $has > 0 )
776
  $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET ignored = 0 WHERE id = %d", $id ) );
@@ -802,7 +780,7 @@ class Meow_WPMC_Core {
802
 
803
  function wpmc_delete( $id ) {
804
  global $wpdb;
805
- $table_name = $wpdb->prefix . "wpmcleaner";
806
  $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
807
  $regex = "^(.*)(\\s\\(\\+.*)$";
808
  $issue->path = preg_replace( '/' . $regex . '/i', '$1', $issue->path ); // remove " (+ 6 files)" from path
@@ -892,9 +870,88 @@ class Meow_WPMC_Core {
892
  *
893
  */
894
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
  function wpmc_check_is_ignore( $file ) {
896
  global $wpdb;
897
- $table_name = $wpdb->prefix . "wpmcleaner";
898
  $count = $wpdb->get_var( "SELECT COUNT(*)
899
  FROM $table_name
900
  WHERE ignored = 1
@@ -956,13 +1013,15 @@ class Meow_WPMC_Core {
956
  function wpmc_clean_url( $url ) {
957
  $upload_folder = wp_upload_dir();
958
  $baseurl = $upload_folder['baseurl'];
 
 
959
  $baseurl = str_replace( 'https://', 'http://', $baseurl );
960
  $baseurl = str_replace( 'http://www.', 'http://', $baseurl );
961
- $url = str_replace( 'https://', 'http://', $url );
962
- $url = str_replace( 'http://www.', 'http://', $url );
963
- $url = str_replace( $baseurl, '', $url );
964
- $url = trim( $url, "/" );
965
- return $url;
966
  }
967
 
968
  // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
@@ -1003,20 +1062,14 @@ class Meow_WPMC_Core {
1003
 
1004
  $size = filesize( $fullpath );
1005
 
1006
- // ANALYSIS
1007
  $this->last_analysis = "NONE";
1008
  $this->log( "Checking Media #{$attachmentId}: {$mainfile}" );
1009
  if ( $this->wpmc_check_is_ignore( $mainfile, $attachmentId ) ) {
1010
  $this->last_analysis = "IGNORED";
1011
  return true;
1012
  }
1013
- if ( $this->checkers->has_background_or_header( $mainfile, $attachmentId ) )
1014
- return true;
1015
- if ( $this->checkers->has_content( $mainfile, $attachmentId ) )
1016
- return true;
1017
- if ( $this->checkers->check_in_gallery( $mainfile, $attachmentId ) )
1018
- return true;
1019
- if ( $this->checkers->has_meta( $mainfile, $attachmentId ) )
1020
  return true;
1021
 
1022
  // If images, check the other files as well
@@ -1028,21 +1081,13 @@ class Meow_WPMC_Core {
1028
  $filepath = wp_upload_dir();
1029
  $filepath = $filepath['basedir'];
1030
  $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
1031
- if ( file_exists( $filepath ) ) {
1032
  $size += filesize( $filepath );
1033
- }
1034
  $file = $this->wpmc_clean_uploaded_filename( $filepath );
1035
  $countfiles++;
 
1036
  $this->log( "Checking Media #{$attachmentId}: {$file}" );
1037
-
1038
- // ANALYSIS
1039
- if ( $this->checkers->has_content( $file, $attachmentId ) )
1040
- return true;
1041
- if ( $this->checkers->check_in_gallery( $file, $attachmentId ) )
1042
- return true;
1043
- if ( $this->checkers->has_background_or_header( $file, $attachmentId ) )
1044
- return true;
1045
- if ( $this->checkers->has_meta( $file, $attachmentId ) )
1046
  return true;
1047
  }
1048
  }
@@ -1053,7 +1098,7 @@ class Meow_WPMC_Core {
1053
  }
1054
 
1055
  if ( !$checkOnly ) {
1056
- $table_name = $wpdb->prefix . "wpmcleaner";
1057
  $wpdb->insert( $table_name,
1058
  array(
1059
  'time' => current_time('mysql'),
@@ -1071,7 +1116,7 @@ class Meow_WPMC_Core {
1071
  // Delete all issues
1072
  function wpmc_reset_issues( $includingIgnored = false ) {
1073
  global $wpdb;
1074
- $table_name = $wpdb->prefix . "wpmcleaner";
1075
  if ( $includingIgnored ) {
1076
  $wpdb->query( "DELETE FROM $table_name WHERE deleted = 0" );
1077
  }
@@ -1081,6 +1126,10 @@ class Meow_WPMC_Core {
1081
  if ( file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
1082
  file_put_contents( plugin_dir_path( __FILE__ ) . '/media-cleaner.log', '' );
1083
  }
 
 
 
 
1084
  delete_transient( "wpmc_theme_ids" );
1085
  delete_transient( "wpmc_theme_urls" );
1086
  delete_transient( "wpmc_widgets_ids" );
@@ -1139,7 +1188,7 @@ class Meow_WPMC_Core {
1139
  if ( 'upload' != $current_screen->id )
1140
  return $actions;
1141
  global $wpdb;
1142
- $table_name = $wpdb->prefix . "wpmcleaner";
1143
  $res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE postId = %d", $post->ID ) );
1144
  if ( !empty( $res ) && isset( $actions['delete'] ) )
1145
  $actions['delete'] = "<a href='?page=media-cleaner&view=deleted'>" .
@@ -1156,7 +1205,6 @@ class Meow_WPMC_Core {
1156
 
1157
  function wpmc_screen() {
1158
  global $wplr;
1159
- $this->wpmc_check_db();
1160
  ?>
1161
  <div class='wrap'>
1162
 
@@ -1174,7 +1222,7 @@ class Meow_WPMC_Core {
1174
  $this->wpmc_reset_issues();
1175
  }
1176
  $s = isset ( $_GET[ 's' ] ) ? sanitize_text_field( $_GET[ 's' ] ) : null;
1177
- $table_name = $wpdb->prefix . "wpmcleaner";
1178
  $issues_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1179
  $total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1180
  $trash_total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 1" );
@@ -1285,18 +1333,27 @@ class Meow_WPMC_Core {
1285
 
1286
  <p>
1287
  <?php
1288
- $method = get_option( 'wpmc_method', 'media' );
1289
- if ( !$this->admin->is_registered() )
1290
- $method = 'media';
1291
 
1292
- $hide_warning = get_option( 'wpmc_hide_warning', false );
1293
-
1294
- if ( !$hide_warning ) {
1295
- _e( "<div class='notice notice-error'><p><b style='color: red;'>Important.</b> <b>Backup your DB and your /uploads directory before using Media Cleaner. </b> The deleted files will be temporarily moved to the <b>uploads/wpmc-trash</b> directory. After testing your website, you can check the <a href='?page=media-cleaner&s&view=deleted'>trash</a> to either empty it or recover the media and files. The Media Cleaner does its best to be safe to use. However, WordPress being a very dynamic and pluggable system, it is impossible to predict all the situations in which your files are used. <b style='color: red;'>Again, please backup!</b> If you don't know how, give a try to this: <a href='https://updraftplus.com/?afref=460' target='_blank'>UpdraftPlus</a>. <br /><br /><b style='color: red;'>Be thoughtful.</b> Don't blame Media Cleaner if it deleted too many or not enough of your files. It makes cleaning possible and this task is only possible this way; don't post a bad review because it broke your install. <b>If you have a proper backup, there is no risk</b>. Sorry for the lengthy message, but better be safe than sorry. You can disable this big warning in the options if you have a Pro license. Make sure you read this warning twice. Media Cleaner is awesome and always getting better so I hope you will enjoy it. Thank you :)</p></div>", 'media-cleaner' );
 
1296
  }
 
 
 
 
 
 
1297
 
1298
- if ( !MEDIA_TRASH ) {
1299
- _e( "<div class='notice notice-warning'><p>The trash for the Media Library is disabled. Any media removed by the plugin will be <b>permanently deleted</b>. To enable it, modify your wp-config.php file and add this line (preferably at the top):<br /><b>define( 'MEDIA_TRASH', true );</b></p></div>", 'media-cleaner' );
 
 
 
 
 
1300
  }
1301
 
1302
  if ( !$this->admin->is_registered() ) {
@@ -1495,18 +1552,24 @@ class Meow_WPMC_Core {
1495
  INSTALL / UNINSTALL
1496
  */
1497
 
1498
- register_activation_hook( __FILE__, 'wpmc_activate' );
1499
  register_deactivation_hook( __FILE__, 'wpmc_uninstall' );
1500
  register_uninstall_hook( __FILE__, 'wpmc_uninstall' );
1501
 
1502
- function wpmc_reset() {
1503
  wpmc_uninstall();
1504
- wpmc_activate();
 
 
 
 
 
 
1505
  }
1506
 
1507
- function wpmc_activate () {
1508
  global $wpdb;
1509
- $table_name = $wpdb->prefix . "wpmcleaner";
1510
  $charset_collate = $wpdb->get_charset_collate();
1511
  $sql = "CREATE TABLE $table_name (
1512
  id BIGINT(20) NOT NULL AUTO_INCREMENT,
@@ -1518,20 +1581,30 @@ function wpmc_activate () {
1518
  ignored TINYINT(1) NOT NULL DEFAULT 0,
1519
  deleted TINYINT(1) NOT NULL DEFAULT 0,
1520
  issue TINYTEXT NOT NULL,
1521
- UNIQUE KEY id (id)
 
 
 
 
 
 
 
 
 
 
 
 
1522
  ) " . $charset_collate . ";";
1523
  require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1524
  dbDelta( $sql );
1525
-
1526
- $upload_folder = wp_upload_dir();
1527
- $basedir = $upload_folder['basedir'];
1528
- if ( !is_writable( $basedir ) ) {
1529
- echo '<div class="error"><p>' . __( 'The directory for uploads is not writable. Media Cleaner will only be able to scan.', 'media-cleaner' ) . '</p></div>';
1530
- }
1531
  }
1532
 
1533
  function wpmc_uninstall () {
1534
  global $wpdb;
1535
  $table_name = $wpdb->prefix . "wpmcleaner";
1536
  $wpdb->query("DROP TABLE IF EXISTS $table_name");
 
 
 
 
1537
  }
6
  public $admin = null;
7
  public $last_analysis = null;
8
  public $last_analysis_ids = null;
 
9
  private $regex_file = '/[A-Za-z0-9-_,\s]+[.]{1}(MIMETYPES)/';
10
+ public $current_method = 'media';
11
+ private $refcache = array();
12
 
13
  public function __construct( $admin ) {
14
  $this->admin = $admin;
29
  }
30
 
31
  function admin_init() {
32
+ $this->current_method = get_option( 'wpmc_method', 'media' );
33
  $types = "jpg|jpeg|jpe|gif|png|tiff|bmp|csv|pdf|xls|xlsx|doc|docx|tiff|mp3|mp4|wav|lua";
34
  $this->regex_file = str_replace( "MIMETYPES", $types, $this->regex_file );
35
+ require( 'scan.php' );
36
+ require( 'checkers.php' );
37
  new MeowApps_WPMC_Scan( $this );
38
  $this->checkers = new Meow_WPMC_Checkers( $this );
39
  }
47
  }
48
 
49
  function display_metabox( $post ) {
 
 
 
 
 
50
  $this->log( "Media Edit > Checking Media #{$post->ID}" );
51
  $success = $this->wpmc_check_media( $post->ID, true );
52
  $this->log( "Success $success\n" );
88
  echo "Found in widget.";
89
  }
90
  else {
91
+ echo "It seems to be used as: " . $this->last_analysis;
92
  }
93
  }
94
  else {
154
  die();
155
  }
156
 
157
+ function deepsleep( $seconds ) {
158
+ $start_time = time();
159
+ while( true ) {
160
+ if ( ( time() - $start_time ) > $seconds ) {
161
+ return false;
162
+ }
163
+ get_post( array( 'posts_per_page' => 50 ) );
164
+ }
165
+ }
166
+
167
+ private $start_time;
168
+ private $time_elapsed = 0;
169
+ private $item_scan_avg_time = 0;
170
+ private $wordpress_init_time = 0.5;
171
+ private $max_execution_time;
172
+ private $items_checked = 0;
173
+ private $items_count = 0;
174
+
175
+ function timeout_check_start( $count ) {
176
+ $this->start_time = time();
177
+ $this->items_count = $count;
178
+ $this->max_execution_time = ini_get( "max_execution_time" );
179
+ if ( empty( $this->max_execution_time ) )
180
+ $this->max_execution_time = 30;
181
+ }
182
+
183
+ function timeout_check() {
184
+ $this->time_elapsed = time() - $this->start_time;
185
+ $this->time_remaining = $this->max_execution_time - $this->wordpress_init_time - $this->time_elapsed;
186
+ if ( $this->time_remaining - $this->item_scan_avg_time < 0 ) {
187
+ error_log("Media Cleaner Timeout! Check the Media Cleaner logs for more info.");
188
+ $this->log( "Timeout! Some info for debug:" );
189
+ $this->log( "Elapsed time: $this->time_elapsed" );
190
+ $this->log( "WP init time: $this->wordpress_init_time" );
191
+ $this->log( "Remaining time: $this->time_remaining" );
192
+ $this->log( "Scan time per item: $this->item_scan_avg_time" );
193
+ $this->log( "PHP max_execution_time: $this->max_execution_time" );
194
+ header("HTTP/1.0 408 Request Timeout");
195
+ exit;
196
+ }
197
+ }
198
+
199
+ function timeout_check_additem() {
200
+ $this->items_checked++;
201
+ $this->time_elapsed = time() - $this->start_time;
202
+ $this->item_scan_avg_time = ceil( ( $this->time_elapsed / $this->items_checked ) * 10 ) / 10;
203
+ }
204
+
205
+ function wp_ajax_wpmc_prepare_do() {
206
+ $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
207
+ $limitsize = get_option( 'wpmc_posts_buffer', 5 );
208
+ if ( empty( $limit ) )
209
+ $this->wpmc_reset_issues();
210
+
211
+ $method = get_option( 'wpmc_method', 'media' );
212
+ $check_library = get_option(' wpmc_media_library', true );
213
+ $check_postmeta = get_option( 'wpmc_postmeta', false );
214
+ $check_posts = get_option( 'wpmc_posts', false );
215
+ $check_widgets = get_option( 'wpmc_widgets', false );
216
+ if ( $method == 'media' && !$check_posts && !$check_postmeta && !$check_widgets ) {
217
+ echo json_encode( array(
218
+ 'results' => array(),
219
+ 'success' => true,
220
+ 'finished' => true,
221
+ 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
222
+ ) );
223
+ die();
224
+ }
225
+ if ( $method == 'files' && $check_library && !$check_posts && !$check_postmeta && !$check_widgets ) {
226
+ echo json_encode( array(
227
+ 'results' => array(),
228
+ 'success' => true,
229
+ 'finished' => true,
230
+ 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
231
+ ) );
232
+ die();
233
+ }
234
+
235
+ global $wpdb;
236
+ // Maybe we could avoid to check more post_types.
237
+ // SELECT post_type, COUNT(*) FROM `wp_posts` GROUP BY post_type
238
+ $posts = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
239
+ WHERE p.post_status != 'inherit'
240
+ AND p.post_status != 'trash'
241
+ AND p.post_type != 'attachment'
242
+ AND p.post_type != 'shop_order'
243
+ AND p.post_type != 'shop_order_refund'
244
+ AND p.post_type != 'nav_menu_item'
245
+ AND p.post_type != 'revision'
246
+ AND p.post_type != 'auto-draft'
247
+ AND p.post_type != 'wphb_minify_group'
248
+ AND p.post_type != 'customize_changeset'
249
+ AND p.post_type != 'oembed_cache'
250
+ AND p.post_type NOT LIKE '%acf-%'
251
+ AND p.post_type NOT LIKE '%edd_%'
252
+ LIMIT %d, %d", $limit, $limitsize
253
+ )
254
+ );
255
+
256
+ $found = array();
257
+
258
+ // Only at the beginning
259
+ if ( empty( $limit ) ) {
260
+
261
+ $this->log( "Analyzing for references:" );
262
+
263
+ $theme_ids = array();
264
+ $theme_urls = array();
265
+ $this->get_images_from_themes( $theme_ids, $theme_urls );
266
+ $this->add_reference_id( $theme_ids, 'THEME' );
267
+ $this->add_reference_url( $theme_urls, 'THEME' );
268
+
269
+ // Only on Start: Analyze Widgets
270
+ if ( get_option( 'wpmc_widgets', false ) ) {
271
+ $widgets_ids = array();
272
+ $widgets_urls = array();
273
+ $this->get_images_from_widgets( $widgets_ids, $widgets_urls );
274
+ $this->add_reference_id( $widgets_ids, 'WIDGET' );
275
+ $this->add_reference_url( $widgets_urls, 'WIDGET' );
276
+ }
277
+
278
+ // Only on Start: Analyze WooCommerce Categories Images
279
+ if ( class_exists( 'WooCommerce' ) ) {
280
+ $metas = $wpdb->get_col( "SELECT meta_value
281
+ FROM $wpdb->termmeta
282
+ WHERE meta_key LIKE '%thumbnail_id%'"
283
+ );
284
+ if ( count( $metas ) > 0 ) {
285
+ $postmeta_images_ids = array();
286
+ foreach ( $metas as $meta )
287
+ if ( is_numeric( $meta ) && $meta > 0 )
288
+ array_push( $postmeta_images_ids, $meta );
289
+ $this->add_reference_id( $postmeta_images_ids, 'META (ID)' );
290
+ }
291
+ }
292
+ }
293
+
294
+ $this->timeout_check_start( count( $posts ) );
295
+
296
+ foreach ( $posts as $post ) {
297
+ $this->timeout_check();
298
+ // Run the scanners
299
+ if ( $check_postmeta )
300
+ do_action( 'wpmc_scan_postmeta', $post );
301
+ if ( $check_posts ) {
302
+ // Get HTML for this post
303
+ $html = get_post_field( 'post_content', $post );
304
+ // Scan on the raw TML content
305
+ do_action( 'wpmc_scan_post', $html, $post );
306
+ $html = do_shortcode( $html );
307
+ $html = wp_make_content_images_responsive( $html );
308
+ // Scan with shortcodes resolved and src-set
309
+ do_action( 'wpmc_scan_post', $html, $post );
310
+ }
311
+ $this->timeout_check_additem();
312
+ }
313
+ // Write the references cached by the scanners
314
+ $this->write_references();
315
+
316
+ $finished = count( $posts ) < $limitsize;
317
+ if ( $finished ) {
318
+ $found = array();
319
+ // Optimize DB (but that takes too long!)
320
+ //$table_name = $wpdb->prefix . "mclean_refs";
321
+ // $wpdb->query ("DELETE a FROM $table_name as a, $table_name as b
322
+ // WHERE (a.mediaId = b.mediaId OR a.mediaId IS NULL AND b.mediaId IS NULL)
323
+ // AND (a.mediaUrl = b.mediaUrl OR a.mediaUrl IS NULL AND b.mediaUrl IS NULL)
324
+ // AND (a.originType = b.originType OR a.originType IS NULL AND b.originType IS NULL)
325
+ // AND (a.origin = b.origin OR a.origin IS NULL AND b.origin IS NULL)
326
+ // AND a.ID < b.ID;" );
327
+ // $wpdb->query ("DELETE a FROM $table_name as a, $table_name as b WHERE a.mediaId = b.mediaId AND a.mediaId > 0 AND a.ID < b.ID;" );
328
+ // $wpdb->query ("DELETE a FROM $table_name as a, $table_name as b WHERE a.mediaUrl = b.mediaUrl AND LENGTH(a.mediaUrl) > 1 AND a.ID < b.ID;" );
329
+ }
330
+ if ( $finished && get_option( 'wpmc_debuglogs', false ) ) {
331
+ //$this->log( print_r( $found, true ) );
332
+ }
333
+ echo json_encode(
334
+ array(
335
+ 'success' => true,
336
+ 'finished' => $finished,
337
+ 'limit' => $limit + $limitsize,
338
+ 'message' => __( "Posts checked.", 'media-cleaner' ) )
339
+ );
340
+ die();
341
+ }
342
+
343
  function wp_ajax_wpmc_scan_do () {
344
  // For debug, to pretend there is a timeout
345
+ //$this->deepsleep(10);
346
+ //header("HTTP/1.0 408 Request Timeout");
347
+ //exit;
348
+
349
  ob_start();
350
  $type = $_POST['type'];
351
  $data = $_POST['data'];
352
+ $this->timeout_check_start( count( $data ) );
353
  $success = 0;
354
  foreach ( $data as $piece ) {
355
+ $this->timeout_check();
356
  if ( $type == 'file' ) {
357
  $this->log( "Check File: {$piece}" );
358
  $result = ( apply_filters( 'wpmc_check_file', true, $piece ) ? 1 : 0 );
359
  $this->log( "Success " . $result . "\n" );
360
  $success += $result;
361
+ }
362
+ else if ( $type == 'media' ) {
363
  $this->log( "Checking Media #{$piece}" );
364
  $result = ( $this->wpmc_check_media( $piece ) ? 1 : 0 );
365
  $this->log( "Success " . $result . "\n" );
366
  $success += $result;
367
  }
368
+ $this->timeout_check_additem();
369
  }
370
  ob_end_clean();
371
  echo json_encode(
380
 
381
  function wp_ajax_wpmc_get_all_deleted () {
382
  global $wpdb;
383
+ $table_name = $wpdb->prefix . "mclean_scan";
384
  $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
385
  echo json_encode(
386
  array(
395
  function wp_ajax_wpmc_get_all_issues () {
396
  global $wpdb;
397
  $isTrash = ( isset( $_POST['isTrash'] ) && $_POST['isTrash'] == 1 ) ? true : false;
398
+ $table_name = $wpdb->prefix . "mclean_scan";
399
  if ( $isTrash )
400
  $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
401
  else
426
  }
427
  else if ( !empty( $m ) ) {
428
  // If it's a string, maybe it's a file (with an extension)
429
+ if ( preg_match( $this->regex_file, $m ) )
430
  array_push( $urls, $m );
431
  }
432
  }
500
  array_push( $results, $src );
501
  }
502
 
503
+ // PDF
504
+ preg_match_all( "/((https?:\/\/)?[^\\&\#\[\] \"\?]+\.pdf)/", $html, $res );
505
+ if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
506
+ foreach ( $res[1] as $url ) {
507
+ error_log(print_r($url, 1));
508
+ array_push( $results, $this->wpmc_clean_url( $url ) );
 
509
  }
510
+ }
511
+
512
+ // Background images
513
+ preg_match_all( "/url\(\'?\"?((https?:\/\/)?[^\\&\#\[\] \"\?]+\.(jpe?g|gif|png))\'?\"?/", $html, $res );
514
+ if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
515
+ foreach ( $res[1] as $url ) {
516
+ //error_log(print_r($res, 1));
517
+ array_push( $results, $this->wpmc_clean_url( $url ) );
518
+ }
519
+ }
520
 
521
  return $results;
522
  }
566
  }
567
  }
568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  function log( $data, $force = false ) {
570
  if ( !get_option( 'wpmc_debuglogs', false ) && !$force )
571
  return;
632
  return trailingslashit( $upload_folder['basedir'] ) . 'wpmc-trash';
633
  }
634
 
 
 
 
 
 
 
 
 
635
  /**
636
  *
637
  * DELETE / SCANNING / RESET
658
 
659
  function wpmc_recover( $id ) {
660
  global $wpdb;
661
+ $table_name = $wpdb->prefix . "mclean_scan";
662
  $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
663
  $issue->path = stripslashes( $issue->path );
664
 
748
 
749
  function wpmc_ignore( $id ) {
750
  global $wpdb;
751
+ $table_name = $wpdb->prefix . "mclean_scan";
752
  $has = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE id = %d AND ignored = 1", $id ) );
753
  if ( $has > 0 )
754
  $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET ignored = 0 WHERE id = %d", $id ) );
780
 
781
  function wpmc_delete( $id ) {
782
  global $wpdb;
783
+ $table_name = $wpdb->prefix . "mclean_scan";
784
  $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
785
  $regex = "^(.*)(\\s\\(\\+.*)$";
786
  $issue->path = preg_replace( '/' . $regex . '/i', '$1', $issue->path ); // remove " (+ 6 files)" from path
870
  *
871
  */
872
 
873
+ function add_reference_url( $urlOrUrls, $type, $origin = null, $extra = null ) {
874
+ $urlOrUrls = !is_array( $urlOrUrls ) ? array( $urlOrUrls ) : $urlOrUrls;
875
+ foreach ( $urlOrUrls as $url ) {
876
+ // With files, we need both filename without resolution and filename with resolution, it's important
877
+ // to make sure the original file is not deleted if a size exists for it.
878
+ // With media, all URLs should be without resolution to make sure it matches Media.
879
+ if ( $this->current_method == 'files' )
880
+ $this->add_reference( null, $url, $type, $origin );
881
+ $this->add_reference( 0, $this->clean_url_from_resolution( $url ), $type, $origin );
882
+ }
883
+ }
884
+
885
+ function add_reference_id( $idOrIds, $type, $origin = null, $extra = null ) {
886
+ $idOrIds = !is_array( $idOrIds ) ? array( $idOrIds ) : $idOrIds;
887
+ foreach ( $idOrIds as $id )
888
+ $this->add_reference( $id, "", $type, $origin );
889
+ }
890
+
891
+ private $cached_ids = array();
892
+ private $cached_urls = array();
893
+
894
+ private function add_reference( $id, $url, $type, $origin = null, $extra = null ) {
895
+ // The references are actually not being added directly in the DB, they are being pushed
896
+ // into a cache ($this->refcache).
897
+ if ( !empty( $id ) ) {
898
+ if ( !in_array( $id, $this->cached_ids ) )
899
+ array_push( $this->cached_ids, $id );
900
+ else
901
+ return;
902
+ }
903
+ if ( !empty( $url ) ) {
904
+ // The URL shouldn't contain http, https, javascript at the beginning (and there are probably many more cases)
905
+ // The URL must be cleaned before being passed as a reference.
906
+ if ( substr( $url, 0, 5 ) === "http:" )
907
+ return;
908
+ if ( substr( $url, 0, 6 ) === "https:" )
909
+ return;
910
+ if ( substr( $url, 0, 11 ) === "javascript:" )
911
+ return;
912
+ if ( !in_array( $url, $this->cached_urls ) )
913
+ array_push( $this->cached_urls, $url );
914
+ else
915
+ return;
916
+ }
917
+ //
918
+ array_push( $this->refcache, array( 'id' => $id, 'url' => $url, 'type' => $type, 'origin' => $origin ) );
919
+
920
+ // Without cache, the code would be this.
921
+ // $wpdb->insert( $table_name,
922
+ // array(
923
+ // 'time' => current_time('mysql'), 'mediaId' => $id, 'mediaUrl' => $url, 'origin' => $origin, 'originType' => $type )
924
+ // );
925
+ }
926
+
927
+ // The cache containing the references is wrote to the DB.
928
+ function write_references() {
929
+ global $wpdb;
930
+ $table = $wpdb->prefix . "mclean_refs";
931
+ $values = array();
932
+ $place_holders = array();
933
+ $query = "INSERT INTO $table (mediaId, mediaUrl, originType) VALUES ";
934
+ foreach( $this->refcache as $key => $value ) {
935
+ array_push( $values, $value['id'], $value['url'], $value['type'] );
936
+ if ( get_option( 'wpmc_debuglogs', false ) ) {
937
+ if ( !empty( $value['id'] ) )
938
+ $this->log( "* {$value['type']}: Media #{$value['id']}" );
939
+ if ( !empty( $value['url'] ) )
940
+ $this->log( "* {$value['type']}: {$value['url']}" );
941
+ }
942
+ $place_holders[] = "('%d','%s','%s')";
943
+ }
944
+ if ( !empty( $values ) ) {
945
+ $query .= implode( ', ', $place_holders );
946
+ $prepared = $wpdb->prepare( "$query ", $values );
947
+ $wpdb->query( $prepared );
948
+ }
949
+ $this->refcache = array();
950
+ }
951
+
952
  function wpmc_check_is_ignore( $file ) {
953
  global $wpdb;
954
+ $table_name = $wpdb->prefix . "mclean_scan";
955
  $count = $wpdb->get_var( "SELECT COUNT(*)
956
  FROM $table_name
957
  WHERE ignored = 1
1013
  function wpmc_clean_url( $url ) {
1014
  $upload_folder = wp_upload_dir();
1015
  $baseurl = $upload_folder['baseurl'];
1016
+ if ( substr( $url, 0, 2 ) === "//" )
1017
+ $url = "http:" . $url;
1018
  $baseurl = str_replace( 'https://', 'http://', $baseurl );
1019
  $baseurl = str_replace( 'http://www.', 'http://', $baseurl );
1020
+ $newurl = str_replace( 'https://', 'http://', $url );
1021
+ $newurl = str_replace( 'http://www.', 'http://', $newurl );
1022
+ $newurl = str_replace( $baseurl, '', $newurl );
1023
+ $newurl = trim( $newurl, "/" );
1024
+ return $newurl;
1025
  }
1026
 
1027
  // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
1062
 
1063
  $size = filesize( $fullpath );
1064
 
1065
+ // Analysis
1066
  $this->last_analysis = "NONE";
1067
  $this->log( "Checking Media #{$attachmentId}: {$mainfile}" );
1068
  if ( $this->wpmc_check_is_ignore( $mainfile, $attachmentId ) ) {
1069
  $this->last_analysis = "IGNORED";
1070
  return true;
1071
  }
1072
+ if ( $this->checkers->check( $mainfile, $attachmentId ) )
 
 
 
 
 
 
1073
  return true;
1074
 
1075
  // If images, check the other files as well
1081
  $filepath = wp_upload_dir();
1082
  $filepath = $filepath['basedir'];
1083
  $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
1084
+ if ( file_exists( $filepath ) )
1085
  $size += filesize( $filepath );
 
1086
  $file = $this->wpmc_clean_uploaded_filename( $filepath );
1087
  $countfiles++;
1088
+ // Analysis
1089
  $this->log( "Checking Media #{$attachmentId}: {$file}" );
1090
+ if ( $this->checkers->check( $mainfile, $attachmentId ) )
 
 
 
 
 
 
 
 
1091
  return true;
1092
  }
1093
  }
1098
  }
1099
 
1100
  if ( !$checkOnly ) {
1101
+ $table_name = $wpdb->prefix . "mclean_scan";
1102
  $wpdb->insert( $table_name,
1103
  array(
1104
  'time' => current_time('mysql'),
1116
  // Delete all issues
1117
  function wpmc_reset_issues( $includingIgnored = false ) {
1118
  global $wpdb;
1119
+ $table_name = $wpdb->prefix . "mclean_scan";
1120
  if ( $includingIgnored ) {
1121
  $wpdb->query( "DELETE FROM $table_name WHERE deleted = 0" );
1122
  }
1126
  if ( file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
1127
  file_put_contents( plugin_dir_path( __FILE__ ) . '/media-cleaner.log', '' );
1128
  }
1129
+ $table_name = $wpdb->prefix . "mclean_refs";
1130
+ $wpdb->query("TRUNCATE $table_name");
1131
+
1132
+ // Delete the old transient. Let's delete those lines later.
1133
  delete_transient( "wpmc_theme_ids" );
1134
  delete_transient( "wpmc_theme_urls" );
1135
  delete_transient( "wpmc_widgets_ids" );
1188
  if ( 'upload' != $current_screen->id )
1189
  return $actions;
1190
  global $wpdb;
1191
+ $table_name = $wpdb->prefix . "mclean_scan";
1192
  $res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE postId = %d", $post->ID ) );
1193
  if ( !empty( $res ) && isset( $actions['delete'] ) )
1194
  $actions['delete'] = "<a href='?page=media-cleaner&view=deleted'>" .
1205
 
1206
  function wpmc_screen() {
1207
  global $wplr;
 
1208
  ?>
1209
  <div class='wrap'>
1210
 
1222
  $this->wpmc_reset_issues();
1223
  }
1224
  $s = isset ( $_GET[ 's' ] ) ? sanitize_text_field( $_GET[ 's' ] ) : null;
1225
+ $table_name = $wpdb->prefix . "mclean_scan";
1226
  $issues_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1227
  $total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1228
  $trash_total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 1" );
1333
 
1334
  <p>
1335
  <?php
 
 
 
1336
 
1337
+ $table_scan = $wpdb->prefix . "mclean_scan";
1338
+ $table_refs = $wpdb->prefix . "mclean_refs";
1339
+ if ( $wpdb->get_var("SHOW TABLES LIKE '$table_scan'") != $table_scan ||
1340
+ $wpdb->get_var("SHOW TABLES LIKE '$table_refs'") != $table_refs ) {
1341
+ _e( "<div class='notice notice-error'><p><b>The database is not ready for Media Cleaner. The scan will not work.</b> Click on the <b>Reset</b> button, it re-creates the tables required by Media Cleaner. If this message still appear, contact the support.</p></div>", 'media-cleaner' );
1342
  }
1343
+ else {
1344
+ $method = get_option( 'wpmc_method', 'media' );
1345
+ if ( !$this->admin->is_registered() )
1346
+ $method = 'media';
1347
+
1348
+ $hide_warning = get_option( 'wpmc_hide_warning', false );
1349
 
1350
+ if ( !$hide_warning ) {
1351
+ _e( "<div class='notice notice-warning'><p><b style='color: red;'>Important.</b> <b>Backup your DB and your /uploads directory before using Media Cleaner. </b> The deleted files will be temporarily moved to the <b>uploads/wpmc-trash</b> directory. After testing your website, you can check the <a href='?page=media-cleaner&s&view=deleted'>trash</a> to either empty it or recover the media and files. The Media Cleaner does its best to be safe to use. However, WordPress being a very dynamic and pluggable system, it is impossible to predict all the situations in which your files are used. <b style='color: red;'>Again, please backup!</b> If you don't know how, give a try to this: <a href='https://updraftplus.com/?afref=460' target='_blank'>UpdraftPlus</a>. <br /><br /><b style='color: red;'>Be thoughtful.</b> Don't blame Media Cleaner if it deleted too many or not enough of your files. It makes cleaning possible and this task is only possible this way; don't post a bad review because it broke your install. <b>If you have a proper backup, there is no risk</b>. Sorry for the lengthy message, but better be safe than sorry. You can disable this big warning in the options if you have a Pro license. Make sure you read this warning twice. Media Cleaner is awesome and always getting better so I hope you will enjoy it. Thank you :)</p></div>", 'media-cleaner' );
1352
+ }
1353
+
1354
+ if ( !MEDIA_TRASH ) {
1355
+ _e( "<div class='notice notice-warning'><p>The trash for the Media Library is disabled. Any media removed by the plugin will be <b>permanently deleted</b>. To enable it, modify your wp-config.php file and add this line (preferably at the top):<br /><b>define( 'MEDIA_TRASH', true );</b></p></div>", 'media-cleaner' );
1356
+ }
1357
  }
1358
 
1359
  if ( !$this->admin->is_registered() ) {
1552
  INSTALL / UNINSTALL
1553
  */
1554
 
1555
+ register_activation_hook( __FILE__, 'wpmc_reset' );
1556
  register_deactivation_hook( __FILE__, 'wpmc_uninstall' );
1557
  register_uninstall_hook( __FILE__, 'wpmc_uninstall' );
1558
 
1559
+ function wpmc_reset () {
1560
  wpmc_uninstall();
1561
+ wpmc_install();
1562
+ $upload_folder = wp_upload_dir();
1563
+ $basedir = $upload_folder['basedir'];
1564
+ if ( !is_writable( $basedir ) ) {
1565
+ echo '<div class="error"><p>' . __( 'The directory for uploads is not writable. Media Cleaner will only be able to scan.', 'media-cleaner' ) . '</p></div>';
1566
+ }
1567
+
1568
  }
1569
 
1570
+ function wpmc_install() {
1571
  global $wpdb;
1572
+ $table_name = $wpdb->prefix . "mclean_scan";
1573
  $charset_collate = $wpdb->get_charset_collate();
1574
  $sql = "CREATE TABLE $table_name (
1575
  id BIGINT(20) NOT NULL AUTO_INCREMENT,
1581
  ignored TINYINT(1) NOT NULL DEFAULT 0,
1582
  deleted TINYINT(1) NOT NULL DEFAULT 0,
1583
  issue TINYTEXT NOT NULL,
1584
+ PRIMARY KEY (id)
1585
+ ) " . $charset_collate . ";";
1586
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1587
+ dbDelta( $sql );
1588
+ $table_name = $wpdb->prefix . "mclean_refs";
1589
+ $charset_collate = $wpdb->get_charset_collate();
1590
+ $sql = "CREATE TABLE $table_name (
1591
+ id BIGINT(20) NOT NULL AUTO_INCREMENT,
1592
+ mediaId BIGINT(20) NULL,
1593
+ mediaUrl VARCHAR(256) NULL,
1594
+ originType VARCHAR(32) NOT NULL,
1595
+ PRIMARY KEY (id),
1596
+ KEY mediaLookUp (mediaId, mediaUrl)
1597
  ) " . $charset_collate . ";";
1598
  require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1599
  dbDelta( $sql );
 
 
 
 
 
 
1600
  }
1601
 
1602
  function wpmc_uninstall () {
1603
  global $wpdb;
1604
  $table_name = $wpdb->prefix . "wpmcleaner";
1605
  $wpdb->query("DROP TABLE IF EXISTS $table_name");
1606
+ $table_name = $wpdb->prefix . "mclean_scan";
1607
+ $wpdb->query("DROP TABLE IF EXISTS $table_name");
1608
+ $table_name = $wpdb->prefix . "mclean_refs";
1609
+ $wpdb->query("DROP TABLE IF EXISTS $table_name");
1610
  }
custom_checkers.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // This file will contains all the CUSTOM checkers of the Media Cleaner system.
4
+ // It will hook on the Media Cleaner filters to detect if certain media is in use by a plugin.
5
+ // Each plugin or theme can have
6
+
7
+ // WooCommerce
8
+ // if ( is_plugin_active( 'woocommerce' ) ) ...
9
+ //
10
+
11
+ // WP/LR Sync
12
+ // if ( is_plugin_active( 'wplr-sync' ) ) ...
13
+ //
14
+
15
+ // Justified Image Grid
16
+ // Requested by: Alexander S. Kunz
17
+ // Added by: Jordy Meow
18
+ // Usage: Similar as WP internal gallery but use the justified_image_grid shortcode instead.
19
+
20
+ ?>
media-cleaner.php CHANGED
@@ -1,16 +1,13 @@
1
  <?php
2
  /*
3
  Plugin Name: Media Cleaner
4
- Plugin URI: http://meowapps.com
5
  Description: Clean your Media Library, many options, trash system.
6
- Version: 4.5.8
7
  Author: Jordy Meow
8
- Author URI: http://meowapps.com
9
  Text Domain: media-cleaner
10
 
11
- Big thanks to Matt (http://www.twistedtek.net/) for all his
12
- contributions made to the plugin.
13
-
14
  Originally developed for two of my websites:
15
  - Jordy Meow (http://offbeatjapan.org)
16
  - Haikyo (http://haikyo.org)
@@ -27,14 +24,14 @@ if ( class_exists( 'Meow_WPMC_Core' ) ) {
27
  if ( is_admin() ) {
28
 
29
  global $wpmc_version;
30
- $wpmc_version = '4.5.8';
31
 
32
  // Admin
33
- require( 'wpmc_admin.php' );
34
  $wpmc_admin = new Meow_WPMC_Admin( 'wpmc', __FILE__, 'media-cleaner' );
35
 
36
  // Core
37
- require( 'core.php' );
38
  $wpmc_core = new Meow_WPMC_Core( $wpmc_admin );
39
  $wpmc_admin->core = $wpmc_core;
40
 
1
  <?php
2
  /*
3
  Plugin Name: Media Cleaner
4
+ Plugin URI: https://meowapps.com
5
  Description: Clean your Media Library, many options, trash system.
6
+ Version: 4.6.2
7
  Author: Jordy Meow
8
+ Author URI: https://meowapps.com
9
  Text Domain: media-cleaner
10
 
 
 
 
11
  Originally developed for two of my websites:
12
  - Jordy Meow (http://offbeatjapan.org)
13
  - Haikyo (http://haikyo.org)
24
  if ( is_admin() ) {
25
 
26
  global $wpmc_version;
27
+ $wpmc_version = '4.6.2';
28
 
29
  // Admin
30
+ require __DIR__ . '/admin.php';
31
  $wpmc_admin = new Meow_WPMC_Admin( 'wpmc', __FILE__, 'media-cleaner' );
32
 
33
  // Core
34
+ require __DIR__ . '/core.php';
35
  $wpmc_core = new Meow_WPMC_Core( $wpmc_admin );
36
  $wpmc_admin->core = $wpmc_core;
37
 
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: TigrouMeow
3
  Tags: clean, delete, file, files, images, image, media, library, upload, clean, acf
4
  Requires at least: 4.2
5
  Tested up to: 4.9.4
6
- Stable tag: 4.5.8
7
 
8
  Clean your WordPress (broken media, unused media, files). It has its own trash and recovery features. Please read the description.
9
 
@@ -15,14 +15,14 @@ A tutorial is available on the official website, here: [Media Cleaner](https://m
15
 
16
  **This tool is a knife. Do not use it if you don't have any backup, or if you don't know what it does. For backup, you can use such a plugin as [UpdraftPlus](https://updraftplus.com/?afref=460).**
17
 
18
- **COMPATIBILITY**. I am adding support for specific plugins little by little. Currently, I have been working with ACF, Gutenberg, Divi, Fusion Builder (Avada), WooCommerce, Visual Composer (WPBakery), Elementor, and Beaver Builder. **Specific checks for Page Builders are being added to the Pro version** (as it requires meticulous work and updates).
19
-
20
  **SPECIAL PLUGIN**. Such a plugin is difficult to create and to maintain. If you understand WordPress, you probably know why. This plugin does its best to help you. Learn how to use it and you will get awesome results.
21
 
22
  **DASHBOARD**. The files detected as not used will be listed in a specific dashboard. At this point, it will be up to you to delete them. They will be then moved to a trash internal to the plugin. After more testing, you can trash them permanently.
23
 
24
  **PRO**. [Media Cleaner Pro](https://meowapps.com/media-cleaner) can scan your physical /uploads directory, and match it against the Media Library. It also has extra support for Page Builders.
25
 
 
 
26
  **AGAIN, BE CAREFUL**. Again, this plugin deletes files so be careful! Backup is not only important, it is **necessary**. Don't use this plugin if you don't understand how WordPress works.
27
 
28
  == Installation ==
@@ -32,17 +32,9 @@ A tutorial is available on the official website, here: [Media Cleaner](https://m
32
  3. Go in the Settings -> Media Cleaner and check the appropriate options
33
  3. Go in Media -> Media Cleaner
34
 
35
- == Upgrade Notice ==
36
-
37
- Replace all the files. Nothing else to do.
38
-
39
  == Frequently Asked Questions ==
40
 
41
- = Is it safe? =
42
- No! :) How can a plugin that deletes files be 100% safe? ;) I did my best (and will improve it in every way I can) but it is impossible to cover all the cases. On a normal WordPress install it should work perfectly, however other themes and plugins can do whatever they want do and register files in their own way, not always going through the API. I ran it on a few big websites and it performed very well. Make a backup (database + uploads directory) then run it. Again, I insist: BACKUP, BACKUP, BACKUP! Don't come here to complain that it deleted your files, because, yes, it deletes files. The plugin tries its best to help you and it is the only plugin that does it well.
43
-
44
- = What is 'Reset' doing exactly? =
45
- It re-creates the Media Cleaner table in the database. You will need to re-run the scan after this.
46
 
47
  == Screenshots ==
48
 
@@ -50,10 +42,16 @@ It re-creates the Media Cleaner table in the database. You will need to re-run t
50
 
51
  == Changelog ==
52
 
53
- = 4.5.8 =
 
54
  * Add: ACF Repeater support.
55
- * Update: Improve the code.
56
- * Fix: Debug logs weren't logging.
 
 
 
 
 
57
 
58
  = 4.5.4 =
59
  * Update: Streamlined the plugin, tutorial has also been rewritten.
3
  Tags: clean, delete, file, files, images, image, media, library, upload, clean, acf
4
  Requires at least: 4.2
5
  Tested up to: 4.9.4
6
+ Stable tag: 4.6.2
7
 
8
  Clean your WordPress (broken media, unused media, files). It has its own trash and recovery features. Please read the description.
9
 
15
 
16
  **This tool is a knife. Do not use it if you don't have any backup, or if you don't know what it does. For backup, you can use such a plugin as [UpdraftPlus](https://updraftplus.com/?afref=460).**
17
 
 
 
18
  **SPECIAL PLUGIN**. Such a plugin is difficult to create and to maintain. If you understand WordPress, you probably know why. This plugin does its best to help you. Learn how to use it and you will get awesome results.
19
 
20
  **DASHBOARD**. The files detected as not used will be listed in a specific dashboard. At this point, it will be up to you to delete them. They will be then moved to a trash internal to the plugin. After more testing, you can trash them permanently.
21
 
22
  **PRO**. [Media Cleaner Pro](https://meowapps.com/media-cleaner) can scan your physical /uploads directory, and match it against the Media Library. It also has extra support for Page Builders.
23
 
24
+ **COMPATIBILITY**. I am adding support for specific plugins little by little. Currently, I have been working with ACF, Gutenberg, Divi, Fusion Builder (Avada), WooCommerce, Visual Composer (WPBakery), Elementor, and Beaver Builder. **Specific checks for Page Builders are being added to the Pro version** (as it requires meticulous work and updates).
25
+
26
  **AGAIN, BE CAREFUL**. Again, this plugin deletes files so be careful! Backup is not only important, it is **necessary**. Don't use this plugin if you don't understand how WordPress works.
27
 
28
  == Installation ==
32
  3. Go in the Settings -> Media Cleaner and check the appropriate options
33
  3. Go in Media -> Media Cleaner
34
 
 
 
 
 
35
  == Frequently Asked Questions ==
36
 
37
+ The official FAQ is [here](https://meowapps.com/wplr-sync/faq/).
 
 
 
 
38
 
39
  == Screenshots ==
40
 
42
 
43
  == Changelog ==
44
 
45
+ = 4.6.2 =
46
+ * Add: Added an option to only scan the thumbnails and ignore the base files.
47
  * Add: ACF Repeater support.
48
+ * Update: Improved the code and the performance. Scan is now done differently, using the DB.
49
+ * Fix: Debug logs weren't logging (and enhanced them a bit).
50
+ * Notice: That's a big release :) Please help me by giving me a nice review, here: https://wordpress.org/support/plugin/meow-lightbox/reviews/?rate=5#new-post.
51
+
52
+ = 4.5.5 =
53
+ * Fix: Doesn't remove the Media entry if the files cannot be deleted.
54
+ * Update: Displays a warning if the log file cannot be created.
55
 
56
  = 4.5.4 =
57
  * Update: Streamlined the plugin, tutorial has also been rewritten.
scan.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class MeowApps_WPMC_Scan {
4
+
5
+ private $core = null;
6
+ private $likes = "";
7
+ private $metakeys = array( '%gallery%', '%ids%' );
8
+
9
+ public function __construct( $core ) {
10
+ $this->core = $core;
11
+
12
+ // Prepare likes for SQL
13
+ foreach ( $this->metakeys as $metakey )
14
+ $this->likes .= "OR meta_key LIKE '$metakey' ";
15
+
16
+ // Detect values in the general (known, based on %like%) Meta Keys
17
+ add_action( 'wpmc_scan_postmeta', array( $this, 'scan_postmeta' ) );
18
+
19
+ if ( class_exists( 'WooCommerce' ) )
20
+ add_action( 'wpmc_scan_postmeta', array( $this, 'scan_postmeta_woocommerce' ) );
21
+
22
+ // Check URLs, IDs, WP Gallery, WooCommerce
23
+ add_action( 'wpmc_scan_post', array( $this, 'scan_post' ), 10, 2 );
24
+
25
+ // Advanced Custom Fields
26
+ if ( class_exists( 'acf' ) )
27
+ add_action( 'wpmc_scan_postmeta', array( $this, 'scan_postmeta_acf' ) );
28
+
29
+ }
30
+
31
+ public function scan_post( $html, $id ) {
32
+ $posts_images_urls = array();
33
+ $posts_images_ids = array();
34
+ $galleries_images = array();
35
+
36
+ // Check URLs in HTML
37
+ $new_urls = $this->core->get_urls_from_html( $html );
38
+ $posts_images_urls = array_merge( $posts_images_urls, $new_urls );
39
+
40
+ // Check Excerpt for WooCommerce (= Product Short Description)
41
+ if ( class_exists( 'WooCommerce' ) ) {
42
+ $excerpt = get_post_field( 'post_excerpt', $id );
43
+ if ( !empty( $excerpt ) ) {
44
+ $new_urls = $this->core->get_urls_from_html( $excerpt );
45
+ $posts_images_urls = array_merge( $posts_images_urls, $new_urls );
46
+ }
47
+ }
48
+
49
+ // Check for images IDs through classes in in posts
50
+ preg_match_all( "/wp-image-([0-9]+)/", $html, $res );
51
+ if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 )
52
+ $posts_images_ids = array_merge( $posts_images_ids, $res[1] );
53
+
54
+
55
+ // Standard WP Gallery
56
+ $galleries = get_post_galleries_images( $id );
57
+ foreach ( $galleries as $gallery ) {
58
+ foreach ( $gallery as $image ) {
59
+ array_push( $galleries_images, $this->core->wpmc_clean_url( $image ) );
60
+ }
61
+ }
62
+
63
+ $this->core->add_reference_id( $posts_images_ids, 'CONTENT (ID)' );
64
+ $this->core->add_reference_url( $posts_images_urls, 'CONTENT (URL)' );
65
+ $this->core->add_reference_url( $galleries_images, 'GALLERY (URL)' );
66
+ }
67
+
68
+ public function scan_postmeta( $id ) {
69
+ global $wpdb;
70
+ $query = $wpdb->prepare( "SELECT meta_value FROM $wpdb->postmeta
71
+ WHERE post_id = %d
72
+ AND meta_key = '_thumbnail_id' ", $id ) . $this->likes;
73
+ $metas = $wpdb->get_col( $query );
74
+ if ( count( $metas ) > 0 ) {
75
+ $postmeta_images_ids = array();
76
+ $postmeta_images_urls = array();
77
+ foreach ( $metas as $meta ) {
78
+ // Just a number, let's assume it's a Media ID
79
+ if ( is_numeric( $meta ) ) {
80
+ if ( $meta > 0 )
81
+ array_push( $postmeta_images_ids, $meta );
82
+ continue;
83
+ }
84
+ $decoded = @unserialize( $meta );
85
+ if ( is_array( $decoded ) ) {
86
+ $this->core->array_to_ids_or_urls( $decoded, $postmeta_images_ids, $postmeta_images_urls );
87
+ continue;
88
+ }
89
+ $exploded = explode( ',', $meta );
90
+ if ( is_array( $exploded ) ) {
91
+ $this->core->array_to_ids_or_urls( $exploded, $postmeta_images_ids, $postmeta_images_urls );
92
+ continue;
93
+ }
94
+ }
95
+ $this->core->add_reference_id( $postmeta_images_ids, 'META (ID)' );
96
+ $this->core->add_reference_id( $postmeta_images_urls, 'META (URL)' );
97
+ }
98
+ }
99
+
100
+ function scan_postmeta_woocommerce( $id ) {
101
+ global $wpdb;
102
+ $galleries_images_wc = array();
103
+ $res = $wpdb->get_col( "SELECT meta_value FROM $wpdb->postmeta WHERE post_id = $id
104
+ AND meta_key = '_product_image_gallery'" );
105
+ foreach ( $res as $values ) {
106
+ $ids = explode( ',', $values );
107
+ $galleries_images_wc = array_merge( $galleries_images_wc, $ids );
108
+ }
109
+ $this->core->add_reference_id( $galleries_images_wc, 'WOOCOOMMERCE (ID)' );
110
+ }
111
+
112
+ public function scan_postmeta_acf( $id ) {
113
+ $postmeta_images_acf_ids = array();
114
+ $postmeta_images_acf_urls = array();
115
+ $fields = get_field_objects( $id );
116
+ if ( is_array( $fields ) ) {
117
+ foreach ( $fields as $field ) {
118
+ $format = "";
119
+ if ( isset( $field['return_format'] ) )
120
+ $format = $field['return_format'];
121
+ else if ( isset( $field['save_format'] ) )
122
+ $format = $field['save_format'];
123
+
124
+ // ACF Repeater
125
+ if ( $field['type'] == 'repeater' ) {
126
+ if ( !empty( $field['value'] ) ) {
127
+ foreach ( $field['value'] as $subfields ) {
128
+ foreach ( $subfields as $subfield ) {
129
+ if ( $subfield['type'] == 'image' ) {
130
+ if ( !empty( $subfield['id'] ) )
131
+ array_push( $postmeta_images_acf_ids, $subfield['id'] );
132
+ if ( !empty( $subfield['url'] ) )
133
+ array_push( $postmeta_images_acf_urls, $this->core->wpmc_clean_url( $subfield['url'] ) );
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ // ACF Image ID and URL
140
+ else if ( $field['type'] == 'image' && ( $format == 'array' || $format == 'object' ) ) {
141
+ if ( !empty( $field['value']['id'] ) )
142
+ array_push( $postmeta_images_acf_ids, $field['value']['id'] );
143
+ if ( !empty( $field['value']['url'] ) )
144
+ array_push( $postmeta_images_acf_urls, $this->core->wpmc_clean_url( $field['value']['url'] ) );
145
+ }
146
+ // ACF Image ID
147
+ else if ( $field['type'] == 'image' && $format == 'id' && !empty( $field['value'] ) ) {
148
+ array_push( $postmeta_images_acf_ids, $field['value'] );
149
+ }
150
+ // ACF Image URL
151
+ else if ( $field['type'] == 'image' && $format == 'url' && !empty( $field['value'] ) ) {
152
+ array_push( $postmeta_images_acf_urls, $this->core->wpmc_clean_url( $field['value'] ) );
153
+ }
154
+ // ACF Gallery
155
+ else if ( $field['type'] == 'gallery' && !empty( $field['value'] ) ) {
156
+ foreach ( $field['value'] as $media ) {
157
+ if ( !empty( $media['id'] ) )
158
+ array_push( $postmeta_images_acf_ids, $media['id'] );
159
+ }
160
+ }
161
+ }
162
+ $this->core->add_reference_id( $postmeta_images_acf_ids, 'ACF (ID)' );
163
+ $this->core->add_reference_url( $postmeta_images_acf_urls, 'ACF (URL)' );
164
+ }
165
+ }
166
+
167
+ }