Media Cleaner - Version 3.6.8

Version Description

  • Fix: Little issue when inserting the serial key for the first time.
  • Update: Compliance with the WordPress.org rules, new licensing system.
  • Update: Moved assets.
  • Info: There will be an important warning showing up during this update. It is an important annoucement.
Download this release

Release Info

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

Version 3.6.8

common/admin.css ADDED
@@ -0,0 +1,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: 11px !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 {
165
+ width: 19px;
166
+ height: 19px;
167
+ margin-right: 10px;
168
+ }
169
+
170
+ /* IMAGE SIZES RELATED INFO */
171
+
172
+ .meow-sized-images {
173
+ margin-top: 0px;
174
+ cursor: pointer;
175
+ }
176
+
177
+ .meow-sized-images li, #meow-modal-info .meow-sized-image {
178
+ display: block;
179
+ color: white;
180
+ padding: 5px 0px;
181
+ font-size: 10px;
182
+ text-align: center;
183
+ width: 18px;
184
+ height: 18px;
185
+ line-height: 8px;
186
+ background: black;
187
+ float: left;
188
+ margin-right: 1px;
189
+ box-sizing: border-box;
190
+ margin-bottom: 2px;
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 */
297
+ .meow-col { display: block; float:left; margin: 1% 0 1% 1.6%; }
298
+ .meow-col:first-child { margin-left: 0; }
299
+
300
+ /* GROUPING */
301
+ .meow-row { clear: both; padding: 0px; margin: 0px; }
302
+ .meow-row:before,
303
+ .meow-row:after { content:""; display:table; }
304
+ .meow-row:after { clear:both; }
305
+ .meow-row { zoom:1; /* For IE 6/7 */ }
306
+
307
+ /* GRID OF THREE */
308
+ .meow-span_3_of_3 { width: 100%; }
309
+ .meow-span_2_of_3 { width: 66.1%; }
310
+ .meow-span_1_of_3 { width: 32.2%; }
311
+
312
+ /* GRID OF TWO */
313
+ .meow-span_2_of_2 { width: 100%; }
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 ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( !class_exists( 'MeowApps_Admin' ) ) {
4
+
5
+ class MeowApps_Admin {
6
+
7
+ public static $loaded = false;
8
+ public static $version = "1.0";
9
+
10
+ public function __construct( $prefix = null, $item = null ) {
11
+ if ( !MeowApps_Admin::$loaded ) {
12
+ if ( is_admin() ) {
13
+ add_action( 'admin_menu', array( $this, 'admin_menu_start' ) );
14
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
15
+ add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ) );
16
+ }
17
+ MeowApps_Admin::$loaded = true;
18
+ }
19
+ $this->prefix = $prefix;
20
+ $this->item = $item;
21
+ }
22
+
23
+ function display_ads() {
24
+ return !get_option( 'meowapps_hide_ads', false );
25
+ }
26
+
27
+ function display_title( $title = "Meow Apps",
28
+ $author = "By <a style='text-decoration: none;' href='http://meowapps.com' target='_blank'>Jordy Meow</a>" ) {
29
+ if ( !empty( $this->prefix ) )
30
+ $title = apply_filters( $this->prefix . '_plugin_title', $title );
31
+ if ( $this->display_ads() ) {
32
+ echo '<a class="meow-header-ad" target="_blank" href="http://www.shareasale.com/r.cfm?b=906810&u=767054&m=41388&urllink=&afftrack="">
33
+ <img src="' . $this->common_url( 'img/wpengine.png' ) . '" height="60" border="0" /></a>';
34
+ }
35
+ ?>
36
+ <h1 style="line-height: 16px;">
37
+ <img width="36" style="margin-right: 10px; float: left; position: relative; top: -5px;"
38
+ src="<?php echo $this->meowapps_logo_url(); ?>"><?php echo $title; ?><br />
39
+ <span style="font-size: 12px"><?php echo $author; ?></span>
40
+ </h1>
41
+ <div style="clear: both;"></div>
42
+ <?php
43
+ }
44
+
45
+ function admin_enqueue_scripts() {
46
+ wp_register_style( 'meowapps-core-css', $this->common_url( 'admin.css' ) );
47
+ wp_enqueue_style( 'meowapps-core-css' );
48
+ }
49
+
50
+ function admin_menu_start() {
51
+ if ( get_option( 'meowapps_hide_meowapps', false ) ) {
52
+ register_setting( 'general', 'meowapps_hide_meowapps' );
53
+ add_settings_field( 'meowapps_hide_ads', 'Meow Apps Menu', array( $this, 'meowapps_hide_dashboard_callback' ), 'general' );
54
+ return;
55
+ }
56
+
57
+ // Creates standard menu if it does NOT exist
58
+ global $submenu;
59
+ if ( !isset( $submenu[ 'meowapps-main-menu' ] ) ) {
60
+ add_menu_page( 'Meow Apps', 'Meow Apps', 'manage_options', 'meowapps-main-menu',
61
+ array( $this, 'admin_meow_apps' ), 'dashicons-camera', 82 );
62
+ add_submenu_page( 'meowapps-main-menu', __( 'Dashboard', 'meowapps' ),
63
+ __( 'Dashboard', 'meowapps' ), 'manage_options',
64
+ 'meowapps-main-menu', array( $this, 'admin_meow_apps' ) );
65
+ }
66
+
67
+ add_settings_section( 'meowapps_common_settings', null, null, 'meowapps_common_settings-menu' );
68
+ add_settings_field( 'meowapps_hide_meowapps', "Main Menu",
69
+ array( $this, 'meowapps_hide_dashboard_callback' ),
70
+ 'meowapps_common_settings-menu', 'meowapps_common_settings' );
71
+ add_settings_field( 'meowapps_hide_ads', "Ads",
72
+ array( $this, 'meowapps_hide_ads_callback' ),
73
+ 'meowapps_common_settings-menu', 'meowapps_common_settings' );
74
+ register_setting( 'meowapps_common_settings', 'meowapps_hide_meowapps' );
75
+ register_setting( 'meowapps_common_settings', 'meowapps_hide_ads' );
76
+ }
77
+
78
+ function meowapps_hide_ads_callback() {
79
+ $value = get_option( 'meowapps_hide_ads', null );
80
+ $html = '<input type="checkbox" id="meowapps_hide_ads" name="meowapps_hide_ads" value="1" ' .
81
+ checked( 1, get_option( 'meowapps_hide_ads' ), false ) . '/>';
82
+ $html .= __( '<label>Hide</label><br /><small>Doesn\'t display the ads.</small>', 'wp-retina-2x' );
83
+ echo $html;
84
+ }
85
+
86
+ function meowapps_hide_dashboard_callback() {
87
+ $value = get_option( 'meowapps_hide_meowapps', null );
88
+ $html = '<input type="checkbox" id="meowapps_hide_meowapps" name="meowapps_hide_meowapps" value="1" ' .
89
+ checked( 1, get_option( 'meowapps_hide_meowapps' ), false ) . '/>';
90
+ $html .= __( '<label>Hide <b>Meow Apps</b> Menu</label><br /><small>Hide Meow Apps menu and all its components, for a nicer an faster WordPress admin UI. An option will be added in Settings > General to display it again.</small>', 'wp-retina-2x' );
91
+ echo $html;
92
+ }
93
+
94
+ function display_serialkey_box( $url = "https://meowapps.com/" ) {
95
+ $html = '<div class="meow-box">';
96
+ $html .= '<h3 class="' . ( $this->is_registered( $this->prefix ) ? 'meow-bk-blue' : 'meow-bk-red' ) . '">Pro Version ' .
97
+ ( $this->is_registered( $this->prefix ) ? '(enabled)' : '(disabled)' ) . '</h3>';
98
+ $html .= '<div class="inside">';
99
+ echo $html;
100
+ $html = apply_filters( 'meowapps_license_input', ( 'More information about the Pro version here:
101
+ <a target="_blank" href="' . $url . '">' . $url . '</a>.' ), $url );
102
+ $html .= '</div>';
103
+ $html .= '</div>';
104
+ echo $html;
105
+ }
106
+
107
+ function is_registered() {
108
+ return apply_filters( 'meowapps_is_registered', false, $this->prefix );
109
+ }
110
+
111
+ function check_install( $plugin ) {
112
+ $pluginpath = get_home_path() . 'wp-content/plugins/' . $plugin;
113
+ if ( !file_exists( $pluginpath ) ) {
114
+ $url = wp_nonce_url( "update.php?action=install-plugin&plugin=$plugin", "install-plugin_$plugin" );
115
+ return "<a href='$url'><small><span class='' style='float: right;'>install</span></small></a>";
116
+ }
117
+ $plugin_file = $plugin . '/' . $plugin . '.php';
118
+ if ( is_plugin_active( $plugin_file ) )
119
+ return "<small><span style='float: right; color: green;'><span class='dashicons dashicons-yes'></span></span></small>";
120
+ else {
121
+ $url = wp_nonce_url( self_admin_url( 'plugins.php?action=activate&plugin=' . $plugin_file ),
122
+ 'activate-plugin_' . $plugin_file );
123
+ return '<small><span style="color: orange; float: right;">off
124
+ (<a style="color: rgba(30,140,190,.8); text-decoration: none;" href="' .
125
+ $url . '">enable</a>)</span></small>';
126
+ }
127
+ }
128
+
129
+ function common_url( $file ) {
130
+ die( "Meow Apps: The function common_url( \$file ) needs to be overriden." );
131
+ // Normally, this should be used:
132
+ // return plugin_dir_url( __FILE__ ) . ( '\/common\/' . $file );
133
+ }
134
+
135
+ function meowapps_logo_url() {
136
+ return $this->common_url( 'img/meowapps.png' );
137
+ }
138
+
139
+ function plugins_loaded() {
140
+ if ( isset( $_GET[ 'tool' ] ) && $_GET[ 'tool' ] == 'error_log' ) {
141
+ $sec = "5";
142
+ header("Refresh: $sec;");
143
+ }
144
+ }
145
+
146
+ function admin_meow_apps() {
147
+
148
+ echo '<div class="wrap meow-dashboard">';
149
+ if ( isset( $_GET['tool'] ) && $_GET['tool'] == 'phpinfo' ) {
150
+ echo "<a href=\"javascript:history.go(-1)\">< Go back</a><br /><br />";
151
+ echo '<div id="phpinfo">';
152
+ ob_start();
153
+ phpinfo();
154
+ $pinfo = ob_get_contents();
155
+ ob_end_clean();
156
+ $pinfo = preg_replace( '%^.*<body>(.*)</body>.*$%ms','$1', $pinfo );
157
+ echo $pinfo;
158
+ echo "</div>";
159
+ }
160
+ else if ( isset( $_GET['tool'] ) && $_GET['tool'] == 'error_log' ) {
161
+ $errorpath = ini_get( 'error_log' );
162
+ echo "<a href=\"javascript:history.go(-1)\">< Go back</a><br /><br />";
163
+ echo '<div id="error_log">';
164
+ if ( file_exists( $errorpath ) ) {
165
+ echo "Now (auto-reload every 5 seconds):<br />[" . date( "d-M-Y H:i:s", time() ) . " UTC]<br /<br /><br />Errors (order by latest):";
166
+ $errors = file_get_contents( $errorpath );
167
+ $errors = explode( "\n", $errors );
168
+ $errors = array_reverse( $errors );
169
+ $errors = implode( "<br />", $errors );
170
+ echo $errors;
171
+ }
172
+ else {
173
+ echo "The PHP Error Logs cannot be found. Please ask your hosting service for it.";
174
+ }
175
+ echo "</div>";
176
+
177
+ }
178
+ else {
179
+
180
+ ?>
181
+ <?php $this->display_title(); ?>
182
+ <p>
183
+ <?php _e( 'Meow Apps is run by <a href="http://jordymeow.com">Jordy Meow</a>, a photographer and software developer based in Japan. When he realized that WordPress was an environment not so friendly to photographers, Meow Apps was born. It is a suite of plugins dedicate to make the blogging life of image lovers easy and pretty. Meow Apps also teams up with the best players in the community (other themes or plugins developers). For more information, please check <a href="http://meowapps.com" target="_blank">Meow Apps</a>.', 'meowapps' )
184
+ ?>
185
+ </p>
186
+ <div class="meow-row">
187
+ <div class="meow-box meow-col meow-span_1_of_2 ">
188
+ <h3 class=""><span class="dashicons dashicons-camera"></span> UI Plugins </h3>
189
+ <ul class="">
190
+ <li><b>WP/LR Sync</b> <?php echo $this->check_install( 'wplr-sync' ) ?><br />
191
+ Bring synchronization from Lightroom to WordPress.</li>
192
+ <li><b>Meow Lightbox</b> <?php echo $this->check_install( 'meow-lightbox' ) ?><br />
193
+ Lightbox with EXIF information nicely displayed.</li>
194
+ <li><b>Meow Gallery</b> <?php echo $this->check_install( 'meow-gallery' ) ?><br />
195
+ Simple gallery to make your photos look better (Masonry and others).</li>
196
+ <li><b>Audio Story for Images</b> <?php echo $this->check_install( 'audio-story-images' ) ?><br />
197
+ Add audio to your images.</li>
198
+ </ul>
199
+ </div>
200
+ <div class="meow-box meow-col meow-span_1_of_2">
201
+ <h3 class=""><span class="dashicons dashicons-admin-tools"></span> System Plugins</h3>
202
+ <ul class="">
203
+ <li><b>Media File Renamer</b> <?php echo $this->check_install( 'media-file-renamer' ) ?><br />
204
+ Nicer filenames and better SEO, automatically.</li>
205
+ <li><b>Media Cleaner</b> <?php echo $this->check_install( 'media-cleaner' ) ?><br />
206
+ Detect the files you are not using to clean your system.</li>
207
+ <li><b>WP Retina 2x</b> <?php echo $this->check_install( 'wp-retina-2x' ) ?><br />
208
+ Make your website perfect for retina devices.</li>
209
+ <li><b>WP Category Permalink</b> <?php echo $this->check_install( 'wp-category-permalink' ) ?><br />
210
+ Allows you to select a main category (or taxonomy) for nicer permalinks.</li>
211
+ </ul>
212
+ </div>
213
+ </div>
214
+
215
+ <div class="meow-row">
216
+ <div class="meow-box meow-col meow-span_2_of_3">
217
+ <h3><span class="dashicons dashicons-admin-tools"></span> Common</h3>
218
+ <div class="inside">
219
+ <form method="post" action="options.php">
220
+ <?php settings_fields( 'meowapps_common_settings' ); ?>
221
+ <?php do_settings_sections( 'meowapps_common_settings-menu' ); ?>
222
+ <?php submit_button(); ?>
223
+ </form>
224
+ </div>
225
+ </div>
226
+
227
+ <div class="meow-box meow-col meow-span_1_of_3">
228
+ <h3><span class="dashicons dashicons-admin-tools"></span> Debug</h3>
229
+ <div class="inside">
230
+ <ul>
231
+ <li><a href="?page=meowapps-main-menu&amp;tool=error_log">Display Error Log</a></li>
232
+ <li><a href="?page=meowapps-main-menu&amp;tool=phpinfo">Display PHP Info</a></li>
233
+ </ul>
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ <?php
239
+
240
+ }
241
+
242
+ echo "<br /><small style='color: lightgray;'>Meow Admin " . MeowApps_Admin::$version . "</small></div>";
243
+ }
244
+
245
+ // HELPERS
246
+
247
+ static function size_shortname( $name ) {
248
+ $name = preg_split( '[_-]', $name );
249
+ $short = strtoupper( substr( $name[0], 0, 1 ) );
250
+ if ( count( $name ) > 1 )
251
+ $short .= strtoupper( substr( $name[1], 0, 1 ) );
252
+ return $short;
253
+ }
254
+
255
+ }
256
+
257
+ if ( file_exists( plugin_dir_path( __FILE__ ) . '/meowapps/admin.php' ) ) {
258
+ require( 'meowapps/admin.php' );
259
+ }
260
+ }
261
+
262
+ ?>
common/img/meowapps.png ADDED
Binary file
common/img/wpengine.png ADDED
Binary file
languages/media-file-cleaner-fr_FR.mo ADDED
Binary file
languages/media-file-cleaner-fr_FR.po ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: WP Media Cleaner\n"
4
+ "POT-Creation-Date: 2015-08-25 11:33+0900\n"
5
+ "PO-Revision-Date: 2015-08-25 11:34+0900\n"
6
+ "Last-Translator: Jordy Meow <jordy@meow.fr>\n"
7
+ "Language-Team: Meow.fr <apps@meow.fr>\n"
8
+ "Language: fr_FR\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "X-Generator: Poedit 1.8.1\n"
13
+ "X-Poedit-KeywordsList: _e;__\n"
14
+ "X-Poedit-Basepath: ..\n"
15
+ "X-Poedit-SourceCharset: UTF-8\n"
16
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
17
+ "X-Poedit-SearchPath-0: .\n"
18
+
19
+ #: media-file-cleaner.php:55 media-file-cleaner.php:73
20
+ #: media-file-cleaner.php:91
21
+ msgid "Status unknown."
22
+ msgstr "Statut inconnu"
23
+
24
+ #: media-file-cleaner.php:118
25
+ msgid "Items checked."
26
+ msgstr "Fichiers vérifiés"
27
+
28
+ #: media-file-cleaner.php:132 media-file-cleaner.php:150
29
+ msgid "List generated."
30
+ msgstr "Liste générée"
31
+
32
+ #: media-file-cleaner.php:262
33
+ msgid "Files retrieved."
34
+ msgstr "Fichiers récupérés"
35
+
36
+ #: media-file-cleaner.php:272
37
+ msgid "Medias retrieved."
38
+ msgstr "Images récupérées"
39
+
40
+ #: media-file-cleaner.php:278
41
+ msgid "No task."
42
+ msgstr "Aucune opération"
43
+
44
+ #: media-file-cleaner.php:906
45
+ msgid "Seems not in use."
46
+ msgstr "Ne semble pas en cours d'utilisation"
47
+
48
+ #: media-file-cleaner.php:909
49
+ msgid "Not in Media Library."
50
+ msgstr "Pas dans la bibliothèque multimédia"
51
+
52
+ #: media-file-cleaner.php:912
53
+ msgid "Orphan retina."
54
+ msgstr "Retina orphelin"
55
+
56
+ #: media-file-cleaner.php:915
57
+ msgid "File not found."
58
+ msgstr "Fichier introuvable"
59
+
60
+ #: media-file-cleaner.php:996
61
+ msgid "Scan"
62
+ msgstr "Scanner"
63
+
64
+ #: media-file-cleaner.php:1000
65
+ msgid "Delete"
66
+ msgstr "Supprimer"
67
+
68
+ #: media-file-cleaner.php:1002
69
+ msgid "Recover"
70
+ msgstr "Récupérer"
71
+
72
+ #: media-file-cleaner.php:1006
73
+ msgid "Ignore"
74
+ msgstr "Ignorer"
75
+
76
+ #: media-file-cleaner.php:1010
77
+ msgid "Reset"
78
+ msgstr "Reset"
79
+
80
+ #: media-file-cleaner.php:1015
81
+ msgid "Recover all"
82
+ msgstr "Tout récupérer"
83
+
84
+ #: media-file-cleaner.php:1016
85
+ msgid "Empty trash"
86
+ msgstr "Vider la corbeille"
87
+
88
+ #: media-file-cleaner.php:1018
89
+ msgid "Delete all"
90
+ msgstr "Tout supprimer"
91
+
92
+ #: media-file-cleaner.php:1027
93
+ msgid "Search"
94
+ msgstr "Chercher"
95
+
96
+ #: media-file-cleaner.php:1042
97
+ msgid ""
98
+ "<b>Backup your database and files before delete! This is important.</b> The "
99
+ "files deleted by the plugin will be moved to the 'uploads/wpmc-trash' "
100
+ "directory and you can trash them later. I am trying my best to make this "
101
+ "plugin safe but since it deletes files on a very dynamic system (= "
102
+ "WordPress), it is impossible to predict every single situation. Be careful."
103
+ msgstr ""
104
+ "<p style=\"text-align: justify;\"><strong>Note importante </strong>: Avant "
105
+ "de lancer la scan, je vous remercie de <strong>sauvegarder vos fichiers et "
106
+ "votre base de données</strong> parce que les éléments supprimés par le "
107
+ "plugin WP Media Cleaner seront déplacés dans le répertoire \"uploads/wpmc-"
108
+ "trash\" de votre client FTP.</p>"
109
+
110
+ #: media-file-cleaner.php:1044
111
+ msgid ""
112
+ " If you delete an item of the type MEDIA, the database entry for it (Media "
113
+ "Library) will be deleted permanently."
114
+ msgstr ""
115
+ "<p style=\"text-align: justify;\">Si vous supprimez un média de votre "
116
+ "bibliothèque WordPress à l'issue d'un scan, le plugin WP Media Cleaner le "
117
+ "supprimera de celle-ci.</p>"
118
+
119
+ #: media-file-cleaner.php:1049
120
+ msgid ""
121
+ "Scan is not enabled for neither the files or for the medias. The plugin is "
122
+ "basically disabled. <b>Please check Settings > Media Cleaner</b>."
123
+ msgstr ""
124
+ "<p style=\"text-align: justify;\">Vous ne pouvez pas utiliser WP Media "
125
+ "Cleaner, et scanner vos fichiers et vos médias tant que vous n'aurez pas "
126
+ "<strong>vérifier les paramètres</strong> (Réglages > Media Cleaner)</"
127
+ "strong>. Il faut ainsi que vous cochiez le scan de la bibliothèque et/ou le "
128
+ "scan des fichiers pour que l'extension fonctionne.</p>"
129
+
130
+ #: media-file-cleaner.php:1054
131
+ msgid ""
132
+ "<b>This version is not Pro.</b> It will only let you delete the files "
133
+ "<u><b>one by one</b></u>, for your safety. <b>If the plugin works perfectly "
134
+ "for deleting the files one by one then you can <a href='http://apps.meow.fr/"
135
+ "media-file-cleaner'>get the PRO version</a></b>. It will let you delete all "
136
+ "the files in one click."
137
+ msgstr ""
138
+ "<p style=\"text-align: justify;\">Vous utilisez la version gratuite de WP "
139
+ "Media Cleaner qui vous autorise à scanner votre bibliothèque de médias et à "
140
+ "supprimer les fichiers un par un.</p>\n"
141
+ "<p style=\"text-align: justify;\"> Une version payante de WP Media Cleaner "
142
+ "est disponible sur <a href='http://apps.meow.fr/wp-media-cleaner'>le site de "
143
+ "son auteur</a> afin que vous l'utilisiez avec toutes ses fonctionnalités "
144
+ "(suppression de tous les fichiers).</p>"
145
+
146
+ #: media-file-cleaner.php:1058
147
+ #, php-format
148
+ msgid ""
149
+ "There are <b>%d issue(s)</b> with your files, accounting for <b>%d MB</b>. "
150
+ "Your trash contains <b>%d MB.</b>"
151
+ msgstr ""
152
+ "Il y a <strong>%d fichier(s) inutilisé(s)</strong> qui représente un total "
153
+ "de <strong>%d MB</strong>. Votre corbeille contient <strong>%d MB</strong>."
154
+
155
+ #: media-file-cleaner.php:1075
156
+ msgid "Issues"
157
+ msgstr "Fichiers inutilisés"
158
+
159
+ #: media-file-cleaner.php:1076
160
+ msgid "Ignored"
161
+ msgstr "Fichiers ignorés"
162
+
163
+ #: media-file-cleaner.php:1077
164
+ msgid "Trash"
165
+ msgstr "Corbeille"
166
+
167
+ #: media-file-cleaner.php:1086
168
+ msgid "Thumb"
169
+ msgstr "Aperçu"
170
+
171
+ #: media-file-cleaner.php:1088 media-file-cleaner.php:1132
172
+ msgid "Type"
173
+ msgstr "Type"
174
+
175
+ #: media-file-cleaner.php:1089 media-file-cleaner.php:1132
176
+ msgid "Origin"
177
+ msgstr "Origine"
178
+
179
+ #: media-file-cleaner.php:1090 media-file-cleaner.php:1132
180
+ msgid "Path"
181
+ msgstr "Fichier"
182
+
183
+ #: media-file-cleaner.php:1091 media-file-cleaner.php:1132
184
+ msgid "Issue"
185
+ msgstr "Problème"
186
+
187
+ #: media-file-cleaner.php:1092 media-file-cleaner.php:1132
188
+ msgid "Size"
189
+ msgstr "Taille"
190
+
191
+ #: media-file-cleaner.php:1181
192
+ msgid "Your serial does not seem right."
193
+ msgstr "Votre numéro de série ne semble pas être correct."
194
+
195
+ #: media-file-cleaner.php:1184
196
+ msgid "Your subscription is not active."
197
+ msgstr "Votre abonnement n'est pas actif."
198
+
199
+ #: media-file-cleaner.php:1187
200
+ msgid "Too many URLs are linked to your subscription."
201
+ msgstr "Il y a trop d'adresse URL qui sont liées à votre abonnement."
202
+
203
+ #: media-file-cleaner.php:1190
204
+ msgid "There is a problem with your subscription."
205
+ msgstr "Il y a un problème avec votre abonnement."
206
+
207
+ #: media-file-cleaner.php:1199
208
+ msgid "Your subscription is enabled."
209
+ msgstr "Votre abonnement est actif."
210
+
211
+ #: media-file-cleaner.php:1249
212
+ msgid ""
213
+ "The directory for uploads is not writable. Media File Cleaner will only be "
214
+ "able to scan."
215
+ msgstr ""
216
+ "Le répertoire pour les téléchargements (/uploads) n'est pas accessible en "
217
+ "écriture. WP Media Cleaner ne pourra seulement que scanner vos fichiers. "
218
+ "Pour résoudre le problème, merci de contacter votre hébergeur Internet."
219
+
220
+ #: meow_footer.php:22
221
+ msgid ""
222
+ "Developed by <a style=\"text-decoration: none;\" href=\"http://www.meow.fr\" "
223
+ "target=\"_blank\">Jordy Meow</a>"
224
+ msgstr ""
225
+ "Développé par <a style=\"text-decoration: none;\" href=\"http://www.meow.fr"
226
+ "\">Jordy Meow</a>."
227
+
228
+ #: meow_footer.php:34
229
+ msgid ""
230
+ "I love and strongly recommend WP Engine. My plugins are all tested with it."
231
+ msgstr "J'utilise WP Engine pour tester mes plugins et je le recommande."
232
+
233
+ #: meow_footer.php:45
234
+ msgid ""
235
+ "<b>This plugin is actively developed and maintained by <a href=\"http://www."
236
+ "meow.fr\">Jordy Meow</a></b>.<br />More of my tools are available here: <a "
237
+ "href=\"http://apps.meow.fr\">Meow Apps</a>. I am also a photographer in "
238
+ "Japan: <a href=\"http://www.totorotimes.com\">Totoro Times</a>."
239
+ msgstr ""
240
+ "<strong>Le plugin est développé et maintenu par <a href=\"http://www.meow.fr"
241
+ "\">Jordy Meow</a></strong>.<br />Mes outils et mes plugins sont disponibles "
242
+ "dans les pages de mon site <a href=\"http://apps.meow.fr\">Meow Apps</a>. </"
243
+ "br />Je suis également photographe au Japon et mes travaux sont disponibles "
244
+ "sur mon autre site : <a href=\"http://www.totorotimes.fr\">Totoro Times</a>."
245
+
246
+ #: meow_footer.php:48
247
+ #, php-format
248
+ msgid "Donation link: %sPaypal%s. Thanks! ^^"
249
+ msgstr ""
250
+ "Don Paypal : %sPaypal%s. Merci de soutenir l'auteur du plugin WP Media "
251
+ "Cleaner."
252
+
253
+ #: wpmc_settings.php:48
254
+ msgid "Options"
255
+ msgstr "Options"
256
+
257
+ #: wpmc_settings.php:52
258
+ msgid "Serial Key (Pro)"
259
+ msgstr "Numéro de série (Pro)"
260
+
261
+ #: wpmc_settings.php:67
262
+ msgid "Scan Media"
263
+ msgstr "Scan de la bibliothèque"
264
+
265
+ #: wpmc_settings.php:68
266
+ msgid ""
267
+ "The Media Library will be scanned.<br /><small>The medias from Media Library "
268
+ "which seem not being used in your WordPress will be marked as to be deleted."
269
+ "</small>"
270
+ msgstr ""
271
+ "<p style=\"text-align: justify;\">La bibliothèque de médias sera scannée.</"
272
+ "p>\n"
273
+ "<p style=\"text-align: justify;\"><small>Les fichiers situés dans votre "
274
+ "bibliothèque de médias qui seront inutilisés par vos billets, seront listés "
275
+ "dans l'onglet \"Fichiers inutilisés\" (Médias > Media Cleaner)</small>.</p>"
276
+
277
+ #: wpmc_settings.php:74
278
+ msgid "Scan Files"
279
+ msgstr "Scan des fichiers"
280
+
281
+ #: wpmc_settings.php:75
282
+ msgid ""
283
+ "The Uploads folder will be scanned.<br /><small>The files in your /uploads "
284
+ "folder that don't seem being used in your WordPress will be marked as to be "
285
+ "deleted. <b>If they are found in your Media Library, they will be considered "
286
+ "as fine.</b></small>"
287
+ msgstr ""
288
+ "<p style=\"text-align: justify;\">Le dossier uploads du FTP sera scanné.</"
289
+ "p>\n"
290
+ "<p style=\"text-align: justify;\"><small>Les fichiers du dossier uploads qui "
291
+ "seront inutilisés par vos billets, seront listés dans l'onglet \"Fichiers "
292
+ "inutilisés\" (Médias > Media Cleaner). Si ils se trouvent dans votre "
293
+ "bibliothèque de médias, les fichiers seront valides.<small></p>"
294
+
295
+ #: wpmc_settings.php:81
296
+ msgid "Resolve Shortcode"
297
+ msgstr "Gestion des shortcodes"
298
+
299
+ #: wpmc_settings.php:82
300
+ #, php-format
301
+ msgid ""
302
+ "The shortcodes you are using in your posts and widgets will be resolved and "
303
+ "checked.<br /><small>This process takes more resources. If the scanning "
304
+ "suddenly stops, this might be the cause. Here is the list of the shortcodes "
305
+ "enabled on your WordPress that you might be using: <b>%s</b>. Please note "
306
+ "that the gallery shortcode is checked by the normal process. You don't need "
307
+ "to have this option enabled for the WP gallery.</small>"
308
+ msgstr ""
309
+ "<p style=\"text-align: justify;\">WP Media Cleaner vérifiera les shortcodes "
310
+ "que vous utilisez dans vos articles, dans vos pages et dans vos widgets. Ce "
311
+ "processus de vérification nécessitera un peu plus de ressources que "
312
+ "d'habitude. Si le scan s'arrête soudainement, merci de décocher cette "
313
+ "option, d’enregistrer le paramètre et de relancer le processus.</p>\n"
314
+ "<p style=\"text-align: justify;\"><small>Je vous présente la liste non-"
315
+ "exhaustive des shortcodes qui pourraient être utilisés sur votre WordPress : "
316
+ "%s.</small></p>\n"
317
+ "<p style=\"text-align: justify;\"><small>A noter également qu'il est inutile "
318
+ "de cocher cette option pour vérifier uniquement le shortcode \"gallery\" de "
319
+ "WordPress.</small></p>"
320
+
321
+ #: wpmc_settings.php:88
322
+ msgid "UTF-8 Support"
323
+ msgstr "Gestion de l'UTF-8"
324
+
325
+ #: wpmc_settings.php:89
326
+ msgid ""
327
+ "The filenames in UTF-8 will not be skipped.<br /><small>PHP does not always "
328
+ "work well with UTF-8 on all systems (Windows?). If the scanning suddenly "
329
+ "stops, this might be the cause.</small>"
330
+ msgstr ""
331
+ "<p style=\"text-align: justify;\">Les noms de fichiers encodés en UTF-8 ne "
332
+ "seront pas ignorés.</p>\n"
333
+ "<p style=\"text-align: justify;\"><small>Le PHP ne fonctionne pas toujours "
334
+ "correctement avec ce type d'encodage et le système Windows. Si le scan des "
335
+ "fichiers s'arrête soudainement, cela signifierait qu'il y a un soucis avec "
336
+ "le mode UTF-8 et que vous devez décocher cette option.</small></p>"
337
+
338
+ #: wpmc_settings.php:95
339
+ msgid "Hide Thumbnails"
340
+ msgstr "Désactiver les miniatures"
341
+
342
+ #: wpmc_settings.php:96
343
+ msgid ""
344
+ "Hide the thumbnails column.<br /><small>Useful if your WordPress if filled-"
345
+ "up with huge images.</small>"
346
+ msgstr ""
347
+ "<p style=\"text-align: justify;\">Cacher la colonne des miniatures.</p>\n"
348
+ "<p style=\"text-align: justify;\"><small>Cette option est utile si la taille "
349
+ "de vos images est importante.</small></p>"
350
+
351
+ #: wpmc_settings.php:105
352
+ #, php-format
353
+ msgid "Status: %s"
354
+ msgstr "Statut : %s"
355
+
356
+ #: wpmc_settings.php:110
357
+ msgid "Serial"
358
+ msgstr "Numéro de série"
359
+
360
+ #: wpmc_settings.php:111
361
+ msgid ""
362
+ "<br />Enter your serial or subscription ID here. If you don't have one yet, "
363
+ "get one <a target=\"_blank\" href=\"http://apps.meow.fr/wp-media-cleaner/"
364
+ "\">right here</a>."
365
+ msgstr ""
366
+ "<p style=\"text-align: justify;\">Saisissez votre numéro de série dans la "
367
+ "zone de texte située ci-dessus. Si vous ne possédez pas de clé de licence, "
368
+ "merci de vous rendre sur <a href=\"http://apps.meow.fr/wp-media-cleaner/"
369
+ "\">le site de l'auteur</a>.</p>"
370
+
371
+ #~ msgid ""
372
+ #~ "<b>This version is not Pro.</b> It will only let you delete the files "
373
+ #~ "<u><b>one by one</b></u>, for your safety. <b>If the plugin works "
374
+ #~ "perfectly for deleting the files one by one then you can <a href='http://"
375
+ #~ "apps.meow.fr/wp-media-cleaner'>get the PRO version</a></b>. It will let "
376
+ #~ "you delete all the files in one click."
377
+ #~ msgstr ""
378
+ #~ "<p style=\"text-align: justify;\">Vous utilisez la version gratuite de WP "
379
+ #~ "Media Cleaner qui vous autorise à scanner votre bibliothèque de médias et "
380
+ #~ "à supprimer les fichiers un par un.</p>\n"
381
+ #~ "<p style=\"text-align: justify;\"> Une version payante de WP Media "
382
+ #~ "Cleaner est disponible sur <a href='http://apps.meow.fr/wp-media-"
383
+ #~ "cleaner'>le site de son auteur</a> afin que vous l'utilisiez avec toutes "
384
+ #~ "ses fonctionnalités (suppression de tous les fichiers).</p>"
385
+
386
+ #~ msgid ""
387
+ #~ "The directory for uploads is not writable. WP Media Cleaner will only be "
388
+ #~ "able to scan."
389
+ #~ msgstr ""
390
+ #~ "Le répertoire pour les téléchargements (/uploads) n'est pas accessible en "
391
+ #~ "écriture. WP Media Cleaner ne pourra seulement que scanner vos fichiers. "
392
+ #~ "Pour résoudre le problème, merci de contacter votre hébergeur Internet."
393
+
394
+ #~ msgid ""
395
+ #~ "Scan is not enabled for neither the files or for the medias. The plugin "
396
+ #~ "is basically disabled.<br /><b>Please check Settings > Media Cleaner</b>."
397
+ #~ msgstr ""
398
+ #~ "<p style=\"text-align: justify;\">Le scan n'est activé ni pour les "
399
+ #~ "fichiers ni pour les médias. <strong>Merci de vérifier les paramètres de "
400
+ #~ "WP Media Cleaner dans les options générales de WordPress (Réglages > "
401
+ #~ "Media Cleaner)</strong>.</p>"
402
+
403
+ #~ msgid "Basics"
404
+ #~ msgstr "Options"
405
+
406
+ #~ msgid "Pro"
407
+ #~ msgstr "Pro"
408
+
409
+ #~ msgid "Lists generated."
410
+ #~ msgstr "Listes générées."
411
+
412
+ #~ msgid "Related content or media not found."
413
+ #~ msgstr "Pas de media associé, ni contenu."
414
+
415
+ #~ msgid ""
416
+ #~ "Be aware that a media will be considered <b>NOT</b> an issue <b>ONLY IF</"
417
+ #~ "b> it is found in the Posts or Pages, and not in a Gallery. The deletion "
418
+ #~ "of a media is also <b>PERMANENT</b>."
419
+ #~ msgstr ""
420
+ #~ "Attention, un media ne sera pas considéré comme un problème <b>seulement "
421
+ #~ "dans le cas où</b> il est présent dans les Posts ou les Pages, mais pas "
422
+ #~ "dans les Galleries ! La suppression des médias est aussi <b>irrémédiable</"
423
+ #~ "b>."
424
+
425
+ #~ msgid "The Media Library will be scanned."
426
+ #~ msgstr "La Bibliothèque sera scannée."
427
+
428
+ #~ msgid "The Uploads folder will be scanned."
429
+ #~ msgstr "Les fichiers uploadés seront scannés."
430
+
431
+ #~ msgid "The categories are both the same. Mmm. Please be careful!"
432
+ #~ msgstr "Les catégories sont identiques... ohlala, faites-attention !"
433
+
434
+ #~ msgid ""
435
+ #~ "This plugin switches category 2 by 2. Doing that, you can change the way "
436
+ #~ "WordPress picks the default category. This is particularly useful when a "
437
+ #~ "post belongs to 2 or more categories. This plugin modifies directly the "
438
+ #~ "ID's, which means you can uninstall it when you are done."
439
+ #~ msgstr ""
440
+ #~ "Ce plugin échange les ids des catégories deux par deux. Vous pourrez "
441
+ #~ "ainsi changer la façon dont WordPress choisi les catégories par défaut "
442
+ #~ "(très utile quand les posts appartiennent à deux catégories ou plus). Ce "
443
+ #~ "plugin modifie les ids directement, il peut donc être désinstallé une "
444
+ #~ "fois que l'opération est terminée."
445
+
446
+ #~ msgid "Please backup your database before switching."
447
+ #~ msgstr "Sauvegardez votre base de donnée avant d'utiliser cette fonction."
448
+
449
+ #~ msgid "Categories (ordered by id's)"
450
+ #~ msgstr "Catégories (triées par id)"
451
+
452
+ #~ msgid "Switch:"
453
+ #~ msgstr "Échanger :"
media-cleaner.css ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .wp-core-ui .button-red {
2
+ background-color: #9B2124;
3
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#C5292E), to(#9B2124));
4
+ background-image: -webkit-linear-gradient(top, #C5292E, #9B2124);
5
+ background-image: -moz-linear-gradient(top, #C5292E, #9B2124);
6
+ background-image: -ms-linear-gradient(top, #C5292E, #9B2124);
7
+ background-image: -o-linear-gradient(top, #C5292E, #9B2124);
8
+ background-image: linear-gradient(to bottom, #C5292E, #9B2124);
9
+ border-color: #9B2124;
10
+ border-bottom-color: #8D1F21;
11
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.5);
12
+ box-shadow: inset 0 1px 0 rgba(120,200,230,0.5);
13
+ color: #fff;
14
+ text-decoration: none;
15
+ text-shadow: 0 1px 0 rgba(0,0,0,0.1);
16
+ float: right;
17
+ }
18
+
19
+ .wp-core-ui .button-red.hover,
20
+ .wp-core-ui .button-red:hover,
21
+ .wp-core-ui .button-red.focus,
22
+ .wp-core-ui .button-red:focus {
23
+ background-color: #B72629;
24
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#D22E30), to(#9B2124));
25
+ background-image: -webkit-linear-gradient(top, #D22E30, #9B2124);
26
+ background-image: -moz-linear-gradient(top, #D22E30, #9B2124);
27
+ background-image: -ms-linear-gradient(top, #D22E30, #9B2124);
28
+ background-image: -o-linear-gradient(top, #D22E30, #9B2124);
29
+ background-image: linear-gradient(to bottom, #D22E30, #9B2124);
30
+ border-color: #7F1C1F;
31
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.6);
32
+ box-shadow: inset 0 1px 0 rgba(120,200,230,0.6);
33
+ color: #fff;
34
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
35
+ }
36
+
37
+ .wp-core-ui .button-red.focus,
38
+ .wp-core-ui .button-red:focus {
39
+ border-color: #500F0E;
40
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.6), 1px 1px 2px rgba(0,0,0,0.4);
41
+ box-shadow: inset 0 1px 0 rgba(120,200,230,0.6), 1px 1px 2px rgba(0,0,0,0.4);
42
+ }
43
+
44
+ .wp-core-ui .button-red.active,
45
+ .wp-core-ui .button-red.active:hover,
46
+ .wp-core-ui .button-red.active:focus,
47
+ .wp-core-ui .button-red:active {
48
+ background: #7F1C1F;
49
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#9B2124), to(#B72629));
50
+ background-image: -webkit-linear-gradient(top, #9B2124, #B72629);
51
+ background-image: -moz-linear-gradient(top, #9B2124, #B72629);
52
+ background-image: -ms-linear-gradient(top, #9B2124, #B72629);
53
+ background-image: -o-linear-gradient(top, #9B2124, #B72629);
54
+ background-image: linear-gradient(to bottom, #9B2124, #B72629);
55
+ border-color: #601312 #AE2426 #AE2426 #AE2426;
56
+ color: rgba(255,255,255,0.95);
57
+ -webkit-box-shadow: inset 0 1px 0 rgba(0,0,0,0.1);
58
+ box-shadow: inset 0 1px 0 rgba(0,0,0,0.1);
59
+ text-shadow: 0 1px 0 rgba(0,0,0,0.1);
60
+ }
61
+
62
+ .wp-core-ui .button-red[disabled],
63
+ .wp-core-ui .button-red:disabled,
64
+ .wp-core-ui .button-red-disabled {
65
+ color: #E79496 !important;
66
+ background: #BA292B !important;
67
+ border-color: #7F1C1F !important;
68
+ -webkit-box-shadow: none !important;
69
+ box-shadow: none !important;
70
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.1) !important;
71
+ cursor: default;
72
+ }
media-cleaner.js ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Plugin Name: Media Cleaner
3
+ Description: Clean your Media Library and Uploads Folder.
4
+ Author: Jordy Meow
5
+ */
6
+
7
+ function wpmc_pop_array(items, count) {
8
+ var newItems = [];
9
+ while ( newItems.length < count && items.length > 0 ) {
10
+ newItems.push( items.pop() );
11
+ }
12
+ return newItems;
13
+ }
14
+
15
+ /**
16
+ *
17
+ * RECOVER
18
+ *
19
+ */
20
+
21
+ function wpmc_recover() {
22
+ var items = [];
23
+ jQuery('#wpmc-table input:checked').each(function (index) {
24
+ if (jQuery(this)[0].value != 'on') {
25
+ items.push(jQuery(this)[0].value);
26
+ }
27
+ });
28
+ wpmc_recover_do(items, items.length);
29
+ }
30
+
31
+ function wpmc_recover_all() {
32
+ var items = [];
33
+ var data = { action: 'wpmc_get_all_deleted' };
34
+ jQuery.post(ajaxurl, data, function (response) {
35
+ reply = jQuery.parseJSON(response);
36
+ if ( !reply.success ) {
37
+ alert( reply.message );
38
+ return;
39
+ }
40
+ wpmc_recover_do(reply.results.ids, reply.results.ids.length);
41
+ });
42
+ }
43
+
44
+ function wpmc_recover_do(items, totalcount) {
45
+ wpmc_update_progress(totalcount - items.length, totalcount);
46
+ if (items.length > 0) {
47
+ newItems = wpmc_pop_array(items, 5);
48
+ data = { action: 'wpmc_recover_do', data: newItems };
49
+ }
50
+ else {
51
+ jQuery('#wpmc_progression').html("Done. Please <a href='?page=media-cleaner'>refresh</a> this page.");
52
+ return;
53
+ }
54
+ jQuery.post(ajaxurl, data, function (response) {
55
+ reply = jQuery.parseJSON(response);
56
+ if ( !reply.success ) {
57
+ alert( reply.message );
58
+ return;
59
+ }
60
+ wpmc_recover_do(items, totalcount);
61
+ });
62
+ }
63
+
64
+ /**
65
+ *
66
+ * DELETE
67
+ *
68
+ */
69
+
70
+ function wpmc_ignore() {
71
+ var items = [];
72
+ jQuery('#wpmc-table input:checked').each(function (index) {
73
+ if (jQuery(this)[0].value != 'on') {
74
+ items.push(jQuery(this)[0].value);
75
+ }
76
+ });
77
+ wpmc_ignore_do(items, items.length);
78
+ }
79
+
80
+ function wpmc_delete() {
81
+ var items = [];
82
+ jQuery('#wpmc-table input:checked').each(function (index) {
83
+ if (jQuery(this)[0].value != 'on') {
84
+ items.push(jQuery(this)[0].value);
85
+ }
86
+ });
87
+ wpmc_delete_do(items, items.length);
88
+ }
89
+
90
+ function wpmc_delete_all(isTrash) {
91
+ var items = [];
92
+ var data = { action: 'wpmc_get_all_issues', isTrash: isTrash ? 1 : 0 };
93
+ jQuery.post(ajaxurl, data, function (response) {
94
+ reply = jQuery.parseJSON(response);
95
+ if ( !reply.success ) {
96
+ alert( reply.message );
97
+ return;
98
+ }
99
+ wpmc_delete_do(reply.results.ids, reply.results.ids.length);
100
+ });
101
+ }
102
+
103
+ function wpmc_update_progress(current, totalcount) {
104
+ jQuery('#wpmc_progression').html('<span class="dashicons dashicons-controls-play"></span> Analyzing ' + current + "/" + totalcount + " (" + Math.round(current / totalcount * 100) + "%)");
105
+ }
106
+
107
+ function wpmc_delete_do(items, totalcount) {
108
+ wpmc_update_progress(totalcount - items.length, totalcount);
109
+ if (items.length > 0) {
110
+ newItems = wpmc_pop_array(items, 5);
111
+ data = { action: 'wpmc_delete_do', data: newItems };
112
+ }
113
+ else {
114
+ jQuery('#wpmc_progression').html("Done. Please <a href='?page=media-cleaner'>refresh</a> this page.");
115
+ return;
116
+ }
117
+ jQuery.post(ajaxurl, data, function (response) {
118
+ reply = jQuery.parseJSON(response);
119
+ if ( !reply.success ) {
120
+ alert( reply.message );
121
+ return;
122
+ }
123
+ wpmc_delete_do(items, totalcount);
124
+ });
125
+ }
126
+
127
+ function wpmc_ignore_do(items, totalcount) {
128
+ wpmc_update_progress(totalcount - items.length, totalcount);
129
+ if (items.length > 0) {
130
+ newItems = wpmc_pop_array(items, 5);
131
+ data = { action: 'wpmc_ignore_do', data: newItems };
132
+ }
133
+ else {
134
+ jQuery('#wpmc_progression').html("Done. Please <a href='?page=media-cleaner'>refresh</a> this page.");
135
+ return;
136
+ }
137
+ jQuery.post(ajaxurl, data, function (response) {
138
+ reply = jQuery.parseJSON(response);
139
+ if ( !reply.success ) {
140
+ alert( reply.message );
141
+ return;
142
+ }
143
+ wpmc_ignore_do(items, totalcount);
144
+ });
145
+ }
146
+
147
+ /**
148
+ *
149
+ * SCAN
150
+ *
151
+ */
152
+
153
+ var wpmc = {
154
+ dirs: [],
155
+ files: [],
156
+ medias: [],
157
+ total: 0,
158
+ issues: 0
159
+ };
160
+
161
+ // WPMC GET INITIAL INFO
162
+
163
+ function wpmc_scan_type_finished() {
164
+
165
+ }
166
+
167
+ function wpmc_scan_type_next(type, path) {
168
+
169
+ }
170
+
171
+ function wpmc_scan_type(type, path = null, limit = 0) {
172
+ var data = { action: 'wpmc_scan', medias: type === 'medias', files: type === 'files', path: path, limit: limit };
173
+ if (path) {
174
+ elpath = path.replace(/^.*[\\\/]/, '');
175
+ jQuery('#wpmc_progression').html('<span class="dashicons dashicons-portfolio"></span> Preparing files (' + elpath + ')...');
176
+ }
177
+ else if (type === 'medias')
178
+ jQuery('#wpmc_progression').html('<span class="dashicons dashicons-admin-media"></span> Preparing medias (' + limit + ' media)....');
179
+ else
180
+ jQuery('#wpmc_progression').html('<span class="dashicons dashicons-portfolio"></span> Preparing files...');
181
+
182
+
183
+ jQuery.post(ajaxurl, data, function (response) {
184
+ reply = jQuery.parseJSON(response);
185
+ if ( !reply.success ) {
186
+ alert( reply.message );
187
+ return;
188
+ }
189
+
190
+ // Store results
191
+ for (var i = 0, len = reply.results.length; i < len; i++) {
192
+ var r = reply.results[i];
193
+ if (type === 'files') {
194
+ if ( r.type === 'dir' )
195
+ wpmc.dirs.push( r.path );
196
+ else if ( r.type === 'file' ) {
197
+ wpmc.files.push( r.path );
198
+ wpmc.total++;
199
+ }
200
+ }
201
+ else if (type === 'medias') {
202
+ wpmc.medias.push( r );
203
+ wpmc.total++;
204
+ }
205
+ }
206
+
207
+ // Next query
208
+ if (type === 'medias') {
209
+ if (wpmc_cfg.scanFiles || !reply.finished)
210
+ return wpmc_scan_type('medias', null, reply.limit);
211
+ else
212
+ return wpmc_scan_do();
213
+ }
214
+ else if (type === 'files') {
215
+ var dir = wpmc.dirs.pop();
216
+ if (dir)
217
+ return wpmc_scan_type('files', dir);
218
+ else
219
+ return wpmc_scan_do();
220
+ }
221
+ });
222
+ }
223
+
224
+ function wpmc_scan() {
225
+ wpmc = { dirs: [], files: [], medias: [], total: 0, issues: 0 };
226
+ if (wpmc_cfg.scanMedia)
227
+ wpmc_scan_type('medias', null);
228
+ else if (wpmc_cfg.scanFiles)
229
+ wpmc_scan_type('files', null);
230
+ }
231
+
232
+ function wpmc_scan_do() {
233
+ wpmc_update_progress(wpmc.total - (wpmc.files.length + wpmc.medias.length), wpmc.total);
234
+ var data = {};
235
+ var expectedSuccess = 0;
236
+ if (wpmc.files.length > 0) {
237
+ newFiles = wpmc_pop_array(wpmc.files, 5);
238
+ expectedSuccess = newFiles.length;
239
+ data = { action: 'wpmc_scan_do', type: 'file', data: newFiles };
240
+ }
241
+ else if (wpmc.medias.length > 0) {
242
+ newMedias = wpmc_pop_array(wpmc.medias, 5);
243
+ expectedSuccess = newMedias.length;
244
+ data = { action: 'wpmc_scan_do', type: 'media', data: newMedias };
245
+ }
246
+ else {
247
+ jQuery('#wpmc_progression').html(wpmc.issues + " issue(s) found. <a href='?page=media-cleaner'></span>Refresh</a>.");
248
+ return;
249
+ }
250
+ jQuery.post(ajaxurl, data, function (response) {
251
+ try {
252
+ reply = jQuery.parseJSON(response);
253
+ }
254
+ catch (e) {
255
+ reply = null;
256
+ }
257
+ if (!reply) {
258
+ reply = { success: false, message: "The reply from the server is broken. The reply will be displayed in your Javascript console. You should also check your PHP Error Logs." };
259
+ console.debug( "Media File Cleaner got this reply from the server: " + response);
260
+ }
261
+ if ( !reply.success ) {
262
+ alert( reply.message );
263
+ }
264
+ if (reply.result) {
265
+ wpmc.issues += expectedSuccess - reply.result.success;
266
+ }
267
+ wpmc_scan_do();
268
+ });
269
+ }
270
+
271
+ /**
272
+ *
273
+ * INIT
274
+ *
275
+ */
276
+
277
+ jQuery('#wpmc-cb-select-all').on('change', function (cb) {
278
+ jQuery('#wpmc-table input').prop('checked', cb.target.checked);
279
+ });
media-cleaner.php ADDED
@@ -0,0 +1,1064 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: 3.6.8
7
+ Author: Jordy Meow
8
+ Author URI: http://meowapps.com
9
+ Text Domain: media-cleaner
10
+ Domain Path: /languages
11
+
12
+ Big thanks to Matt (http://www.twistedtek.net/) for all his
13
+ contributions made to the plugin.
14
+
15
+ Originally developed for two of my websites:
16
+ - Jordy Meow (http://jordymeow.com)
17
+ - Haikyo (http://www.haikyo.org)
18
+ */
19
+
20
+ add_action( 'admin_notices', 'wpmc_admin_notices' );
21
+ add_action( 'admin_menu', 'wpmc_admin_menu' );
22
+ add_action( 'admin_enqueue_scripts', 'wpmc_wp_enqueue_scripts' );
23
+ add_action( 'admin_print_scripts', 'wpmc_admin_inline_js' );
24
+ add_action( 'wp_ajax_wpmc_scan', 'wpmc_wp_ajax_wpmc_scan' );
25
+ add_action( 'wp_ajax_wpmc_get_all_issues', 'wpmc_wp_ajax_wpmc_get_all_issues' );
26
+ add_action( 'wp_ajax_wpmc_get_all_deleted', 'wpmc_wp_ajax_wpmc_get_all_deleted' );
27
+ add_action( 'wp_ajax_wpmc_scan_do', 'wpmc_wp_ajax_wpmc_scan_do' );
28
+ add_action( 'wp_ajax_wpmc_delete_do', 'wpmc_wp_ajax_wpmc_delete_do' );
29
+ add_action( 'wp_ajax_wpmc_ignore_do', 'wpmc_wp_ajax_wpmc_ignore_do' );
30
+ add_action( 'wp_ajax_wpmc_recover_do', 'wpmc_wp_ajax_wpmc_recover_do' );
31
+ add_filter( 'media_row_actions', 'wpmc_media_row_actions', 10, 2 );
32
+
33
+ register_activation_hook( __FILE__, 'wpmc_activate' );
34
+ register_uninstall_hook( __FILE__, 'wpmc_uninstall' );
35
+
36
+ require( 'wpmc_admin.php' );
37
+
38
+ global $wpmc_admin, $wpmc_debug, $disable_meowapps,
39
+ $wpmc_exclude_dir, $wpmc_version;
40
+ $wpmc_version = '3.6.8';
41
+ $wpmc_debug = false;
42
+ $disable_meowapps = false;
43
+ $wpmc_admin = new Meow_MediaCleaner_Admin();
44
+ $wpmc_exclude_dir = array( ".", "..", "wpmc-trash", ".htaccess",
45
+ "ptetmp", "profiles", "sites", "bws_captcha_images",
46
+ "woocommerce_uploads", "wc-logs" );
47
+
48
+ /*******************************************************************************
49
+ * ASYNCHRONOUS AJAX FUNCTIONS
50
+ ******************************************************************************/
51
+
52
+ function wpmc_wp_ajax_wpmc_delete_do () {
53
+ ob_start();
54
+ $data = $_POST['data'];
55
+ $success = 0;
56
+ foreach ( $data as $piece ) {
57
+ $success += ( wpmc_delete( $piece ) ? 1 : 0 );
58
+ }
59
+ ob_end_clean();
60
+ echo json_encode(
61
+ array(
62
+ 'success' => true,
63
+ 'result' => array( 'data' => $data, 'success' => $success ),
64
+ 'message' => __( "Status unknown.", 'media-cleaner' )
65
+ )
66
+ );
67
+ die();
68
+ }
69
+
70
+ function wpmc_wp_ajax_wpmc_ignore_do () {
71
+ ob_start();
72
+ $data = $_POST['data'];
73
+ $success = 0;
74
+ foreach ( $data as $piece ) {
75
+ $success += ( wpmc_ignore( $piece ) ? 1 : 0 );
76
+ }
77
+ ob_end_clean();
78
+ echo json_encode(
79
+ array(
80
+ 'success' => true,
81
+ 'result' => array( 'data' => $data, 'success' => $success ),
82
+ 'message' => __( "Status unknown.", 'media-cleaner' )
83
+ )
84
+ );
85
+ die();
86
+ }
87
+
88
+ function wpmc_wp_ajax_wpmc_recover_do () {
89
+ ob_start();
90
+ $data = $_POST['data'];
91
+ $success = 0;
92
+ foreach ( $data as $piece ) {
93
+ $success += ( wpmc_recover( $piece ) ? 1 : 0 );
94
+ }
95
+ ob_end_clean();
96
+ echo json_encode(
97
+ array(
98
+ 'success' => true,
99
+ 'result' => array( 'data' => $data, 'success' => $success ),
100
+ 'message' => __( "Status unknown.", 'media-cleaner' )
101
+ )
102
+ );
103
+ die();
104
+ }
105
+
106
+ function wpmc_wp_ajax_wpmc_scan_do () {
107
+ global $wpmc_debug;
108
+ ob_start();
109
+ $type = $_POST['type'];
110
+ $data = $_POST['data'];
111
+ $success = 0;
112
+ foreach ( $data as $piece ) {
113
+ if ( $type == 'file' ) {
114
+ if ( $wpmc_debug )
115
+ error_log( "Check File: {$piece}" );
116
+ $success += ( wpmc_check_file( $piece ) ? 1 : 0 );
117
+ if ( $wpmc_debug )
118
+ error_log( "Success " . $success . "\n" );
119
+ } elseif ( $type == 'media' ) {
120
+ if ( $wpmc_debug )
121
+ error_log( "Check Media: {$piece}" );
122
+ $success += ( wpmc_check_media( $piece ) ? 1 : 0 );
123
+ if ( $wpmc_debug )
124
+ error_log( "Success " . $success . "\n" );
125
+ }
126
+ }
127
+ ob_end_clean();
128
+ echo json_encode(
129
+ array(
130
+ 'success' => true,
131
+ 'result' => array( 'type' => $type, 'data' => $data, 'success' => $success ),
132
+ 'message' => __( "Items checked.", 'media-cleaner' )
133
+ )
134
+ );
135
+ die();
136
+ }
137
+
138
+ function wpmc_wp_ajax_wpmc_get_all_deleted () {
139
+ global $wpdb;
140
+ $table_name = $wpdb->prefix . "wpmcleaner";
141
+ $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
142
+ echo json_encode(
143
+ array(
144
+ 'results' => array( 'ids' => $ids ),
145
+ 'success' => true,
146
+ 'message' => __( "List generated.", 'media-cleaner' )
147
+ )
148
+ );
149
+ die;
150
+ }
151
+
152
+ function wpmc_wp_ajax_wpmc_get_all_issues () {
153
+ global $wpdb;
154
+ $isTrash = ( isset( $_POST['isTrash'] ) && $_POST['isTrash'] == 1 ) ? true : false;
155
+ $table_name = $wpdb->prefix . "wpmcleaner";
156
+ if ( $isTrash )
157
+ $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
158
+ else
159
+ $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 0" );
160
+ echo json_encode(
161
+ array(
162
+ 'results' => array( 'ids' => $ids ),
163
+ 'success' => true,
164
+ 'message' => __( "List generated.", 'media-cleaner' )
165
+ )
166
+ );
167
+ die;
168
+ }
169
+
170
+ function wpmc_get_galleries_images( $force = false ) {
171
+ if ( $force ) {
172
+ delete_transient( "wpmc_galleries_images" );
173
+ $galleries_images = null;
174
+ }
175
+ else {
176
+ $galleries_images = get_transient("wpmc_galleries_images");
177
+ }
178
+ if ( !$galleries_images ) {
179
+ global $wpdb;
180
+ $galleries_images = array();
181
+ $posts = $wpdb->get_col( "SELECT id FROM $wpdb->posts WHERE post_type != 'attachment' AND post_status != 'inherit'" );
182
+ foreach( $posts as $post ) {
183
+ $galleries = get_post_galleries_images( $post );
184
+ foreach( $galleries as $gallery ) {
185
+ foreach( $gallery as $image ) {
186
+ array_push( $galleries_images, $image );
187
+ }
188
+ }
189
+ }
190
+
191
+ $post_galleries = get_posts( array(
192
+ 'tax_query' => array(
193
+ array(
194
+ 'taxonomy' => 'post_format',
195
+ 'field' => 'slug',
196
+ 'terms' => array( 'post-format-gallery' ),
197
+ 'operator' => 'IN'
198
+ )
199
+ )
200
+ ) );
201
+
202
+ foreach( (array) $post_galleries as $gallery_post ) {
203
+ $arrImages = get_children( 'post_type=attachment&post_mime_type=image&post_parent=' . $gallery_post->ID );
204
+ if ( $arrImages ) {
205
+ foreach( (array) $arrImages as $image_post ) {
206
+ array_push( $galleries_images, $image_post->guid );
207
+ }
208
+ }
209
+ }
210
+ wp_reset_postdata();
211
+
212
+ set_transient( "wpmc_galleries_images", $galleries_images, 60 * 60 * 2 );
213
+ }
214
+ return $galleries_images;
215
+ }
216
+
217
+ function wpmc_wp_ajax_wpmc_scan() {
218
+ global $wpdb;
219
+ global $wpmc_admin;
220
+
221
+ $method = get_option( 'wpmc_method', 'media' );
222
+ if ( !$wpmc_admin->is_registered() )
223
+ $method = 'media';
224
+ $path = isset( $_POST['path'] ) ? $_POST['path'] : null;
225
+ $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
226
+ $limitsize = 100;
227
+ $upload_folder = wp_upload_dir();
228
+
229
+ if ( ( $method == 'media' && empty( $limit ) ) || ( $method == 'files' && empty( $path ) ) ) {
230
+ // Reset and prepare all the Attachment IDs of all the galleries
231
+ wpmc_reset_issues();
232
+ delete_transient( 'wpmc_posts_with_shortcode' );
233
+ wpmc_get_galleries_images( true );
234
+ }
235
+
236
+ if ( $method == 'files' ) {
237
+ $files = wpmc_list_uploaded_files( $path ? ( trailingslashit( $upload_folder['basedir'] ) . $path ) : $upload_folder['basedir'] );
238
+ echo json_encode(
239
+ array(
240
+ 'results' => $files, 'success' => true, 'message' => __( "Files retrieved.", 'media-cleaner' )
241
+ )
242
+ );
243
+ die();
244
+ }
245
+
246
+ if ( $method == 'media' ) {
247
+ // Prevent double scanning by removing filesystem entries that we have DB entries for
248
+ $results = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
249
+ WHERE p.post_status = 'inherit'
250
+ AND p.post_type = 'attachment'
251
+ LIMIT %d, %d", $limit, $limitsize
252
+ )
253
+ );
254
+ $finished = count( $results ) < $limitsize;
255
+ echo json_encode(
256
+ array(
257
+ 'results' => $results,
258
+ 'success' => true,
259
+ 'finished' => $finished,
260
+ 'limit' => $limit + $limitsize,
261
+ 'message' => __( "Medias retrieved.", 'media-cleaner' ) )
262
+ );
263
+ die();
264
+ }
265
+
266
+ // No task.
267
+ echo json_encode( array( 'success' => false, 'message' => __( "No task.", 'media-cleaner' ) ) );
268
+ die();
269
+ }
270
+
271
+ /**
272
+ *
273
+ * HELPERS
274
+ *
275
+ */
276
+
277
+ function wpmc_trashdir() {
278
+ $upload_folder = wp_upload_dir();
279
+ return trailingslashit( $upload_folder['basedir'] ) . 'wpmc-trash';
280
+ }
281
+
282
+ /**
283
+ *
284
+ * DELETE / SCANNING / RESET
285
+ *
286
+ */
287
+
288
+ function wpmc_recover_file( $path ) {
289
+ $basedir = wp_upload_dir();
290
+ $originalPath = trailingslashit( $basedir['basedir'] ) . $path;
291
+ $trashPath = trailingslashit( wpmc_trashdir() ) . $path;
292
+ $path_parts = pathinfo( $originalPath );
293
+ if ( !file_exists( $path_parts['dirname'] ) && !wp_mkdir_p( $path_parts['dirname'] ) ) {
294
+ die( 'Failed to create folder.' );
295
+ }
296
+ if ( !file_exists( $trashPath ) ) {
297
+ global $wpmc_debug;
298
+ if ( $wpmc_debug )
299
+ error_log( "The file $originalPath actually does not exist in the trash." );
300
+ return true;
301
+ }
302
+ if ( !rename( $trashPath, $originalPath ) ) {
303
+ die( 'Failed to move the file.' );
304
+ }
305
+ return true;
306
+ }
307
+
308
+ function wpmc_recover( $id ) {
309
+ global $wpdb;
310
+ $table_name = $wpdb->prefix . "wpmcleaner";
311
+ $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
312
+ $issue->path = stripslashes( $issue->path );
313
+
314
+ // Files
315
+ if ( $issue->type == 0 ) {
316
+ wpmc_recover_file( $issue->path );
317
+ $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 0 WHERE id = %d", $id ) );
318
+ return true;
319
+ }
320
+ // Media
321
+ else if ( $issue->type == 1 ) {
322
+
323
+ // Copy the main file back
324
+ $fullpath = get_attached_file( $issue->postId );
325
+ $mainfile = wpmc_clean_uploaded_filename( $fullpath );
326
+ $baseUp = pathinfo( $mainfile );
327
+ $baseUp = $baseUp['dirname'];
328
+ $file = wpmc_clean_uploaded_filename( $fullpath );
329
+ if ( !wpmc_recover_file( $file ) )
330
+ error_log( "Could not recover $file." );
331
+
332
+ // If images, copy the other files as well
333
+ $meta = wp_get_attachment_metadata( $issue->postId );
334
+ $isImage = isset( $meta, $meta['width'], $meta['height'] );
335
+ $sizes = wpmc_get_image_sizes();
336
+ if ( $isImage && isset( $meta['sizes'] ) ) {
337
+ foreach ( $meta['sizes'] as $name => $attr ) {
338
+ if ( isset( $attr['file'] ) ) {
339
+ $filepath = wp_upload_dir();
340
+ $filepath = $filepath['basedir'];
341
+ $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
342
+ $file = wpmc_clean_uploaded_filename( $filepath );
343
+ if ( !wpmc_recover_file( $file ) )
344
+ error_log( "Could not recover $file." );
345
+ }
346
+ }
347
+ }
348
+ if ( !wp_untrash_post( $issue->postId ) )
349
+ die( "Failed to untrash Media {$issue->postId}." );
350
+ $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 0 WHERE id = %d", $id ) );
351
+ return true;
352
+ }
353
+ }
354
+
355
+ function wpmc_trash_file( $fileIssuePath ) {
356
+ global $wpdb;
357
+ $basedir = wp_upload_dir();
358
+ $originalPath = trailingslashit( $basedir['basedir'] ) . $fileIssuePath;
359
+ $trashPath = trailingslashit( wpmc_trashdir() ) . $fileIssuePath;
360
+ $path_parts = pathinfo( $trashPath );
361
+
362
+ try {
363
+ if ( !file_exists( $path_parts['dirname'] ) && !wp_mkdir_p( $path_parts['dirname'] ) ) {
364
+ return false;
365
+ }
366
+ // Rename the file (move). 'is_dir' is just there for security (no way we should move a whole directory)
367
+ if ( is_dir( $originalPath ) ) {
368
+ error_log( "Attempted to delete a directory instead of a file ($originalPath). Can't do that." );
369
+ return false;
370
+ }
371
+ if ( !file_exists( $originalPath ) ) {
372
+ global $wpmc_debug;
373
+ if ( $wpmc_debug )
374
+ error_log( "The file $originalPath actually does not exist." );
375
+ return true;
376
+ }
377
+ if ( !rename( $originalPath, $trashPath ) ) {
378
+ return false;
379
+ }
380
+ }
381
+ catch ( Exception $e ) {
382
+ return false;
383
+ }
384
+ wpmc_clean_dir( dirname( $originalPath ) );
385
+ return true;
386
+ }
387
+
388
+ function wpmc_ignore( $id ) {
389
+ global $wpdb;
390
+ $table_name = $wpdb->prefix . "wpmcleaner";
391
+ $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET ignored = 1 WHERE id = %d", $id ) );
392
+ return true;
393
+ }
394
+
395
+ function wpmc_endsWith( $haystack, $needle )
396
+ {
397
+ $length = strlen( $needle );
398
+ if ( $length == 0 )
399
+ return true;
400
+ return ( substr( $haystack, -$length ) === $needle );
401
+ }
402
+
403
+ function wpmc_clean_dir( $dir ) {
404
+ if ( !file_exists( $dir ) )
405
+ return;
406
+ else if ( wpmc_endsWith( $dir, 'uploads' ) )
407
+ return;
408
+ $found = array_diff( scandir( $dir ), array( '.', '..' ) );
409
+ if ( count( $found ) < 1 ) {
410
+ if ( rmdir( $dir ) ) {
411
+ wpmc_clean_dir( dirname( $dir ) );
412
+ }
413
+ }
414
+ }
415
+
416
+ function wpmc_delete( $id ) {
417
+ global $wpdb;
418
+ $table_name = $wpdb->prefix . "wpmcleaner";
419
+ $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
420
+ $regex = "^(.*)(\\s\\(\\+.*)$";
421
+ $issue->path = preg_replace('/'.$regex.'/i', '$1', $issue->path); // remove " (+ 6 files)" from path
422
+
423
+ // Make sure there isn't a media DB entry
424
+ if ( $issue->type == 0 ) {
425
+ $attachmentid = wpmc_find_attachment_id_by_file( $issue->path );
426
+ if ( $attachmentid ) {
427
+ error_log( "File Cleaner: Issue listed as filesystem but Media {$attachmentid} exists." );
428
+ }
429
+ }
430
+
431
+ if ( $issue->type == 0 ) {
432
+
433
+ if ( $issue->deleted == 0 ) {
434
+ // Move file to the trash
435
+ if ( wpmc_trash_file( $issue->path ) )
436
+ $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
437
+ return true;
438
+ }
439
+ else {
440
+ // Delete file from the trash
441
+ $trashPath = trailingslashit( wpmc_trashdir() ) . $issue->path;
442
+ if ( !unlink( $trashPath ) )
443
+ error_log( 'Failed to delete the file.' );
444
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
445
+ wpmc_clean_dir( dirname( $trashPath ) );
446
+ return true;
447
+ }
448
+ }
449
+
450
+ if ( $issue->type == 1 ) {
451
+ if ( $issue->deleted == 0 && MEDIA_TRASH ) {
452
+ // Move Media to trash
453
+ // Let's copy the images to the trash so that it can be recovered.
454
+ $fullpath = get_attached_file( $issue->postId );
455
+ $mainfile = wpmc_clean_uploaded_filename( $fullpath );
456
+ $baseUp = pathinfo( $mainfile );
457
+ $baseUp = $baseUp['dirname'];
458
+ $file = wpmc_clean_uploaded_filename( $fullpath );
459
+ if ( !wpmc_trash_file( $file ) )
460
+ error_log( "Could not trash $file." );
461
+
462
+ // If images, check the other files as well
463
+ $meta = wp_get_attachment_metadata( $issue->postId );
464
+ $isImage = isset( $meta, $meta['width'], $meta['height'] );
465
+ $sizes = wpmc_get_image_sizes();
466
+ if ( $isImage && isset( $meta['sizes'] ) ) {
467
+ foreach ( $meta['sizes'] as $name => $attr ) {
468
+ if ( isset( $attr['file'] ) ) {
469
+ $filepath = wp_upload_dir();
470
+ $filepath = $filepath['basedir'];
471
+ $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
472
+ $file = wpmc_clean_uploaded_filename( $filepath );
473
+ if ( !wpmc_trash_file( $file ) )
474
+ error_log( "Could not trash $file." );
475
+ }
476
+ }
477
+ }
478
+ wp_delete_attachment( $issue->postId, false );
479
+ $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
480
+ return true;
481
+ }
482
+ else {
483
+ // Trash Media definitely by recovering it (to be like a normal Media) and remove it through the
484
+ // standard WordPress workflow
485
+ if ( MEDIA_TRASH )
486
+ wpmc_recover( $id );
487
+ wp_delete_attachment( $issue->postId, true );
488
+ $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
489
+ return true;
490
+ }
491
+ }
492
+ return false;
493
+ }
494
+
495
+ /**
496
+ *
497
+ * SCANNING / RESET
498
+ *
499
+ */
500
+
501
+ function wpmc_check_is_ignore( $file ) {
502
+ global $wpdb, $wpmc_debug;
503
+ $table_name = $wpdb->prefix . "wpmcleaner";
504
+ $count = $wpdb->get_var( "SELECT COUNT(*)
505
+ FROM $table_name
506
+ WHERE deleted = 0
507
+ AND path LIKE '%". esc_sql( $wpdb->esc_like( $file ) ) . "%'" );
508
+ if ( $wpmc_debug && $count > 0 )
509
+ error_log("{$file} found in IGNORE");
510
+ return ($count > 0);
511
+ }
512
+
513
+
514
+
515
+ function wpmc_find_attachment_id_by_file ($file) {
516
+ global $wpdb, $wpmc_debug;
517
+ $postmeta_table_name = $wpdb->prefix . 'postmeta';
518
+ $file = wpmc_clean_uploaded_filename( $file );
519
+ $sql = $wpdb->prepare( "SELECT post_id
520
+ FROM {$postmeta_table_name}
521
+ WHERE meta_key = '_wp_attached_file'
522
+ AND meta_value = %s", $file
523
+ );
524
+ $ret = $wpdb->get_var( $sql );
525
+ if ( $wpmc_debug && empty( $ret ) )
526
+ error_log( "File $file not found as _wp_attached_file (Library)." );
527
+ else if ( $wpmc_debug ) {
528
+ error_log( "File $file found as Media $ret." );
529
+ }
530
+ return $ret;
531
+ }
532
+
533
+ function wpmc_get_image_sizes() {
534
+ $sizes = array();
535
+ global $_wp_additional_image_sizes;
536
+ foreach ( get_intermediate_image_sizes() as $s ) {
537
+ $crop = false;
538
+ if ( isset( $_wp_additional_image_sizes[$s] ) ) {
539
+ $width = intval( $_wp_additional_image_sizes[$s]['width'] );
540
+ $height = intval( $_wp_additional_image_sizes[$s]['height'] );
541
+ $crop = $_wp_additional_image_sizes[$s]['crop'];
542
+ } else {
543
+ $width = get_option( $s.'_size_w' );
544
+ $height = get_option( $s.'_size_h' );
545
+ $crop = get_option( $s.'_crop' );
546
+ }
547
+ $sizes[$s] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
548
+ }
549
+ return $sizes;
550
+ }
551
+
552
+
553
+ // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
554
+ function wpmc_clean_uploaded_filename( $fullpath ) {
555
+ $upload_folder = wp_upload_dir();
556
+ $basedir = $upload_folder['basedir'];
557
+ $file = str_replace( $basedir, '', $fullpath );
558
+ $file = trim( $file, "/" );
559
+ return $file;
560
+ }
561
+
562
+ function wpmc_check_media( $attachmentId ) {
563
+
564
+ // Is it an image?
565
+ $meta = wp_get_attachment_metadata( $attachmentId );
566
+ $isImage = isset( $meta, $meta['width'], $meta['height'] );
567
+
568
+ // Get the main file
569
+ global $wpdb, $wpmc_debug;
570
+ $fullpath = get_attached_file( $attachmentId );
571
+ $mainfile = wpmc_clean_uploaded_filename( $fullpath );
572
+ $baseUp = pathinfo( $mainfile );
573
+ $baseUp = $baseUp['dirname'];
574
+ $size = 0;
575
+ $countfiles = 0;
576
+ $issue = 'NO_CONTENT';
577
+ if ( file_exists( $fullpath ) ) {
578
+ $size = filesize( $fullpath );
579
+
580
+ if ( wpmc_check_is_ignore( $mainfile )
581
+ || wpmc_check_db_has_background_or_header( $mainfile )
582
+ || wpmc_check_db_has_content( $mainfile, $attachmentId )
583
+ || wpmc_check_in_gallery( $mainfile )
584
+ || wpmc_check_db_has_meta( $mainfile, $attachmentId ) )
585
+ return true;
586
+
587
+ // If images, check the other files as well
588
+ $countfiles = 0;
589
+ $sizes = wpmc_get_image_sizes();
590
+ if ( $isImage && isset( $meta['sizes'] ) ) {
591
+ foreach ( $meta['sizes'] as $name => $attr ) {
592
+ if ( isset( $attr['file'] ) ) {
593
+ $filepath = wp_upload_dir();
594
+ $filepath = $filepath['basedir'];
595
+ $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
596
+ if ( file_exists( $filepath ) ) {
597
+ $size += filesize( $filepath );
598
+ }
599
+ $file = wpmc_clean_uploaded_filename( $attr['file'] );
600
+ $countfiles++;
601
+ if ($wpmc_debug) error_log("checking MEDIA-IMAGE {$filepath}");
602
+ if ( wpmc_check_in_gallery( $filepath )
603
+ || wpmc_check_db_has_background_or_header( $filepath )
604
+ || wpmc_check_db_has_meta( $filepath, $attachmentId ) )
605
+ return true;
606
+ }
607
+ }
608
+ }
609
+ } else {
610
+ $issue = 'ORPHAN_MEDIA';
611
+ }
612
+
613
+ $table_name = $wpdb->prefix . "wpmcleaner";
614
+ $wpdb->insert( $table_name,
615
+ array(
616
+ 'time' => current_time('mysql'),
617
+ 'type' => 1,
618
+ 'size' => $size,
619
+ 'path' => $mainfile . ( $countfiles > 0 ? ( " (+ " . $countfiles . " files)" ) : "" ),
620
+ 'postId' => $attachmentId,
621
+ 'issue' => $issue
622
+ )
623
+ );
624
+ return false;
625
+ }
626
+
627
+ // Delete all issues
628
+ function wpmc_reset_issues( $includingIgnored = false ) {
629
+ global $wpdb;
630
+ $table_name = $wpdb->prefix . "wpmcleaner";
631
+ if ( $includingIgnored ) {
632
+ $wpdb->query( "DELETE FROM $table_name WHERE deleted = 0" );
633
+ }
634
+ else {
635
+ $wpdb->query( "DELETE FROM $table_name WHERE ignored = 0 AND deleted = 0" );
636
+ }
637
+ }
638
+
639
+ /**
640
+ *
641
+ * DASHBOARD
642
+ *
643
+ */
644
+
645
+ function wpmc_admin_inline_js() {
646
+ global $wpmc_admin;
647
+ echo "<script type='text/javascript'>\n";
648
+ echo 'var wpmc_cfg = { isPro: ' . ( $wpmc_admin->is_registered() ? '1' : '0') . ', scanFiles: ' . ( ( get_option( 'wpmc_method', 'media' ) == 'files' && $wpmc_admin->is_registered() ) ? '1' : '0' ) . ', scanMedia: ' . ( get_option( 'wpmc_method', 'media' ) == 'media' ? '1' : '0' ) . ' };';
649
+ echo "\n</script>";
650
+ }
651
+
652
+ function echo_issue( $issue ) {
653
+ if ( $issue == 'NO_CONTENT' ) {
654
+ _e( "Seems not in use.", 'media-cleaner' );
655
+ }
656
+ else if ( $issue == 'NO_MEDIA' ) {
657
+ _e( "Not in Media Library.", 'media-cleaner' );
658
+ }
659
+ else if ( $issue == 'ORPHAN_RETINA' ) {
660
+ _e( "Orphan retina.", 'media-cleaner' );
661
+ }
662
+ else if ( $issue == 'ORPHAN_MEDIA' ) {
663
+ _e( "File not found.", 'media-cleaner' );
664
+ }
665
+ else {
666
+ echo $issue;
667
+ }
668
+ }
669
+
670
+ function wpmc_media_row_actions( $actions, $post ) {
671
+ global $current_screen;
672
+ if ( 'upload' != $current_screen->id )
673
+ return $actions;
674
+ global $wpdb;
675
+ $table_name = $wpdb->prefix . "wpmcleaner";
676
+ $res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE postId = %d", $post->ID ) );
677
+ if ( !empty( $res ) && isset( $actions['delete'] ) )
678
+ $actions['delete'] = "<a href='?page=media-cleaner&view=deleted'>Delete with Media Cleaner</a>";
679
+ if ( !empty( $res ) && isset( $actions['trash'] ) )
680
+ $actions['trash'] = "<a href='?page=media-cleaner'>Trash with Media Cleaner</a>";
681
+ if ( !empty( $res ) && isset( $actions['untrash'] ) ) {
682
+ $actions['untrash'] = "<a href='?page=media-cleaner&view=deleted'>Restore with Media Cleaner</a>";
683
+ }
684
+ return $actions;
685
+ }
686
+
687
+ function wpmc_screen() {
688
+ global $wpmc_admin;
689
+ global $wplr;
690
+ ?>
691
+ <div class='wrap'>
692
+
693
+ <?php
694
+ echo $wpmc_admin->display_title( "Media Cleaner" );
695
+ global $wpdb;
696
+ $posts_per_page = get_user_meta( get_current_user_id(), 'upload_per_page', true );
697
+ if ( empty( $posts_per_page ) )
698
+ $posts_per_page = 20;
699
+ $view = isset ( $_GET[ 'view' ] ) ? sanitize_text_field( $_GET[ 'view' ] ) : "issues";
700
+ $paged = isset ( $_GET[ 'paged' ] ) ? sanitize_text_field( $_GET[ 'paged' ] ) : 1;
701
+ $reset = isset ( $_GET[ 'reset' ] ) ? $_GET[ 'reset' ] : 0;
702
+ if ( $reset ) {
703
+ wpmc_reset();
704
+ }
705
+ $s = isset ( $_GET[ 's' ] ) ? sanitize_text_field( $_GET[ 's' ] ) : null;
706
+ $table_name = $wpdb->prefix . "wpmcleaner";
707
+ $issues_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
708
+ $total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
709
+ $trash_total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 1" );
710
+ $ignored_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 1" );
711
+ $deleted_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE deleted = 1" );
712
+
713
+ if ( $view == 'deleted' ) {
714
+ $items_count = $deleted_count;
715
+ $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
716
+ FROM $table_name WHERE ignored = 0 AND deleted = 1 AND path LIKE %s
717
+ ORDER BY time
718
+ DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
719
+ }
720
+ else if ( $view == 'ignored' ) {
721
+ $items_count = $ignored_count;
722
+ $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
723
+ FROM $table_name
724
+ WHERE ignored = 1 AND deleted = 0 AND path LIKE %s
725
+ ORDER BY time
726
+ DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
727
+ }
728
+ else {
729
+ $items_count = $issues_count;
730
+ $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
731
+ FROM $table_name
732
+ WHERE ignored = 0 AND deleted = 0 AND path LIKE %s
733
+ ORDER BY time
734
+ DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
735
+ }
736
+ ?>
737
+
738
+ <style>
739
+ #wpmc-pages {
740
+ float: right;
741
+ position: relative;
742
+ top: 12px;
743
+ }
744
+
745
+ #wpmc-pages a {
746
+ text-decoration: none;
747
+ border: 1px solid black;
748
+ padding: 2px 5px;
749
+ border-radius: 4px;
750
+ background: #E9E9E9;
751
+ color: lightslategrey;
752
+ border-color: #BEBEBE;
753
+ }
754
+
755
+ #wpmc-pages .current {
756
+ font-weight: bold;
757
+ }
758
+ </style>
759
+
760
+ <div style='margin-top: 0px; background: #FFF; padding: 5px; border-radius: 4px; height: 28px; box-shadow: 0px 0px 6px #C2C2C2;'>
761
+
762
+ <!-- SCAN -->
763
+ <?php if ( $view != 'deleted' ) { ?>
764
+ <a id='wpmc_scan' onclick='wpmc_scan()' class='button-primary' style='float: left;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-search"></span><?php _e("Scan", 'media-cleaner'); ?></a>
765
+ <?php } ?>
766
+
767
+ <!-- DELETE SELECTED -->
768
+ <a id='wpmc_delete' onclick='wpmc_delete()' class='button' style='float: left; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-no"></span><?php _e("Delete", 'media-cleaner'); ?></a>
769
+ <?php if ( $view == 'deleted' ) { ?>
770
+ <a id='wpmc_recover' onclick='wpmc_recover()' class='button-secondary' style='float: left; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-controls-repeat"></span><?php _e( "Recover", 'media-cleaner' ); ?></a>
771
+ <?php } ?>
772
+
773
+ <!-- IGNORE SELECTED -->
774
+ <a id='wpmc_ignore' onclick='wpmc_ignore()' class='button' style='float: left; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-yes"></span><?php _e("Ignore", 'media-cleaner'); ?></a>
775
+
776
+ <!-- RESET -->
777
+ <?php if ( $view != 'deleted' ) { ?>
778
+ <a id='wpmc_reset' href='?page=media-cleaner&reset=1' class='button-primary' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-sos"></span><?php _e("Reset", 'media-cleaner'); ?></a>
779
+ <?php } ?>
780
+
781
+ <!-- DELETE ALL -->
782
+ <?php if ( $view == 'deleted' ) { ?>
783
+ <a id='wpmc_recover_all' onclick='wpmc_recover_all()' class='button-primary' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-controls-repeat"></span><?php _e("Recover all", 'media-cleaner'); ?></a>
784
+ <a id='wpmc_delete_all' onclick='wpmc_delete_all(true)' class='button button-red' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-trash"></span><?php _e("Empty trash", 'media-cleaner'); ?></a>
785
+ <?php } else { ?>
786
+ <a id='wpmc_delete_all' onclick='wpmc_delete_all()' class='button button-red' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-trash"></span><?php _e("Delete all", 'media-cleaner'); ?></a>
787
+ <?php } ?>
788
+
789
+ <form id="posts-filter" action="upload.php" method="get" style='float: right;'>
790
+ <p class="search-box" style='margin-left: 5px; float: left;'>
791
+ <input type="search" name="s" style="width: 120px;" value="<?php echo $s ? $s : ""; ?>">
792
+ <input type="hidden" name="page" value="media-cleaner">
793
+ <input type="hidden" name="view" value="<?php echo $view; ?>">
794
+ <input type="hidden" name="paged" value="<?php echo $paged; ?>">
795
+ <input type="submit" class="button" value="<?php _e( 'Search', 'media-cleaner' ) ?>"><span style='border-right: #A2A2A2 solid 1px; margin-left: 5px; margin-right: 3px;'>&nbsp;</span>
796
+ </p>
797
+ </form>
798
+
799
+ <!-- PROGRESS -->
800
+ <span style='margin-left: 12px; font-size: 15px; top: 5px; position: relative; color: #747474;' id='wpmc_progression'></span>
801
+
802
+ </div>
803
+
804
+ <p>
805
+ <?php
806
+ $method = get_option( 'wpmc_method', 'media' );
807
+ if ( !$wpmc_admin->is_registered() )
808
+ $method = 'media';
809
+
810
+ $hide_warning = get_option( 'wpmc_hide_warning', false );
811
+
812
+ if ( !$hide_warning ) {
813
+ _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> <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' );
814
+ }
815
+
816
+ if ( !MEDIA_TRASH ) {
817
+ _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:<br /><b>define( 'MEDIA_TRASH', true );</b></p></div>" );
818
+ }
819
+
820
+ if ( !$wpmc_admin->is_registered() ) {
821
+ echo "<div class='notice notice-info'><p>";
822
+ _e( "<b>This version is not Pro.</b> This plugin is a lot of work so please consider in getting the Pro version in order to receive support and to help the plugin to evolve. Also, the Pro version will also give you the option <b>to scan the <u>physical files</u> in your /uploads folder</b>. You can <a target='_blank' href='http://meowapps.com/media-cleaner'>get a serial for the Pro version here</a></b>.", 'media-cleaner' );
823
+ echo "</p></div>";
824
+ }
825
+
826
+ $anychecks = get_option(' wpmc_posts', false ) || get_option(' wpmc_galleries', false ) || get_option(' wpmc_postmeta', false );
827
+ $check_library = get_option(' wpmc_media_library', false );
828
+
829
+ if ( $method == 'media' ) {
830
+ if ( !$anychecks )
831
+ _e( "<div class='error'><p>Media Cleaner will analyze your Media Library. There is however <b>nothing marked to be check</b> in the Settings.</p></div>", 'media-cleaner' );
832
+ else
833
+ _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Media Library.</p></div>", 'media-cleaner' );
834
+ }
835
+ else if ( $method == 'files' ) {
836
+ if ( !$anychecks && !$check_library )
837
+ _e( "<div class='error'><p>Media Cleaner will analyze your Filesystem. There is however <b>nothing marked to be check</b> in the Settings.</p></div>", 'media-cleaner' );
838
+ else
839
+ _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Filesystem.</p></div>", 'media-cleaner' );
840
+ }
841
+
842
+ echo sprintf( __( 'There are <b>%s issue(s)</b> with your files, accounting for <b>%s MB</b>. Your trash contains <b>%s MB.</b>', 'media-cleaner' ), number_format( $issues_count, 0 ), number_format( $total_size / 1000000, 2 ), number_format( $trash_total_size / 1000000, 2 ) );
843
+ ?>
844
+ </p>
845
+
846
+ <div id='wpmc-pages'>
847
+ <?php
848
+ echo paginate_links(array(
849
+ 'base' => '?page=media-cleaner&s=' . urlencode($s) . '&view=' . $view . '%_%',
850
+ 'current' => $paged,
851
+ 'format' => '&paged=%#%',
852
+ 'total' => ceil( $items_count / $posts_per_page ),
853
+ 'prev_next' => false
854
+ ));
855
+ ?>
856
+ </div>
857
+
858
+ <ul class="subsubsub">
859
+ <li class="all"><a <?php if ( $view == 'issues' ) echo "class='current'"; ?> href='?page=media-cleaner&s=<?php echo $s; ?>&view=issues'><?php _e( "Issues", 'media-cleaner' ); ?></a><span class="count">(<?php echo $issues_count; ?>)</span></li> |
860
+ <li class="all"><a <?php if ( $view == 'ignored' ) echo "class='current'"; ?> href='?page=media-cleaner&s=<?php echo $s; ?>&view=ignored'><?php _e( "Ignored", 'media-cleaner' ); ?></a><span class="count">(<?php echo $ignored_count; ?>)</span></li> |
861
+ <li class="all"><a <?php if ( $view == 'deleted' ) echo "class='current'"; ?> href='?page=media-cleaner&s=<?php echo $s; ?>&view=deleted'><?php _e( "Trash", 'media-cleaner' ); ?></a><span class="count">(<?php echo $deleted_count; ?>)</span></li>
862
+ </ul>
863
+
864
+ <table id='wpmc-table' class='wp-list-table widefat fixed media'>
865
+
866
+ <thead>
867
+ <tr>
868
+ <th scope="col" id="cb" class="manage-column column-cb check-column"><input id="wpmc-cb-select-all" type="checkbox"></th>
869
+ <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
870
+ <th style='width: 64px;'><?php _e( 'Thumb', 'media-cleaner' ) ?></th>
871
+ <?php endif; ?>
872
+ <th style='width: 50px;'><?php _e( 'Type', 'media-cleaner' ) ?></th>
873
+ <th style='width: 80px;'><?php _e( 'Origin', 'media-cleaner' ) ?></th>
874
+
875
+ <?php if ( !empty( $wplr ) ): ?>
876
+ <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
877
+ <?php endif; ?>
878
+
879
+ <th><?php _e( 'Path', 'media-cleaner' ) ?></th>
880
+ <th style='width: 220px;'><?php _e( 'Issue', 'media-cleaner' ) ?></th>
881
+ <th style='width: 80px; text-align: right;'><?php _e( 'Size', 'media-cleaner' ) ?></th>
882
+ </tr>
883
+ </thead>
884
+
885
+ <tbody>
886
+ <?php
887
+ foreach ( $items as $issue ) {
888
+ $regex = "^(.*)(\\s\\(\\+.*)$";
889
+ $issue->path = preg_replace( '/' .$regex . '/i', '$1', $issue->path );
890
+ ?>
891
+ <tr>
892
+ <td><input type="checkbox" name="id" value="<?php echo $issue->id ?>"></td>
893
+ <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
894
+ <td>
895
+ <?php
896
+ if ( $issue->deleted == 0 ) {
897
+ if ( $issue ->type == 0 ) {
898
+ // FILE
899
+ $upload_dir = wp_upload_dir();
900
+ $url = htmlspecialchars( $upload_dir['baseurl'] . '/' . $issue->path, ENT_QUOTES );
901
+ echo "<a target='_blank' href='" . $url .
902
+ "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
903
+ }
904
+ else {
905
+ // MEDIA
906
+ $attachmentsrc = wp_get_attachment_image_src( $issue->postId, 'thumbnail' );
907
+ $attachmentsrc_clean = htmlspecialchars( $attachmentsrc[0], ENT_QUOTES );
908
+ echo "<a target='_blank' href='" . $attachmentsrc_clean .
909
+ "'><img style='max-width: 48px; max-height: 48px;' src='" .
910
+ $attachmentsrc_clean . "' />";
911
+ }
912
+ }
913
+ if ( $issue->deleted == 1 ) {
914
+ $upload_dir = wp_upload_dir();
915
+ $url = htmlspecialchars( $upload_dir['baseurl'] . '/wpmc-trash/' . $issue->path, ENT_QUOTES );
916
+ echo "<a target='_blank' href='" . $url .
917
+ "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
918
+ }
919
+ ?>
920
+ </td>
921
+ <?php endif; ?>
922
+ <td><?php echo $issue->type == 0 ? 'FILE' : 'MEDIA'; ?></td>
923
+ <td><?php echo $issue->type == 0 ? 'Filesystem' : ("<a href='post.php?post=" .
924
+ $issue->postId . "&action=edit'>ID " . $issue->postId . "</a>"); ?></td>
925
+ <?php if ( !empty( $wplr ) ) { $info = $wplr->get_sync_info( $issue->postId ); ?>
926
+ <td style='width: 70px;'><?php echo ( !empty( $info ) && $info->lr_id ? $info->lr_id : "" ); ?></td>
927
+ <?php } ?>
928
+ <td><?php echo stripslashes( $issue->path ); ?></td>
929
+ <td><?php echo_issue( $issue->issue ); ?></td>
930
+ <td style='text-align: right;'><?php echo number_format( $issue->size / 1000, 2 ); ?> KB</td>
931
+ </tr>
932
+ <?php } ?>
933
+ </tbody>
934
+
935
+ <tfoot>
936
+ <tr><th></th>
937
+ <?php if ( !get_option( 'hide_thumbnails', false ) ): ?>
938
+ <th></th>
939
+ <?php endif; ?>
940
+ <th><?php _e( 'Type', 'media-cleaner' ) ?></th><th><?php _e( 'Origin', 'media-cleaner' ) ?></th><th><?php _e( 'Path', 'media-cleaner' ) ?></th><th><?php _e( 'Issue', 'media-cleaner' ) ?></th><th style='width: 80px; text-align: right;'><?php _e( 'Size', 'media-cleaner' ) ?></th></tr>
941
+ </tfoot>
942
+
943
+ </table>
944
+ </wrap>
945
+
946
+ <?php
947
+ }
948
+
949
+ /**
950
+ *
951
+ * PLUGIN INSTALL / UNINSTALL / SCRIPTS
952
+ *
953
+ */
954
+
955
+ function wpmc_check_db() {
956
+ global $wpdb;
957
+ $tbl_m = $wpdb->prefix . 'wpmcleaner';
958
+ 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 ) ) ) {
959
+ wpmc_activate();
960
+ }
961
+ }
962
+
963
+ function wpmc_admin_menu() {
964
+ load_plugin_textdomain( 'media-cleaner', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
965
+ add_media_page( 'Media Cleaner', 'Cleaner', 'manage_options', 'media-cleaner', 'wpmc_screen' );
966
+ }
967
+
968
+ function wpmc_reset () {
969
+ wpmc_uninstall();
970
+ wpmc_activate();
971
+ }
972
+
973
+ function wpmc_activate () {
974
+ global $wpdb;
975
+ $table_name = $wpdb->prefix . "wpmcleaner";
976
+ $charset_collate = $wpdb->get_charset_collate();
977
+ $sql = "CREATE TABLE $table_name (
978
+ id BIGINT(20) NOT NULL AUTO_INCREMENT,
979
+ time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL,
980
+ type TINYINT(1) NOT NULL,
981
+ postId BIGINT(20) NULL,
982
+ path TINYTEXT NULL,
983
+ size INT(9) NULL,
984
+ ignored TINYINT(1) NOT NULL DEFAULT 0,
985
+ deleted TINYINT(1) NOT NULL DEFAULT 0,
986
+ issue TINYTEXT NOT NULL,
987
+ UNIQUE KEY id (id)
988
+ ) " . $charset_collate . ";";
989
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
990
+ dbDelta( $sql );
991
+
992
+ $upload_folder = wp_upload_dir();
993
+ $basedir = $upload_folder['basedir'];
994
+ if ( !is_writable( $basedir ) ) {
995
+ echo '<div class="error"><p>' . __( 'The directory for uploads is not writable. Media Cleaner will only be able to scan.', 'media-cleaner' ) . '</p></div>';
996
+ }
997
+ }
998
+
999
+ function wpmc_uninstall () {
1000
+ global $wpdb;
1001
+ $table_name = $wpdb->prefix . "wpmcleaner";
1002
+ $wpdb->query("DROP TABLE IF EXISTS $table_name");
1003
+ }
1004
+
1005
+ function wpmc_wp_enqueue_scripts () {
1006
+ wp_enqueue_style( 'media-cleaner-css', plugins_url( '/media-cleaner.css', __FILE__ ) );
1007
+ wp_enqueue_script( 'media-cleaner', plugins_url( '/media-cleaner.js', __FILE__ ), array( 'jquery' ), "3.6.8", true );
1008
+ }
1009
+
1010
+ /*******************************************************************************
1011
+ * OLD PRO / TODO: THIS FUNCTION SHOULD BE REMOVED IN THE FUTURE
1012
+ ******************************************************************************/
1013
+
1014
+ function wpmc_admin_notices() {
1015
+ if ( isset( $_POST['wpmc_reset_sub'] ) ) {
1016
+ delete_transient( 'wpmc_validated' );
1017
+ delete_option( 'wpmc_pro_serial' );
1018
+ delete_option( 'wpmc_pro_status' );
1019
+ }
1020
+ $validated = get_transient( 'wpmc_validated' );
1021
+ $subscr_id = get_option( 'wpmc_pro_serial', "" );
1022
+ if ( empty( $subscr_id ) || empty( $validated ) )
1023
+ return;
1024
+ $forever = strpos( $subscr_id, 'F-' ) !== false;
1025
+ $yearly = strpos( $subscr_id, 'I-' ) !== false;
1026
+ ?>
1027
+ <div class="error">
1028
+ <p>
1029
+ <b>IMPORTANT MESSAGE ABOUT MEDIA CLEANER.</b>
1030
+ In order to comply with WordPress.org rules, changes in the code and how the plugin was sold had to be made. The plugin now requires to be bought through <a target='_blank' href="https://store.meowapps.com">https://store.meowapps.com</a>. You will be able to download the Pro version there (and it will be kept updated), manage your keys and websites. Only the free version can be hosted by WordPress.org, so this is the one you have now. To ease this upgrade, I made the price of my standard licenses cheaper.<br /><br />
1031
+ Your license is <b><?php echo $subscr_id ?></b>.
1032
+ <?php
1033
+ if ( $forever ) {
1034
+ echo "You have a Forever license. If you got this license less than 120 days ago, reply to the welcome e-mail (after buying a new license) with your previous license key ($subscr_id) and the e-mail you are using in Paypal. I will refund the previous payment. Otherwise, we are out of luck :( So here is a discount instead, of <b>90% off</b>, for any license you like: <b>UPGRADE90MEDIACLEANER</b>.";
1035
+ }
1036
+ else if ( $yearly ) {
1037
+ echo "You have a Yearly license. If you got this license less than 120 days ago, reply to the welcome e-mail (after buying a new license) with your previous license key ($subscr_id) and the e-mail you are using in Paypal. I will refund the previous payment. If it is more than 120 days ago, we are out of luck :) So here is a discount of <b>50% off</b>, for any license you like: <b>UPGRADEMEDIACLEANER50</b>. Also, don't forget to cancel your current subscription in Paypal (<a target='_blank' href='https://www.paypal.com/us/selfhelp/article/How-do-I-cancel-an-automatic-payment-I-have-with-a-merchant-FAQ2058'>click here</a> if you don't know how to do this).";
1038
+ }
1039
+ else {
1040
+ echo "Your license is special, so please contact me.";
1041
+ }
1042
+ ?>
1043
+ If you absolutely need to use the plugin as it was before, with your current license key, please download it again here: <a target='_blank' href="https://meowapps.com/previous-versions/">Previous Versions</a>. I will keep the old system up for a while, but no updates will be possible, and better to enjoy the discount codes.
1044
+ <br /><br />Also note that I also have now an <a target='_blank' href='https://store.meowapps.com/affiliate-area/'>Affiliate Program</a> in that store, don't hesitate to register for it. Thanks a lot for your comprehension and sorry for the troubles. Not easy for anyone but it had to be done and I think you will really enjoy the new store more than the previous clunky system.
1045
+ </p>
1046
+ <p>
1047
+ <form method="post" action="">
1048
+ <input type="hidden" name="wpmc_reset_sub" value="true">
1049
+ <input type="submit" name="submit" id="submit" class="button" value="Got it. Understood!">
1050
+ <br /><small>Make sure you got a new license and all before clicking this button. It will also clean your install from the old key data.</small>
1051
+ </form>
1052
+ </p>
1053
+ </div>
1054
+ <?php
1055
+ }
1056
+
1057
+ if ( file_exists( plugin_dir_path( __FILE__ ) . 'wpmc_checkers.php' ) ) {
1058
+ require( 'wpmc_checkers.php' );
1059
+ }
1060
+
1061
+ if ( !$disable_meowapps && file_exists( plugin_dir_path( __FILE__ ) . '/meowapps/core.php' ) ) {
1062
+ require( 'meowapps/core.php' );
1063
+ new MeowApps_MediaCleaner_Core( __FILE__ );
1064
+ }
readme.txt ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Media Cleaner ===
2
+ Contributors: TigrouMeow
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=H2S7S3G4XMJ6J
4
+ Tags: management, admin, file, files, images, image, media, library, upload, clean, cleaning
5
+ Requires at least: 4.2
6
+ Tested up to: 4.7
7
+ Stable tag: 3.6.8
8
+
9
+ Clean your Media Library and Uploads directory. It has an internal trash and recovery features.
10
+
11
+ == Description ==
12
+
13
+ Clean your Media Library from the media which aren't used in any of your posts, gallery and so on. It features an internal trash, moving the files in there temporarily for you to make sure the files aren't actually in used; once checked, you can trash them permanently. **Before using this plugin, make sure you have a proper backup of your files and database. This is the most important step on the usage of this plugin as you can't trust any file deletion tools.** The Pro version of this plugin brings also scanning to the /uploads folder and will detect which files aren't registered in the Media Library, not used in your content and so on. Retina images are also detected and supported, shortcodes, HTML in sidebars and of course your posts, pages and all post types.
14
+
15
+ **This tool is a knife. I try to make this knife perfect. However, this is still a knife, and in the hands of somebody who doesn't understand it and just use it without thinking, it might end badly. Don't use it you you don't have any backup, or if you don't know what it does.**
16
+
17
+ **INCOMPATIBILITY**. If you are not using WordPress naturally and using plugin to edit your posts, this plugin will not be able to detect how your images are used. For instance, Visual Composer is not supported as for now.
18
+
19
+ **UNIQUE PLUGIN**. Such a plugin is difficult to create and to maintain. If you understand WordPress, you probably know why. This plugin tries its best to help you. Get used to it and you will get awesome results. This is the only plugin to propose those functions and even a dashboard to cleanup your WordPress install from unused files.
20
+
21
+ **DASHBOARD**. Those file will be shown in a specific dashboard. At this point, it will be up to you to delete them. Files detected as un-used are added to a specific dashboard where you can choose to trash them. They will be then moved to a trash internal to the plugin. After more testing, you can trash them definitely.
22
+
23
+ **FREE / PRO**. The Free version of the plugin works with the media available in your Media Library. The Pro version adds file scanning to your physical /uploads directory.
24
+
25
+ **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. This is a knife, you need to understand what it does and how before using it.
26
+
27
+ It has been tested with WP Retina 2x and WPML.
28
+
29
+ Languages: English, French.
30
+
31
+ == Installation ==
32
+
33
+ 1. Upload `media-file-cleaner` to the `/wp-content/plugins/` directory
34
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
35
+ 3. Go in the Settings -> Media Cleaner and check the appropriate options
36
+ 3. Go in Media -> Media Cleaner
37
+
38
+ == Upgrade Notice ==
39
+
40
+ Replace all the files. Nothing else to do.
41
+
42
+ == Frequently Asked Questions ==
43
+
44
+ = Is it safe? =
45
+ 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.
46
+
47
+ = What is 'Reset' doing exactly? =
48
+ It re-creates the Media Cleaner table in the database. You will need to re-run the scan after this.
49
+
50
+ == Screenshots ==
51
+
52
+ 1. Media -> Media Cleaner
53
+
54
+ == Changelog ==
55
+
56
+ = 3.6.8 =
57
+ * Fix: Little issue when inserting the serial key for the first time.
58
+ * Update: Compliance with the WordPress.org rules, new licensing system.
59
+ * Update: Moved assets.
60
+ * Info: There will be an important warning showing up during this update. It is an important annoucement.
61
+
62
+ = 3.6.4 =
63
+ * Fix: Plugin was not working properly with broken Media metadata. It now handles it properly.
64
+ * Info: If you want to give me a bit of motivation, write a review on https://wordpress.org/support/plugin/media-cleaner/reviews/?rate=5#new-post.
65
+
66
+ = 3.6.2 =
67
+ * Fix: When over 1 GO, was displaying a lower size value.
68
+ * Fix: Counting wasn't exact with a Filesystem scan.
69
+ * Info: Please read the previous changelog as it didn't appear in WP for some reason.
70
+ * Add: Check Posts also look for the Media ID in the classes (more secure).
71
+ * Info: If you want to give me a bit of motivation, write a review on https://wordpress.org/support/plugin/media-cleaner/reviews/?rate=5#new-post.
72
+
73
+ = 3.6.0 =
74
+ * Add: Now the Media can be recovered! You can remove your Media through the plugin, make sure they are not in use (by testing your website thoroughly) and later delete them definitely from the trash. I think you will find it awesome.
75
+ * Update: Nicer internal icons rather than the old images for the UI.
76
+ * Update: Faster and safer for post_content checks.
77
+ * Update: This is a big one. The plugin is more clear about what it does. You need to choose either to scan the Media or the Filesystem, and also against what exactly. There has also been a few fixes and it will work on more big installs. If it fails, you can remove a few scanning options, and I will continue to work on making it perfect to support huge installs with all the options on.
78
+
79
+ = 3.2.8 =
80
+ * Update: Show a better edit media screen.
81
+ * Update: Will show the same number of items as in the Media Library (before it was fixed to 15 items per page).
82
+ * Fix: Was displaying warning if the number of items per page in the Media page is not set.
83
+
84
+ = 3.2.0 =
85
+ * Fix: HTML adapted to WP 4.5.1.
86
+ * Fix: Doesn't break if there is an error on the server-side. Display an alert and continue.
87
+ * Update: Can select more than one file for non-Pro.
88
+ * Fix: Issue with PHP 7.
89
+
90
+ = 3.0.0 =
91
+ * Add: Option for resolving shortcode during analysis.
92
+ * Update: French translation. Big thanks to Guillaume (and also for all his testing!).
93
+ * Info: New name, fresh start. This plugin changed completely since it very first release :)
94
+
95
+ = 2.5.0 =
96
+ * Add: Delete the unused directories.
97
+ * Add: Doesn't break when there are too many files in the system.
98
+ * Add: Pro version with better support.
99
+ * Update: Improved detection of unused files.
100
+ * Fix: UTF8 filenames skipped by default but can be scanned through an option.
101
+ * Fix: Really many fixes :)
102
+ * Info: Contact me if you have been using the plugin for a long time and love it.
103
+
104
+ = 2.4.2 =
105
+ * Add: Inclusion of gallery post format images.
106
+ * Fix: Better gallery URL matching.
107
+ * Info: Thanks to syntax53 for those improvements via GitHub (https://github.com/tigroumeow/media-file-cleaner/pull/3). Please review Media Cleaner if you like it. The plugin needs reviews to live. Thank you :) (https://wordpress.org/support/view/plugin-reviews/media-file-cleaner)
108
+
109
+ = 2.4.0 =
110
+ * Fix: Cross site scripting vulnerability fixes.
111
+ * Change: Many enhancements and fixes made by Matt (http://www.twistedtek.net/). Please thanks him :)
112
+ * Info: Please perform a "Reset" in the plugin dashboard after installing this new version.
113
+
114
+ = 2.2.6 =
115
+ * Fix: Scan for multisite.
116
+ * Change: options are now all enabled by default.
117
+ * Fix: DB issue avoided trashed files from being deleted permanently.
118
+
119
+ = 2.0.2 =
120
+ * Works with WP 4.
121
+ * Gallery support.
122
+ * Fix: IGNORE function was... ignored by the scanning process.
123
+
124
+ = 1.9.0 =
125
+ * Add: thumbnails.
126
+ * Add: IGNORE function.
127
+ * Change: cosmetic changes.
128
+ * Add: now detects the custom header and custom background.
129
+ * Change: the CSS was updated to fit the new Admin theme.
130
+
131
+ = 1.7.0 =
132
+ * Change: the MEDIA files are now going to the trash but the MEDIA reference in the DB is still removed permanently.
133
+ * Stable release.
134
+ * Change: Readme.txt.
135
+
136
+ = 1.4.0 =
137
+ * Add: check the meta properties.
138
+ * Add: check the 'featured image' properties.
139
+ * Fix: keep the trash information when a new scan is started.
140
+ * Fix: remove the DB on uninstall, not on desactivate.
141
+
142
+ = 1.2.2 =
143
+ * Add: progress %.
144
+ * Fix: issues with apostrophes in filenames.
145
+ * Change: UI cleaning.
146
+
147
+ = 1.2.0 =
148
+ * Add: options (scan files / scan media).
149
+ * Fix: mkdir issues.
150
+ * Change: operations are buffered by 5 (faster).
151
+
152
+ = 0.1.0 =
153
+ * First release.
wpmc_admin.php ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ include "common/admin.php";
4
+
5
+ class Meow_MediaCleaner_Admin extends MeowApps_Admin {
6
+
7
+ public function __construct() {
8
+ parent::__construct();
9
+ add_action( 'admin_menu', array( $this, 'app_menu' ) );
10
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
11
+ $method = get_option( 'wpmc_method', 666 );
12
+ if ( $method == 666 )
13
+ $this->initial_setup();
14
+ }
15
+
16
+ function admin_notices() {
17
+ if ( !$this->is_registered() && get_option( 'wpmc_method', 'media' ) == 'files' ) {
18
+ _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' );
19
+ }
20
+ }
21
+
22
+ function initial_setup() {
23
+ update_option( 'wpmc_method', 'media', false );
24
+ update_option( 'wpmc_posts', false, false );
25
+ update_option( 'wpmc_galleries', false, false );
26
+ update_option( 'wpmc_postmeta', false, false );
27
+ $shortcode = $this->old_getoption( 'shortcode', 'wpmc_basics', false );
28
+ update_option( 'wpmc_shortcode', $shortcode, false );
29
+ $utf8_support = $this->old_getoption( 'scan_non_ascii', 'wpmc_basics', false );
30
+ update_option( 'wpmc_utf8', $utf8_support, false );
31
+ $hide_thumbnails = $this->old_getoption( 'hide_thumbnails', 'wpmc_basics', false );
32
+ update_option( 'wpmc_hide_thumbnails', $hide_thumbnails, false );
33
+ $hide_warning = $this->old_getoption( 'hide_warning', 'wpmc_basics', false );
34
+ update_option( 'wpmc_hide_warning', $hide_warning, false );
35
+ delete_option( 'wpmc_basics' );
36
+ delete_option( 'wpmc_pro' );
37
+ }
38
+
39
+ function common_url( $file ) {
40
+ return trailingslashit( plugin_dir_url( __FILE__ ) ) . 'common/' . $file;
41
+ }
42
+
43
+ function app_menu() {
44
+
45
+ // SUBMENU > Settings
46
+ add_submenu_page( 'meowapps-main-menu', 'Media Cleaner', 'Media Cleaner', 'manage_options',
47
+ 'wpmc_settings-menu', array( $this, 'admin_settings' ) );
48
+
49
+ // SUBMENU > Settings > Settings
50
+ add_settings_section( 'wpmc_settings', null, null, 'wpmc_settings-menu' );
51
+ add_settings_field( 'wpmc_method', "Method",
52
+ array( $this, 'admin_method_callback' ),
53
+ 'wpmc_settings-menu', 'wpmc_settings' );
54
+ if ( get_option( 'wpmc_method', 'media' ) == 'files' ) {
55
+ add_settings_field( 'wpmc_media_library', "Media Library",
56
+ array( $this, 'admin_media_library_callback' ),
57
+ 'wpmc_settings-menu', 'wpmc_settings' );
58
+ }
59
+ add_settings_field( 'wpmc_posts', "Posts",
60
+ array( $this, 'admin_posts_callback' ),
61
+ 'wpmc_settings-menu', 'wpmc_settings' );
62
+ add_settings_field( 'wpmc_postmeta', "Post Meta",
63
+ array( $this, 'admin_postmeta_callback' ),
64
+ 'wpmc_settings-menu', 'wpmc_settings' );
65
+ add_settings_field( 'wpmc_galleries', "Galleries",
66
+ array( $this, 'admin_galleries_callback' ),
67
+ 'wpmc_settings-menu', 'wpmc_settings' );
68
+ add_settings_field( 'wpmc_widgets', "Widgets",
69
+ array( $this, 'admin_widgets_callback' ),
70
+ 'wpmc_settings-menu', 'wpmc_settings' );
71
+
72
+ if ( get_option( 'wpmc_posts', false ) ) {
73
+ add_settings_field( 'wpmc_shortcode', "Shortcodes<br />(Pro)",
74
+ array( $this, 'admin_shortcode_callback' ),
75
+ 'wpmc_settings-menu', 'wpmc_settings' );
76
+ }
77
+ add_settings_field( 'wpmc_utf8', "UTF-8",
78
+ array( $this, 'admin_utf8_callback' ),
79
+ 'wpmc_settings-menu', 'wpmc_settings' );
80
+
81
+ // SUBMENU > Settings > Settings
82
+ add_settings_section( 'wpmc_ui_settings', null, null, 'wpmc_ui_settings-menu' );
83
+ add_settings_field( 'wpmc_hide_thumbnails', "Thumbnails",
84
+ array( $this, 'admin_hide_thumbnails_callback' ),
85
+ 'wpmc_ui_settings-menu', 'wpmc_ui_settings' );
86
+ add_settings_field( 'wpmc_hide_warning', "Warning Message (Pro)",
87
+ array( $this, 'admin_hide_warning_callback' ),
88
+ 'wpmc_ui_settings-menu', 'wpmc_ui_settings' );
89
+
90
+ // SETTINGS
91
+ register_setting( 'wpmc_settings', 'wpmc_method' );
92
+ register_setting( 'wpmc_settings', 'wpmc_posts' );
93
+ register_setting( 'wpmc_settings', 'wpmc_shortcode' );
94
+ register_setting( 'wpmc_settings', 'wpmc_galleries' );
95
+ register_setting( 'wpmc_settings', 'wpmc_widgets' );
96
+ register_setting( 'wpmc_settings', 'wpmc_media_library' );
97
+ register_setting( 'wpmc_settings', 'wpmc_postmeta' );
98
+ register_setting( 'wpmc_settings', 'wpmc_utf8' );
99
+
100
+ register_setting( 'wpmc_ui_settings', 'wpmc_hide_thumbnails' );
101
+ register_setting( 'wpmc_ui_settings', 'wpmc_hide_warning' );
102
+ }
103
+
104
+ function admin_settings() {
105
+ wpmc_check_db()
106
+ ?>
107
+ <div class="wrap">
108
+ <?php
109
+ echo $this->display_title( "Media Cleaner" );
110
+ ?>
111
+ <p>This plugin will help you cleaning your WordPress install.</p>
112
+ <div class="meow-section meow-group">
113
+ <div class="meow-box meow-col meow-span_2_of_2">
114
+ <h3>How to use</h3>
115
+ <div class="inside">
116
+ <?php echo _e( "You can choose thow 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. I am working actively on making the plugin to work fine even on huge installs with all those options.</b>", 'media-cleaner' ); ?>
117
+ </div>
118
+
119
+ </div>
120
+ </div>
121
+
122
+ <div class="meow-section meow-group">
123
+
124
+ <div class="meow-col meow-span_1_of_2">
125
+ <div class="meow-box">
126
+ <h3>Scanning</h3>
127
+ <div class="inside">
128
+ <form method="post" action="options.php">
129
+ <?php settings_fields( 'wpmc_settings' ); ?>
130
+ <?php do_settings_sections( 'wpmc_settings-menu' ); ?>
131
+ <?php submit_button(); ?>
132
+ </form>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="meow-col meow-span_1_of_2">
138
+ <?php $this->display_serialkey_box( "https://meowapps.com/media-cleaner/" ); ?>
139
+
140
+ <div class="meow-box">
141
+ <h3>Scanning</h3>
142
+ <div class="inside">
143
+ <form method="post" action="options.php">
144
+ <?php settings_fields( 'wpmc_ui_settings' ); ?>
145
+ <?php do_settings_sections( 'wpmc_ui_settings-menu' ); ?>
146
+ <?php submit_button(); ?>
147
+ </form>
148
+ </div>
149
+ </div>
150
+
151
+ <?php if ( get_option( 'wpmc_shortcode', false ) ): ?>
152
+ <div class="meow-box">
153
+ <h3>Shortcodes</h3>
154
+ <div class="inside">
155
+ <p>Here are the shortcodes registered in your WordPress by your theme and other plugins.</p>
156
+ <?php
157
+ global $shortcode_tags;
158
+ try {
159
+ $allshortcodes = array_diff( $shortcode_tags, array( ) );
160
+ $my_shortcodes = array();
161
+ foreach ( $allshortcodes as $sc )
162
+ if ( $sc != '__return_false' ) {
163
+ if ( is_string( $sc ) )
164
+ array_push( $my_shortcodes, str_replace( '_shortcode', '', (string)$sc ) );
165
+ }
166
+ $my_shortcodes = implode( '<br />', $my_shortcodes );
167
+ }
168
+ catch (Exception $e) {
169
+ $my_shortcodes = "";
170
+ }
171
+ echo $my_shortcodes;
172
+ ?>
173
+ </div>
174
+ </div>
175
+ <?php endif; ?>
176
+
177
+ </div>
178
+
179
+ </div>
180
+ </div>
181
+ <?php
182
+ }
183
+
184
+
185
+
186
+ /*
187
+ OPTIONS CALLBACKS
188
+ */
189
+
190
+ function admin_method_callback( $args ) {
191
+ $value = get_option( 'wpmc_method', 'media' );
192
+ $html = '<select id="wpmc_method" name="wpmc_method">
193
+ <option ' . selected( 'media', $value, false ) . 'value="media">Media Library</option>
194
+ <option ' . disabled( $this->is_registered(), false, false ) . ' ' . selected( 'files', $value, false ) . 'value="files">Filesystem (Pro)</option>
195
+ </select><small><br /><br />' . __( '<b>Media Library</b>: The medias from Media Library which seem not being used in your WordPress will be marked as to be deleted. <br /><br /><b>Filesystem</b>: The files in your /uploads directory that don\'t seem being used in your WordPress will be marked as to be deleted. If the files are registered as a media in your Media Library, they will be considered as fine (even if they are not used in the content of your website).', 'media-cleaner' ) . '</small>';
196
+ echo $html;
197
+ }
198
+
199
+
200
+ function admin_shortcode_callback( $args ) {
201
+ $value = get_option( 'wpmc_shortcode', null );
202
+ $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_shortcode" name="wpmc_shortcode" value="1" ' .
203
+ checked( 1, get_option( 'wpmc_shortcode' ), false ) . '/>';
204
+ $html .= '<label>Analyze</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. This process takes resources and if the scanning suddenly stops, this might be the cause. You don\'t need to have this option enabled for the WP Gallery (this is covered by the Galleries option).</small>';
205
+ echo $html;
206
+ }
207
+
208
+ function admin_utf8_callback( $args ) {
209
+ $value = get_option( 'wpmc_utf8', null );
210
+ $html = '<input type="checkbox" id="wpmc_utf8" name="wpmc_utf8" value="1" ' .
211
+ checked( 1, get_option( 'wpmc_utf8' ), false ) . '/>';
212
+ $html .= __( '<label>Do not skip UTF-8 filenames</label><br /><small>PHP does not always work well with UTF-8 on all systems. If the scanning suddenly stops, this might be the cause.</small>', 'media-cleaner' );
213
+ echo $html;
214
+ }
215
+
216
+ function admin_media_library_callback( $args ) {
217
+ $value = get_option( 'wpmc_media_library', null );
218
+ $html = '<input type="checkbox" id="wpmc_media_library" name="wpmc_media_library" value="1" ' .
219
+ checked( 1, get_option( 'wpmc_media_library' ), false ) . '/>';
220
+ $html .= '<label>Check</label><br /><small>Checks if the file is part of a Media (as a full-size or alternative size). This option is of course only available for the Filesystem method.</small>';
221
+ echo $html;
222
+ }
223
+
224
+ function admin_galleries_callback( $args ) {
225
+ $value = get_option( 'wpmc_galleries', null );
226
+ $html = '<input type="checkbox" id="wpmc_galleries" name="wpmc_galleries" value="1" ' .
227
+ checked( 1, get_option( 'wpmc_galleries' ), false ) . '/>';
228
+ $html .= '<label>Analyze</label><br /><small>Checks if the file is used in a WP Gallery (which are in posts or any post-type).</small>';
229
+ echo $html;
230
+ }
231
+
232
+ function admin_posts_callback( $args ) {
233
+ $value = get_option( 'wpmc_posts', false );
234
+ $html = '<input type="checkbox" id="wpmc_posts" name="wpmc_posts" value="1" ' .
235
+ checked( 1, get_option( 'wpmc_posts' ), false ) . '/>';
236
+ $html .= '<label>Analyze</label><br /><small>Check if the file is used in posts (that includes any post-type: pages, products and others) and, in addition, in case of the Media, check if it used in the IMG\'s class.</small>';
237
+ echo $html;
238
+ }
239
+
240
+ function admin_postmeta_callback( $args ) {
241
+ $value = get_option( 'wpmc_postmeta', false );
242
+ $html = '<input type="checkbox" id="wpmc_postmeta" name="wpmc_postmeta" value="1" ' .
243
+ checked( 1, get_option( 'wpmc_postmeta' ), false ) . '/>';
244
+ $html .= '<label>Analyze</label><br /><small>Checks if the file is used in the Post Meta.</small>';
245
+ echo $html;
246
+ }
247
+
248
+ function admin_widgets_callback( $args ) {
249
+ $value = get_option( 'wpmc_widgets', false );
250
+ $html = '<input type="checkbox" id="wpmc_widgets" name="wpmc_widgets" value="1" ' .
251
+ checked( 1, get_option( 'wpmc_widgets' ), false ) . '/>';
252
+ $html .= '<label>Analyze</label><br /><small>Checks if the file is used in widgets.</small>';
253
+ echo $html;
254
+ }
255
+
256
+ function admin_hide_thumbnails_callback( $args ) {
257
+ $value = get_option( 'wpmc_hide_thumbnails', null );
258
+ $html = '<input type="checkbox" id="wpmc_hide_thumbnails" name="wpmc_hide_thumbnails" value="1" ' .
259
+ checked( 1, get_option( 'wpmc_hide_thumbnails' ), false ) . '/>';
260
+ $html .= '<label>Hide</label><br /><small>If you prefer not to see the thumbnails.</small>';
261
+ echo $html;
262
+ }
263
+
264
+ function admin_hide_warning_callback( $args ) {
265
+ $value = get_option( 'wpmc_hide_warning', null );
266
+ $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_hide_warning" name="wpmc_hide_warning" value="1" ' .
267
+ checked( 1, get_option( 'wpmc_hide_warning' ), false ) . '/>';
268
+ $html .= '<label>Hide</label><br /><small>Have you read it twice? If yes, hide it :)</small>';
269
+ echo $html;
270
+ }
271
+
272
+ /**
273
+ *
274
+ * GET / SET OPTIONS (TO REMOVE)
275
+ *
276
+ */
277
+
278
+ function old_getoption( $option, $section, $default = '' ) {
279
+ $options = get_option( $section );
280
+ if ( isset( $options[$option] ) ) {
281
+ if ( $options[$option] == "off" ) {
282
+ return false;
283
+ }
284
+ if ( $options[$option] == "on" ) {
285
+ return true;
286
+ }
287
+ return $options[$option];
288
+ }
289
+ return $default;
290
+ }
291
+
292
+ }
293
+
294
+ ?>
wpmc_checkers.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // This file will contains all the CORE checkers of the Media Cleaner system.
4
+ // Each 'checker' checks the usage of the file by a certain feature of WordPress.
5
+
6
+ function wpmc_check_db_has_background_or_header( $file ) {
7
+ global $wpmc_debug;
8
+ if ( current_theme_supports( 'custom-header' ) ) {
9
+ $custom_header = get_custom_header();
10
+ if ( $custom_header && $custom_header->url ) {
11
+ if ( strpos( $custom_header->url, $file ) !== false )
12
+ if ($wpmc_debug) error_log("{$file} found in header");
13
+ return true;
14
+ }
15
+ }
16
+
17
+ if ( current_theme_supports( 'custom-background' ) ) {
18
+ $custom_background = get_theme_mod('background_image');
19
+ if ( $custom_background ) {
20
+ if ( strpos( $custom_background, $file ) !== false )
21
+ if ($wpmc_debug) error_log("{$file} found in background");
22
+ return true;
23
+ }
24
+ }
25
+
26
+ return false;
27
+ }
28
+
29
+ function wpmc_check_in_gallery( $file ) {
30
+
31
+ if ( !get_option( 'wpmc_galleries', false ) )
32
+ return false;
33
+
34
+ global $wpmc_debug;
35
+ $file = wpmc_clean_uploaded_filename( $file );
36
+ $uploads = wp_upload_dir();
37
+ $parsedURL = parse_url( $uploads['baseurl'] );
38
+ $regex_match_file = '(' . preg_quote( $file ) . ')';
39
+ $regex = addcslashes( '(?:(?:http(?:s)?\\:)?//' .
40
+ preg_quote( $parsedURL['host'] ).')?' .
41
+ preg_quote( $parsedURL['path'] ) . '/' . $regex_match_file, '/');
42
+ $images = wpmc_get_galleries_images();
43
+ foreach ( $images as $image ) {
44
+ $found = preg_match('/'.$regex.'/i', $image);
45
+ if ( $wpmc_debug && $found )
46
+ error_log("{$file} found in a galllery");
47
+ if ( $found )
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+
53
+ function wpmc_check_db_has_meta( $file, $attachment_id = 0 ) {
54
+
55
+ if ( !get_option( 'wpmc_postmeta', false ) )
56
+ return false;
57
+
58
+ global $wpdb, $wpmc_debug;
59
+ $uploads = wp_upload_dir();
60
+ $parsedURL = parse_url( $uploads['baseurl'] );
61
+ $file = wpmc_clean_uploaded_filename( $file );
62
+ $regex_match_file = '(' . preg_quote( $file ) . ')';
63
+ $regex = addcslashes( '(?:(?:(?:http(?:s)?\\:)?//' .
64
+ preg_quote( $parsedURL['host']) . ')?(?:' .
65
+ preg_quote( $parsedURL['path']) . '/)|^)' . $regex_match_file, '/');
66
+ $regex_mysql = str_replace( '(?:', '(', $regex );
67
+ if ( $attachment_id > 0 ) {
68
+ $mediaCount = $wpdb->get_var(
69
+ $wpdb->prepare( "SELECT COUNT(*)
70
+ FROM $wpdb->postmeta
71
+ WHERE post_id != %d
72
+ AND meta_key != '_wp_attached_file'
73
+ AND (meta_value REGEXP %s OR meta_value = %d)",
74
+ $attachment_id, $regex_mysql, $attachment_id
75
+ )
76
+ );
77
+ } else {
78
+ $mediaCount = $wpdb->get_var(
79
+ $wpdb->prepare( "SELECT COUNT(*)
80
+ FROM $wpdb->postmeta
81
+ WHERE meta_key != '_wp_attached_file'
82
+ AND meta_value REGEXP %s",
83
+ $regex_mysql
84
+ )
85
+ );
86
+ }
87
+ if ( $wpmc_debug && $mediaCount > 0 )
88
+ error_log("{$file} found in POSTMETA");
89
+ return $mediaCount > 0;
90
+ }
91
+
92
+
93
+ function wpmc_check_db_has_content( $file, $mediaId = null ) {
94
+
95
+ global $wpdb, $wpmc_debug;
96
+ $shortcode_support = get_option( 'wpmc_shortcode', false );
97
+
98
+ // Check in Posts Content
99
+ if ( get_option( 'wpmc_posts', false ) ) {
100
+ $file = wpmc_clean_uploaded_filename( $file );
101
+ $uploads = wp_upload_dir();
102
+ $parsedURL = parse_url( $uploads['baseurl'] );
103
+ $pinfo = pathinfo( $file );
104
+ $regex_match_file = '(' . $pinfo['dirname'] . '/' . $pinfo['filename'] . "(\\-[0-9]{1,8}x[0-9]{1,8})?\\." . $pinfo['extension'] . ')';
105
+
106
+ // SUPER STRICT MODE
107
+ // $regex = addcslashes('=[\'"](?:(?:http(?:s)?\\:)?//'
108
+ // . preg_quote( $parsedURL['host'] ) . ')?'
109
+ // . preg_quote( $parsedURL['path'] ) . '/'
110
+ // . $regex_match_file . '(?:\\?[^\'"]*)*[\'"]', '/' );
111
+
112
+ // NORMAL REGEX
113
+ $regex = addcslashes( preg_quote( $parsedURL['path']) . '/' . $regex_match_file . '(?:\\?[^\'"]*)*[\'"]', '/' );
114
+ $regex_mysql = str_replace('(?:', '(', $regex);
115
+ $sql = $wpdb->prepare( "SELECT COUNT(*)
116
+ FROM $wpdb->posts
117
+ WHERE post_type <> 'revision'
118
+ AND post_type <> 'attachment'
119
+ AND post_content REGEXP %s", $regex_mysql );
120
+ $mediaCount = $wpdb->get_var( $sql );
121
+ if ( $wpmc_debug && $mediaCount > 0 )
122
+ error_log( "File {$file} found in post_content, $mediaCount time(s)" );
123
+ if ( $mediaCount > 0 )
124
+ return true;
125
+
126
+ if ( !empty( $mediaId ) ) {
127
+ $sql = $wpdb->prepare( "SELECT COUNT(*)
128
+ FROM $wpdb->posts
129
+ WHERE post_type <> 'revision'
130
+ AND post_type <> 'attachment'
131
+ AND post_content LIKE %s", "%wp-image-$mediaId%" );
132
+ $mediaCount = $wpdb->get_var( $sql );
133
+ if ( $wpmc_debug && $mediaCount > 0 )
134
+ error_log( "Media {$mediaId} found in post_content, $mediaCount time(s)" );
135
+ if ( $mediaCount > 0 )
136
+ return true;
137
+ }
138
+ }
139
+
140
+ // Shortcode analysis
141
+ global $shortcode_tags;
142
+ $active_tags = array_keys( $shortcode_tags );
143
+ if ( !empty( $active_tags ) ) {
144
+ $post_contents = get_transient( 'wpmc_posts_with_shortcode' );
145
+ if ( $post_contents === false ) {
146
+
147
+ $post_contents = array();
148
+
149
+ // Resolve shortcodes from posts
150
+ if ( $shortcode_support ) {
151
+ $query = array();
152
+ $query[] = "SELECT ID, post_content FROM {$wpdb->posts}";
153
+ $query[] = "WHERE post_type <> 'revision' AND post_type <> 'attachment'";
154
+ $sub_query = array();
155
+ foreach ( $active_tags as $tag ) {
156
+ $sub_query[] = "post_content LIKE '%[" . esc_sql( $wpdb->esc_like( $tag ) ) . "%'";
157
+ }
158
+ $query[] = "AND (" . implode ( " OR ", $sub_query ) . ")";
159
+ $sql = join( ' ', $query );
160
+ $results = $wpdb->get_results( $sql );
161
+ foreach ( $results as $key => $data ) {
162
+ $post_contents['post_' . $data->ID] = do_shortcode( $data->post_content );
163
+ }
164
+ }
165
+
166
+ // Read Widgets
167
+ if ( get_option( 'wpmc_widgets', false ) ) {
168
+ global $wp_registered_widgets;
169
+ $active_widgets = get_option( 'sidebars_widgets' );
170
+ foreach ( $active_widgets as $sidebar_name => $sidebar_widgets ) {
171
+ if ( $sidebar_name != 'wp_inactive_widgets' && !empty( $sidebar_widgets ) && is_array( $sidebar_widgets ) ) {
172
+ $i = 0;
173
+ foreach ( $sidebar_widgets as $widget_instance ) {
174
+ $widget_class = $wp_registered_widgets[$widget_instance]['callback'][0]->option_name;
175
+ $instance_id = $wp_registered_widgets[$widget_instance]['params'][0]['number'];
176
+ $widget_data = get_option($widget_class);
177
+ if ( !empty( $widget_data[$instance_id]['text'] ) ) {
178
+
179
+ // Resolve Widgets or just get them
180
+ if ( $shortcode_support )
181
+ $post_contents['widget_' . $i] = do_shortcode( $widget_data[$instance_id]['text'] );
182
+ else
183
+ $post_contents['widget_' . $i] = $widget_data[$instance_id]['text'];
184
+ }
185
+ $i++;
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ if ( !empty( $post_contents ) )
192
+ set_transient( 'wpmc_posts_with_shortcode', $post_contents, 2 * 60 * 60 );
193
+ }
194
+
195
+ if ( !empty( $post_contents ) ) {
196
+ foreach ( $post_contents as $key => $content ) {
197
+ $found = preg_match( '/' . $regex . '/i', $content );
198
+ if ( $wpmc_debug && $found )
199
+ error_log( "File Cleaner: {$file} found in {$key} shortcode or widget" );
200
+ if ( $found )
201
+ return true;
202
+ }
203
+ }
204
+ }
205
+ return false;
206
+ }
207
+
208
+ ?>
wpmc_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
+ ?>