PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.5.2
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.5.2
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / optimizations / revisions.php

revisions.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.5.2, at optimizations/revisions.php

260 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5 class WP_Optimization_revisions extends WP_Optimization {
6
7 public $ui_sort_order = 1000;
8
9 public $available_for_auto = true;
10
11 public $auto_default = true;
12
13 public $setting_default = true;
14
15 public $available_for_saving = true;
16
17 /**
18 * Prepare data for preview widget.
19 *
20 * @param array $params
21 *
22 * @return array
23 */
24 public function preview($params) {
25
26 $retention_subquery = '';
27
28 if ('true' === $this->retention_enabled) {
29 $retention_subquery = ' and post_modified < NOW() - INTERVAL ' . $this->retention_period . ' WEEK';
30 }
31
32 // get data requested for preview.
33 // `$this->wpdb->prepare` is global `$wpdb->prepare`
34 // phpcs:disable
35 $sql = $this->wpdb->prepare(
36 "SELECT `ID`, `post_title`, `post_date`".
37 " FROM `" . $this->wpdb->posts . "`".
38 " WHERE post_type = 'revision'".
39 $retention_subquery.
40 " ORDER BY `ID` LIMIT %d, %d;",
41 array(
42 $params['offset'],
43 $params['limit'],
44 )
45 );
46
47 $posts = $this->wpdb->get_results($sql, ARRAY_A);
48 // phpcs:enable
49
50 // fix empty revision titles.
51 if (!empty($posts)) {
52 foreach ($posts as $key => $post) {
53 $posts[$key]['post_title'] = '' === $post['post_title'] ? '('.__('no title', 'wp-optimize').')' : $post['post_title'];
54 }
55 }
56
57 // get total count revisions for optimization.
58 $sql = "SELECT COUNT(*) FROM `" . $this->wpdb->posts . "` WHERE post_type = 'revision'".$retention_subquery.";";
59
60 $total = $this->wpdb->get_var($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- SQL statement is safe
61
62 return array(
63 'id_key' => 'ID',
64 'columns' => array(
65 'ID' => __('ID', 'wp-optimize'),
66 'post_title' => __('Title', 'wp-optimize'),
67 'post_date' => __('Date', 'wp-optimize'),
68 ),
69 'offset' => $params['offset'],
70 'limit' => $params['limit'],
71 'total' => $total,
72 'data' => $this->htmlentities_array($posts, array('ID')),
73 'message' => $total > 0 ? '' : __('No post revisions found', 'wp-optimize'),
74 );
75 }
76
77 /**
78 * Do actions after optimize() function.
79 */
80 public function after_optimize() {
81 // translators: %s is number of post revisions deleted
82 $message = sprintf(_n('%s post revision deleted', '%s post revisions deleted', $this->processed_count, 'wp-optimize'), number_format_i18n($this->processed_count));
83
84 if ($this->is_multisite_mode()) {
85 // translators: %s is number of sites
86 $message .= ' ' . sprintf(_n('across %s site', 'across %s sites', count($this->blogs_ids), 'wp-optimize'), count($this->blogs_ids));
87 }
88
89 $this->logger->info($message);
90 $this->register_output($message);
91 }
92
93 /**
94 * Do optimization.
95 */
96 public function optimize() {
97
98 if ('true' === $this->revisions_retention_enabled) {
99 $this->optimize_by_posts();
100 return;
101 }
102
103 $clean = "DELETE FROM `" . $this->wpdb->posts . "` WHERE post_type = 'revision'";
104
105 if ('true' === $this->retention_enabled) {
106 $clean .= '
107 AND post_modified < NOW() - INTERVAL ' . $this->retention_period . ' WEEK';
108 }
109
110 // if posted ids in params, then remove only selected items. used by preview widget.
111 if (isset($this->data['ids'])) {
112 $clean .= ' AND `ID` in ('.join(',', $this->data['ids']).')';
113 }
114
115 $clean .= ';';
116
117 $revisions = $this->query($clean);
118 $this->processed_count += $revisions;
119
120 // clean orphaned post meta.
121 $clean = "DELETE pm FROM `" . $this->wpdb->postmeta . "` pm LEFT JOIN `" . $this->wpdb->posts . "` p ON pm.post_id = p.ID WHERE p.ID IS NULL";
122 $this->query($clean);
123 }
124
125 /**
126 * Optimize post revisions but keep `x` revisions for each post
127 */
128 private function optimize_by_posts() {
129 // get data requested for preview.
130 $sql = "SELECT `post_parent`, GROUP_CONCAT(`ID`)".
131 " FROM `" . $this->wpdb->posts . "`".
132 " WHERE post_type = 'revision'".
133 " GROUP BY `post_parent`".
134 " ORDER BY `post_parent`";
135
136 $results = $this->wpdb->get_results($sql, ARRAY_N); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Safe no user input used
137 $post_parents = array();
138 $revisions = '';
139 foreach ($results as $row) {
140 array_push($post_parents, $row[0]);
141 $tmp = explode(',', $row[1]);
142 rsort($tmp);
143 $tmp = implode(',', array_slice($tmp, $this->revisions_retention_count));
144 if ('' !== $tmp) {
145 $revisions .= $tmp . ',';
146 }
147 }
148 $revisions = rtrim($revisions, ',');
149 $revisions = empty($revisions) ? array() : explode(',', $revisions);
150
151 while (count($revisions) > 0) {
152 $delete_this_time = array_splice($revisions, 0, min(count($revisions), 250));
153 $clean = "DELETE FROM `" . $this->wpdb->posts . "` WHERE `ID` IN (" . implode(',', $delete_this_time) . ")";
154 $count = $this->query($clean);
155 $this->processed_count += $count;
156 }
157
158 // clean orphaned post meta.
159 $clean = "DELETE pm FROM `" . $this->wpdb->postmeta . "` pm LEFT JOIN `" . $this->wpdb->posts . "` p ON pm.post_id = p.ID WHERE p.ID IS NULL";
160 $this->query($clean);
161 }
162
163 /**
164 * Do actions after get_info() function.
165 */
166 public function after_get_info() {
167 if ($this->found_count > 0) {
168 // translators: %s is number of post revisions
169 $message = sprintf(_n('%s post revision in your database', '%s post revisions in your database', $this->found_count, 'wp-optimize'), number_format_i18n($this->found_count));
170 } else {
171 $message = __('No post revisions found', 'wp-optimize');
172 }
173
174 if ($this->is_multisite_mode()) {
175 // translators: %s is number of sites
176 $message .= ' '.sprintf(_n('across %s site', 'across %s sites', count($this->blogs_ids), 'wp-optimize'), count($this->blogs_ids));
177 }
178
179 // add preview link to message.
180 if ($this->found_count > 0) {
181 $message = $this->get_preview_link($message);
182 }
183
184 $this->register_output($message);
185 }
186
187 public function get_info() {
188 if ('true' === $this->revisions_retention_enabled) {
189 $sql = "SELECT `post_parent`, GROUP_CONCAT(`ID`)".
190 " FROM `" . $this->wpdb->posts . "`".
191 " WHERE post_type = 'revision'".
192 " GROUP BY `post_parent`".
193 " ORDER BY `post_parent`";
194
195 $results = $this->wpdb->get_results($sql, ARRAY_N); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Safe, no user input used
196 $post_parents = array();
197 $revisions = '';
198 foreach ($results as $row) {
199 array_push($post_parents, $row[0]);
200 $tmp = explode(',', $row[1]);
201 rsort($tmp);
202 $tmp = implode(',', array_slice($tmp, $this->revisions_retention_count));
203 if (!empty($tmp)) {
204 $revisions .= $tmp . ',';
205 }
206 }
207 $revisions = rtrim($revisions, ',');
208 if (!empty($revisions)) {
209 $revisions = explode(',', $revisions);
210 $this->found_count += count($revisions);
211 }
212 } else {
213 $sql = "SELECT COUNT(*) FROM `" . $this->wpdb->posts . "` WHERE post_type = 'revision'";
214
215 if ('true' === $this->retention_enabled) {
216 $sql .= ' and post_modified < NOW() - INTERVAL ' . $this->retention_period . ' WEEK';
217 }
218 $sql .= ';';
219
220 $revisions = $this->wpdb->get_var($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- SQL statement is safe
221
222 $this->found_count += $revisions;
223 }
224 }
225
226 /**
227 * Returns appropriate label string based on option value
228 *
229 * @return string
230 */
231 public function settings_label() {
232
233 if ('true' === $this->retention_enabled && 'true' === $this->revisions_retention_enabled) {
234 // translators: %1$d is revisions retention period in weeks, %2$d is revisions retention count
235 return sprintf(__('Clean post revisions which are older than %1$d weeks and keep at least %2$d revisions', 'wp-optimize'), $this->retention_period, $this->revisions_retention_count);
236 }
237
238 if ('true' === $this->retention_enabled && 'false' === $this->revisions_retention_enabled) {
239 // translators: %d is revisions retention period in weeks
240 return sprintf(__('Clean post revisions which are older than %d weeks', 'wp-optimize'), $this->retention_period);
241 }
242
243 if ('false' === $this->retention_enabled && 'true' === $this->revisions_retention_enabled) {
244 // translators: %d is number of revisions to retain
245 return sprintf(__('Clean post revisions but keep at least %d revisions', 'wp-optimize'), $this->revisions_retention_count);
246 }
247
248 return __('Clean all post revisions', 'wp-optimize');
249 }
250
251 /**
252 * Return description
253 *
254 * @return string
255 */
256 public function get_auto_option_description() {
257 return __('Clean all post revisions', 'wp-optimize');
258 }
259 }
260