PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 2.41
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v2.41
3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 2.44 All 141 releases
photonic / Admin / Shortcode_Usage.php

Shortcode_Usage.php in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 2.41, at Admin/Shortcode_Usage.php

272 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Photonic_Plugin\Admin;
3
4 use WP_List_Table;
5
6 /**
7 * Generates a table showing the usage of the <code>gallery</code> shortcode for Photonic.
8 * This is used as an interim conversion step for switching shortcodes to a different, non-<code>gallery</code> shortcode.
9 * This is crucial for Gutenberg support, as the "Convert to Blocks" capability of Gutenberg is broken (https://github.com/WordPress/gutenberg/issues/10674).
10 *
11 * @since 2.10
12 */
13
14 if(!class_exists('WP_List_Table')){
15 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
16 }
17
18 class Shortcode_Usage extends WP_List_Table {
19 public $items = [];
20 public $tag;
21 var $per_page = 100;
22
23 public function __construct($args = []) {
24 parent::__construct([
25 'singular' => 'post',
26 'plural' => 'posts',
27 'ajax' => false,
28 ]);
29 $this->tag = 'gallery';
30 add_filter('removable_query_args', [&$this, 'remove_args']);
31 }
32
33 /**
34 * List of columns displayed in the table
35 *
36 * @return array
37 */
38 public function get_columns() {
39 return [
40 'cb' => '<input type="checkbox" />',
41 'title' => esc_html__('Post Title', 'photonic'),
42 'type' => esc_html__('Post Type', 'photonic'),
43 'status' => esc_html__('Post Status', 'photonic'),
44 'shortcodes' => esc_html__('Gallery Shortcodes used by Photonic', 'photonic'),
45 ];
46 }
47
48 /**
49 * List of columns sortable by the user
50 *
51 * @return array
52 */
53 public function get_sortable_columns() {
54 return [
55 'type' => ['type', true],
56 'title' => ['title', true],
57 'status' => ['status', false],
58 ];
59 }
60
61 /**
62 * Main method to build out the list items
63 */
64 public function prepare_items() {
65 $this->_column_headers = [
66 $this->get_columns(),
67 [],
68 $this->get_sortable_columns(),
69 'title'
70 ];
71
72 $this->process_bulk_action();
73
74 global $wpdb;
75 $results = $wpdb->get_results(
76 "SELECT ID, post_type, post_status, post_title, post_content FROM {$wpdb->posts} where post_type not in ('revision', 'attachment', 'nav_menu_item', 'oembed_cache') and post_status not in ('trash', 'inherit')",
77 ARRAY_A
78 );
79
80 $pattern = get_shortcode_regex([$this->tag]);
81 $types = ['default', 'wp', 'flickr', 'smugmug', 'picasa', 'google', 'zenfolio', 'instagram'];
82 $layouts = ['square', 'circle', 'random', 'masonry', 'mosaic', 'strip-above', 'strip-below', 'strip-right', 'no-strip'];
83 $data = [];
84
85 foreach ($results as $post) {
86 preg_match_all('/' . $pattern . '/s', $post['post_content'], $matches, PREG_OFFSET_CAPTURE);
87 if (!empty($matches) && !empty($matches[0]) && !empty($matches[1]) && !empty($matches[2]) && !empty($matches[3])) {
88 $to_change = [];
89 foreach ($matches[1] as $instance => $start) {
90 if ($start[0] === '') {
91 if (!empty($matches[3][$instance])) {
92 $attributes = shortcode_parse_atts($matches[3][$instance][0]);
93 if ((!empty($attributes['type']) && in_array($attributes['type'], $types)) ||
94 (empty($attributes['type']) && !empty($attributes['style']) && in_array($attributes['style'], $layouts))) {
95 $to_change[] = "<code>" . esc_html($matches[0][$instance][0]) . "</code>";
96 }
97 }
98 }
99 }
100 if (!empty($to_change)) {
101 $data[] = [
102 'id' => $post['ID'],
103 'type' => $post['post_type'],
104 'status' => $post['post_status'],
105 'title' => $post['post_title'],
106 'shortcodes' => $to_change,
107 ];
108 }
109 }
110 }
111 $current_page = $this->get_pagenum();
112 $total_items = count($data);
113 $data = array_slice($data, (($current_page-1) * $this->per_page), $this->per_page);
114 $this->items = $data;
115 $this->set_pagination_args([
116 'total_items' => $total_items,
117 'per_page' => $this->per_page,
118 'total_pages' => ceil($total_items/$this->per_page),
119 ]);
120 }
121
122 /**
123 * Default output for a column, if a column-specific output is not defined
124 *
125 * @param object $item
126 * @param string $column_name
127 * @return null|string
128 */
129 protected function column_default($item, $column_name) {
130 return isset($item[$column_name]) ? esc_html($item[$column_name]) : null;
131 }
132
133 /**
134 * Adds the "Checkbox" column for bulk actions
135 *
136 * @param object $item
137 * @return string
138 */
139 protected function column_cb($item) {
140 return sprintf('<input type="checkbox" name="photonic_post[]" value="%s" />', $item['id']);
141 }
142
143 protected function column_title($item) {
144 $actions = [
145 'edit' => '<a href="' . get_edit_post_link($item['id']) . '">' . esc_html__('Edit', 'photonic') . '</a>',
146 'view' => '<a href="' . get_permalink($item['id']) . '">' . esc_html__('View', 'photonic') . '</a>',
147 'replace_shortcode_individual' => '<a href="'.admin_url('admin.php?page=photonic-gutenberg&action=replace_shortcode_individual&photonic_post_id='.$item['id']).'" class="photonic-shortcode-replace">' . esc_html__('Replace Shortcodes', 'photonic') . '</a>',
148 ];
149 return $item['title'] . $this->row_actions($actions);
150 }
151
152 protected function column_shortcodes($item) {
153 return implode("<br/>\n", $item['shortcodes']);
154 }
155
156 public function no_items() {
157 echo sprintf(esc_html__('No instances of Photonic found with the %s shortcode', 'photonic'), "<code>{$this->tag}</code>");
158 }
159
160 function get_bulk_actions() {
161 $actions = [
162 'replace_shortcode' => esc_html__('Replace Shortcode', 'photonic')
163 ];
164 return $actions;
165 }
166
167 function process_bulk_action() {
168 if ('replace_shortcode' === $this->current_action()) {
169 if (!empty($_POST['photonic_post'])) {
170 $post_ids = $_POST['photonic_post'];
171 $post_ids = array_map(function ($v) {
172 return "'" . esc_sql($v) . "'";
173 }, $post_ids);
174 $post_ids = implode(',', $post_ids);
175 }
176 }
177 else if ('replace_shortcode_individual' === $this->current_action()) {
178 if (!empty($_REQUEST['photonic_post_id'])) {
179 $post_ids = esc_sql($_REQUEST['photonic_post_id']);
180 }
181 }
182
183 if (!empty($post_ids)) {
184 global $wpdb, $photonic_alternative_shortcode;
185 if (empty($photonic_alternative_shortcode) || strtolower($photonic_alternative_shortcode) === 'gallery') {
186 echo "<div class='notice notice-error is-dismissible'>\n<p>\n";
187 echo sprintf(esc_html__('Cannot update the posts because a custom shortcode has not been set up under %s.', 'photonic'),
188 '<strong><em>Photonic &rarr; Settings &rarr; Generic Options &rarr; Generic Settings &rarr; Custom Shortcode</em></strong>');
189 echo "\n</p>\n</div>\n";
190 return;
191 }
192
193 $r_tag = $photonic_alternative_shortcode;
194 $o_len = strlen($this->tag);
195 $r_len = strlen($r_tag);
196
197 $results = $wpdb->get_results(
198 "SELECT ID, post_type, post_status, post_title, post_content FROM {$wpdb->posts} where post_type not in ('revision', 'attachment', 'nav_menu_item', 'oembed_cache') and post_status not in ('trash', 'inherit') and ID in (" . $post_ids . ")",
199 ARRAY_A
200 );
201 $pattern = get_shortcode_regex([$this->tag]);
202 $types = ['default', 'wp', 'flickr', 'smugmug', 'picasa', 'google', 'zenfolio', 'instagram'];
203 $layouts = ['square', 'circle', 'random', 'masonry', 'mosaic', 'strip-above', 'strip-below', 'strip-right', 'no-strip'];
204
205 $count = 0;
206 $got_error = false;
207 foreach ($results as $id => $post) {
208 preg_match_all('/' . $pattern . '/s', $post['post_content'], $matches, PREG_OFFSET_CAPTURE);
209 $changed = false;
210 if (!empty($matches) && !empty($matches[0]) && !empty($matches[1]) && !empty($matches[2]) && !empty($matches[3])) {
211 $instances = [];
212 $init = $post['post_content'];
213 foreach ($matches[1] as $instance => $start) {
214 if ($start[0] === '') {
215 if (!empty($matches[3][$instance])) {
216 $attributes = shortcode_parse_atts($matches[3][$instance][0]);
217 if ((!empty($attributes['type']) && in_array($attributes['type'], $types)) ||
218 (empty($attributes['type']) && !empty($attributes['style']) && in_array($attributes['style'], $layouts))) {
219 $offset = count($instances) * ($r_len - $o_len);
220 $upto = substr($init, 0, $matches[0][$instance][1] + $offset);
221 $instances[] = $instance;
222 $replacement = str_replace('[' . $this->tag, '[' . $r_tag, $matches[0][$instance][0]);
223 $after = substr($init, $matches[0][$instance][1] + $offset + strlen($matches[0][$instance][0]));
224 $init = $upto . $replacement . $after;
225 $changed = true;
226 }
227 }
228 }
229 }
230 if ($changed) {
231 $update = $wpdb->update($wpdb->posts, ['post_content' => $init], ['ID' => $post['ID']]);
232 if ($update === false) {
233 $got_error = true;
234 }
235 else if ($update === 0) {
236 }
237 else {
238 $count++;
239 }
240 }
241 }
242 }
243 if ($got_error) {
244 $type = 'error';
245 $message = esc_html__('Failed to replace shortcodes due to an error. Please open a support ticket.', 'photonic');
246 }
247 else if ($count === 0) {
248 $type = 'warning';
249 $message = esc_html__('0 replacements made. If this is not what you were expecting please open a support ticket.', 'photonic');
250 }
251 else {
252 $type = 'success';
253 $message = esc_html(sprintf(_n(
254 '%d post updated with the shortcode replacement.',
255 '%d posts updated with the shortcode replacement.',
256 $count, 'photonic'),
257 $count)
258 );
259 }
260
261 echo "<div class='notice notice-$type is-dismissible'>\n<p>\n";
262 echo $message;
263 echo "\n</p>\n</div>\n";
264 }
265 }
266
267 function remove_args($args) {
268 $args[] = 'action';
269 $args[] = 'photonic_post_id';
270 return $args;
271 }
272 }