PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.1.9
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.1.9
3.2.2 3.2.3 3.2.1 3.2.0 3.1.9 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.9 trunk 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.3 1.1.4 1.1.5 All 174 releases
master-addons / inc / admin / popup-builder / class-popup-list-table.php

class-popup-list-table.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.1.9, at inc/admin/popup-builder/class-popup-list-table.php

293 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace MasterAddons\Inc\Admin\PopupBuilder;
3
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 if (!class_exists('WP_List_Table')) {
9 require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
10 }
11
12 class Popup_List_Table extends \WP_List_Table {
13
14 public function __construct() {
15 parent::__construct([
16 'singular' => __('Popup', 'master-addons'),
17 'plural' => __('Popups', 'master-addons'),
18 'ajax' => false
19 ]);
20 }
21
22 public function get_columns() {
23 $columns = [
24 'cb' => '<input type="checkbox" />',
25 'name' => __('Name', 'master-addons'),
26 'type' => __('Type', 'master-addons'),
27 'status' => __('Status', 'master-addons'),
28 'views' => __('Views', 'master-addons'),
29 'conversions' => __('Conversions', 'master-addons'),
30 'created_at' => __('Created', 'master-addons'),
31 ];
32
33 return $columns;
34 }
35
36 public function get_sortable_columns() {
37 $sortable_columns = [
38 'name' => ['name', true],
39 'type' => ['type', false],
40 'status' => ['status', false],
41 'views' => ['views', false],
42 'conversions' => ['conversions', false],
43 'created_at' => ['created_at', false],
44 ];
45
46 return $sortable_columns;
47 }
48
49 public function prepare_items() {
50 $columns = $this->get_columns();
51 $hidden = [];
52 $sortable = $this->get_sortable_columns();
53
54 $this->_column_headers = [$columns, $hidden, $sortable];
55
56 $per_page = $this->get_items_per_page('popups_per_page', 20);
57 $current_page = $this->get_pagenum();
58
59 $data = $this->get_popups($per_page, $current_page);
60 $total_items = $this->get_popups_count();
61
62 $this->set_pagination_args([
63 'total_items' => $total_items,
64 'per_page' => $per_page
65 ]);
66
67 $this->items = $data;
68 }
69
70 private function get_popups($per_page = 20, $page_number = 1) {
71 global $wpdb;
72
73 $table_name = $wpdb->prefix . 'jltma_popups';
74
75 $sql = "SELECT * FROM $table_name";
76
77 // ORDER BY column and direction cannot be bound via prepare(); resolve
78 // them to a fixed whitelist so no user-supplied string reaches the query.
79 $allowed_orderby = array_keys( $this->get_sortable_columns() );
80 $orderby = 'created_at';
81 if ( ! empty( $_REQUEST['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only list table ordering
82 $requested = sanitize_key( wp_unslash( $_REQUEST['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only list table ordering
83 if ( in_array( $requested, $allowed_orderby, true ) ) {
84 $orderby = $requested;
85 }
86 }
87
88 $order = 'DESC';
89 if ( ! empty( $_REQUEST['order'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only list table ordering
90 $requested_order = strtoupper( sanitize_key( wp_unslash( $_REQUEST['order'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only list table ordering
91 if ( in_array( $requested_order, array( 'ASC', 'DESC' ), true ) ) {
92 $order = $requested_order;
93 }
94 }
95
96 // $orderby and $order are now guaranteed whitelist values, not raw input.
97 $sql .= " ORDER BY {$orderby} {$order}";
98
99 $offset = ( $page_number - 1 ) * $per_page;
100 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- custom popups table: LIMIT/OFFSET bound via prepare(); ORDER BY sanitized with esc_sql(); table name cannot be parameterized
101 $results = $wpdb->get_results(
102 $wpdb->prepare( $sql . ' LIMIT %d OFFSET %d', $per_page, $offset ),
103 'ARRAY_A'
104 );
105 // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter
106
107 return $results ? $results : [];
108 }
109
110 private function get_popups_count() {
111 global $wpdb;
112 $table_name = $wpdb->prefix . 'jltma_popups';
113
114 return (int) $wpdb->get_var( "SELECT COUNT(*) FROM $table_name" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- custom popups table count; table name from $wpdb->prefix, not user input
115 }
116
117 public function column_cb($item) {
118 return sprintf(
119 '<input type="checkbox" name="popup[]" value="%s" />',
120 $item['id']
121 );
122 }
123
124 public function column_name($item) {
125 $edit_url = admin_url('admin.php?page=ma-popups&action=edit&popup_id=' . $item['id']);
126 $delete_url = wp_nonce_url(
127 admin_url('admin.php?page=ma-popups&action=delete&popup_id=' . $item['id']),
128 'delete_popup_' . $item['id']
129 );
130
131 $actions = [
132 'edit' => sprintf('<a href="%s">%s</a>', $edit_url, __('Edit', 'master-addons')),
133 'duplicate' => sprintf(
134 '<a href="#" class="ma-popup-duplicate" data-id="%s">%s</a>',
135 $item['id'],
136 __('Duplicate', 'master-addons')
137 ),
138 'delete' => sprintf(
139 '<a href="#" class="ma-popup-delete" data-id="%s">%s</a>',
140 $item['id'],
141 __('Delete', 'master-addons')
142 ),
143 ];
144
145 return sprintf('%1$s %2$s',
146 '<strong><a href="' . $edit_url . '">' . esc_html($item['name']) . '</a></strong>',
147 $this->row_actions($actions)
148 );
149 }
150
151 public function column_type($item) {
152 $types = [
153 'notification' => __('Notification Bar', 'master-addons'),
154 'modal' => __('Modal', 'master-addons'),
155 'slide-in' => __('Slide-in', 'master-addons'),
156 'full-screen' => __('Full Screen', 'master-addons'),
157 'corner' => __('Corner Popup', 'master-addons'),
158 ];
159
160 return isset($types[$item['type']]) ? $types[$item['type']] : $item['type'];
161 }
162
163 public function column_trigger($item) {
164 if (!empty($item['settings'])) {
165 $settings = json_decode($item['settings'], true);
166
167 if (isset($settings['trigger_type'])) {
168 $triggers = [
169 'load' => __('On Load', 'master-addons'),
170 'scroll' => __('On Scroll', 'master-addons'),
171 'element-scroll' => __('Element Scroll', 'master-addons'),
172 'exit' => __('Exit Intent', 'master-addons'),
173 'inactivity' => __('Inactivity', 'master-addons'),
174 'click' => __('On Click', 'master-addons'),
175 ];
176
177 return isset($triggers[$settings['trigger_type']])
178 ? $triggers[$settings['trigger_type']]
179 : $settings['trigger_type'];
180 }
181 }
182
183 return __('On Load', 'master-addons');
184 }
185
186 public function column_status($item) {
187 $status_class = $item['status'] === 'active' ? 'active' : 'inactive';
188 $status_text = $item['status'] === 'active'
189 ? __('Active', 'master-addons')
190 : __('Inactive', 'master-addons');
191
192 return sprintf(
193 '<a href="#" class="ma-popup-status ma-status-%s" data-id="%s">%s</a>',
194 $status_class,
195 $item['id'],
196 $status_text
197 );
198 }
199
200 public function column_views($item) {
201 return number_format_i18n($item['views']);
202 }
203
204 public function column_conversions($item) {
205 $conversions = (int) $item['conversions'];
206 $views = (int) $item['views'];
207
208 if ($views > 0) {
209 $rate = ($conversions / $views) * 100;
210 return sprintf(
211 '%s <span class="conversion-rate">(%s%%)</span>',
212 number_format_i18n($conversions),
213 number_format_i18n($rate, 2)
214 );
215 }
216
217 return number_format_i18n($conversions);
218 }
219
220 public function column_created_at($item) {
221 return date_i18n(get_option('date_format'), strtotime($item['created_at']));
222 }
223
224 public function get_bulk_actions() {
225 $actions = [
226 'bulk-delete' => __('Delete', 'master-addons'),
227 'bulk-activate' => __('Activate', 'master-addons'),
228 'bulk-deactivate' => __('Deactivate', 'master-addons'),
229 ];
230
231 return $actions;
232 }
233
234 public function process_bulk_action() {
235 if ('delete' === $this->current_action()) {
236 $popup_id = isset( $_GET['popup_id'] ) ? absint( $_GET['popup_id'] ) : 0;
237
238 if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'delete_popup_' . $popup_id ) ) {
239 global $wpdb;
240 $table_name = $wpdb->prefix . 'jltma_popups';
241
242 $wpdb->delete( $table_name, [ 'id' => $popup_id ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct query required for custom table delete
243
244 wp_safe_redirect(admin_url('admin.php?page=ma-popups&deleted=1'));
245 exit;
246 }
247 }
248
249 if (isset($_POST['action']) && $_POST['action'] != -1) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- bulk action, nonce checked per-action below
250 $action = sanitize_key( wp_unslash( $_POST['action'] ) );
251 } elseif (isset($_POST['action2']) && $_POST['action2'] != -1) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- bulk action, nonce checked per-action below
252 $action = sanitize_key( wp_unslash( $_POST['action2'] ) );
253 } else {
254 return;
255 }
256
257 if (!isset($_POST['popup']) || !is_array($_POST['popup'])) {
258 return;
259 }
260
261 $popup_ids = array_map('intval', $_POST['popup']);
262
263 global $wpdb;
264 $table_name = $wpdb->prefix . 'jltma_popups';
265
266 switch ($action) {
267 case 'bulk-delete':
268 foreach ($popup_ids as $id) {
269 $wpdb->delete( $table_name, [ 'id' => $id ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct query required for custom table bulk delete
270 }
271 break;
272
273 case 'bulk-activate':
274 foreach ($popup_ids as $id) {
275 $wpdb->update( $table_name, [ 'status' => 'active' ], [ 'id' => $id ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct query required for custom table bulk status update
276 }
277 break;
278
279 case 'bulk-deactivate':
280 foreach ($popup_ids as $id) {
281 $wpdb->update( $table_name, [ 'status' => 'inactive' ], [ 'id' => $id ] ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct query required for custom table bulk status update
282 }
283 break;
284 }
285
286 wp_safe_redirect(admin_url('admin.php?page=ma-popups'));
287 exit;
288 }
289
290 public function no_items() {
291 esc_html_e('No popups found. Create your first popup to get started!', 'master-addons');
292 }
293 }