Header Footer Code Manager - Version 1.1.14

Version Description

2021-10-08 * FIXED: SQL Vulnerability with listing orderby * FIXED: DbDelta query * UPDATED: Compatibility with WordPress 5.8.1

Download this release

Release Info

Developer 99robots
Plugin Icon 128x128 Header Footer Code Manager
Version 1.1.14
Comparing to
See all releases

Code changes from version 1.1.13 to 1.1.14

99robots-header-footer-code-manager.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Header Footer Code Manager
4
  * Plugin URI: https://draftpress.com/products
5
  * Description: Header Footer Code Manager by 99 Robots is a quick and simple way for you to add tracking code snippets, conversion pixels, or other scripts required by third party services for analytics, tracking, marketing, or chat functions. For detailed documentation, please visit the plugin's <a href="https://draftpress.com/"> official page</a>.
6
- * Version: 1.1.13
7
  * Requires at least: 4.9
8
  * Requires PHP: 5.6.20
9
  * Author: 99robots
@@ -68,7 +68,7 @@ if (!class_exists('NNR_HFCM')) :
68
  $table_name = $wpdb->prefix . self::$nnr_hfcm_table;
69
  $charset_collate = $wpdb->get_charset_collate();
70
  $sql =
71
- "CREATE TABLE IF NOT EXISTS $table_name(
72
  `script_id` int(10) NOT NULL AUTO_INCREMENT,
73
  `name` varchar(100) DEFAULT NULL,
74
  `snippet` text,
@@ -626,10 +626,10 @@ if (!class_exists('NNR_HFCM')) :
626
  // Check nonce
627
  check_admin_referer('create-snippet');
628
  } else {
629
- if (!isset($_REQUEST['id'])) {
630
  die('Missing ID parameter.');
631
  }
632
- $id = (int)$_REQUEST['id'];
633
  }
634
  if (isset($_POST['update'])) {
635
  // Check nonce
@@ -880,7 +880,7 @@ if (!class_exists('NNR_HFCM')) :
880
  if (empty($_GET['id'])) {
881
  die('Missing ID parameter.');
882
  }
883
- $id = (int)$_GET['id'];
884
 
885
  global $wpdb;
886
  $table_name = $wpdb->prefix . self::$nnr_hfcm_table;
3
  * Plugin Name: Header Footer Code Manager
4
  * Plugin URI: https://draftpress.com/products
5
  * Description: Header Footer Code Manager by 99 Robots is a quick and simple way for you to add tracking code snippets, conversion pixels, or other scripts required by third party services for analytics, tracking, marketing, or chat functions. For detailed documentation, please visit the plugin's <a href="https://draftpress.com/"> official page</a>.
6
+ * Version: 1.1.14
7
  * Requires at least: 4.9
8
  * Requires PHP: 5.6.20
9
  * Author: 99robots
68
  $table_name = $wpdb->prefix . self::$nnr_hfcm_table;
69
  $charset_collate = $wpdb->get_charset_collate();
70
  $sql =
71
+ "CREATE TABLE $table_name (
72
  `script_id` int(10) NOT NULL AUTO_INCREMENT,
73
  `name` varchar(100) DEFAULT NULL,
74
  `snippet` text,
626
  // Check nonce
627
  check_admin_referer('create-snippet');
628
  } else {
629
+ if (empty($_REQUEST['id'])) {
630
  die('Missing ID parameter.');
631
  }
632
+ $id = (int) $_REQUEST['id'];
633
  }
634
  if (isset($_POST['update'])) {
635
  // Check nonce
880
  if (empty($_GET['id'])) {
881
  die('Missing ID parameter.');
882
  }
883
+ $id = (int) $_GET['id'];
884
 
885
  global $wpdb;
886
  $table_name = $wpdb->prefix . self::$nnr_hfcm_table;
includes/hfcm-list.php CHANGED
@@ -1,421 +1,486 @@
1
  <?php
2
- if ( ! class_exists( 'WP_List_Table' ) ) {
3
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
4
  }
5
 
6
- class Hfcm_Snippets_List extends WP_List_Table {
7
-
8
- /** Class constructor */
9
- public function __construct() {
10
-
11
- parent::__construct(
12
- array(
13
- 'singular' => esc_html__( 'Snippet', '99robots-header-footer-code-manager' ),
14
- 'plural' => esc_html__( 'Snippets', '99robots-header-footer-code-manager' ),
15
- 'ajax' => false,
16
- )
17
- );
18
- }
19
-
20
- /**
21
- * Retrieve snippets data from the database
22
- *
23
- * @param int $per_page
24
- * @param int $page_number
25
- *
26
- * @return mixed
27
- */
28
- public static function get_snippets( $per_page = 20, $page_number = 1, $customvar = 'all' ) {
29
-
30
- global $wpdb;
31
- $table_name = "{$wpdb->prefix}hfcm_scripts";
32
- $sql = "SELECT * FROM $table_name";
33
-
34
- if ( in_array( $customvar, array( 'inactive', 'active' ) ) ) {
35
- $sql .= " where status = '$customvar'";
36
- }
37
-
38
- if ( ! empty( $_REQUEST['orderby'] ) ) {
39
- $sql .= ' ORDER BY ' . esc_sql( $_REQUEST['orderby'] );
40
- $sql .= ! empty( $_REQUEST['order'] ) ? ' ' . esc_sql( $_REQUEST['order'] ) : ' ASC';
41
- }
42
-
43
- $sql .= " LIMIT $per_page";
44
- $sql .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;
45
-
46
- $result = $wpdb->get_results( $sql, 'ARRAY_A' );
47
- return $result;
48
- }
49
-
50
- /**
51
- * Delete a snipppet record.
52
- *
53
- * @param int $id snippet ID
54
- */
55
- public static function delete_snippet( $id ) {
56
-
57
- global $wpdb;
58
- $table_name = "{$wpdb->prefix}hfcm_scripts";
59
-
60
- $wpdb->delete(
61
- $table_name, array( 'script_id' => $id ), array( '%d' )
62
- );
63
- }
64
-
65
- /**
66
- * Activate a snipppet record.
67
- *
68
- * @param int $id snippet ID
69
- */
70
- public static function activate_snippet( $id ) {
71
-
72
- global $wpdb;
73
- $table_name = "{$wpdb->prefix}hfcm_scripts";
74
-
75
- $wpdb->update(
76
- $table_name, array(
77
- 'status' => 'active',
78
- ), array( 'script_id' => $id ), array( '%s' ), array( '%d' )
79
- );
80
- }
81
-
82
- /**
83
- * Deactivate a snipppet record.
84
- *
85
- * @param int $id snippet ID
86
- */
87
- public static function deactivate_snippet( $id ) {
88
-
89
- global $wpdb;
90
- $table_name = "{$wpdb->prefix}hfcm_scripts";
91
-
92
- $wpdb->update(
93
- $table_name, array(
94
- 'status' => 'inactive',
95
- ), array( 'script_id' => $id ), array( '%s' ), array( '%d' )
96
- );
97
- }
98
-
99
- /**
100
- * Returns the count of records in the database.
101
- *
102
- * @return null|string
103
- */
104
- public static function record_count( $customvar = 'all' ) {
105
-
106
- global $wpdb;
107
- $table_name = "{$wpdb->prefix}hfcm_scripts";
108
- $sql = "SELECT COUNT(*) FROM $table_name";
109
-
110
- if ( in_array( $customvar, array( 'inactive', 'active' ) ) ) {
111
- $sql .= " where status = '$customvar'";
112
- }
113
-
114
- return $wpdb->get_var( $sql );
115
- }
116
-
117
- /** Text displayed when no snippet data is available */
118
- public function no_items() {
119
- esc_html_e( 'No Snippets avaliable.', '99robots-header-footer-code-manager' );
120
- }
121
-
122
- /**
123
- * Render a column when no column specific method exist.
124
- *
125
- * @param array $item
126
- * @param string $column_name
127
- *
128
- * @return mixed
129
- */
130
- public function column_default( $item, $column_name ) {
131
-
132
- switch ( $column_name ) {
133
- case 'name':
134
- return esc_html( $item[ $column_name ] );
135
-
136
- case 'display_on':
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  $nnr_hfcm_display_array = array(
138
- 'All' => esc_html__( 'Site Wide', '99robots-header-footer-code-manager' ),
139
- 's_posts' => esc_html__( 'Specific Posts', '99robots-header-footer-code-manager' ),
140
- 's_pages' => esc_html__( 'Specific Pages', '99robots-header-footer-code-manager' ),
141
- 's_categories' => esc_html__( 'Specific Categories', '99robots-header-footer-code-manager' ),
142
- 's_custom_posts' => esc_html__( 'Specific Custom Post Types', '99robots-header-footer-code-manager' ),
143
- 's_tags' => esc_html__( 'Specific Tags', '99robots-header-footer-code-manager' ),
144
- 'latest_posts' => esc_html__( 'Latest Posts', '99robots-header-footer-code-manager' ),
145
- 'manual' => esc_html__( 'Shortcode Only', '99robots-header-footer-code-manager' ),
146
- );
147
-
148
- if ( 's_posts' === $item[ $column_name ] ) {
149
-
150
- $empty = 1;
151
- $s_posts = json_decode( $item['s_posts'] );
152
-
153
- foreach ( $s_posts as $id ) {
154
- if ( 'publish' === get_post_status( $id ) ) {
155
- $empty = 0;
156
- break;
157
- }
158
- }
159
- if ( $empty ) {
160
- return '<span class="hfcm-red">' . esc_html__( 'No post selected', '99robots-header-footer-code-manager' ) . '</span>';
161
- }
162
- }
163
-
164
- return esc_html( $nnr_hfcm_display_array[ $item[ $column_name ] ] );
165
-
166
- case 'location':
167
-
168
- if ( ! $item[ $column_name ] ) {
169
- return esc_html__( 'N/A', '99robots-header-footer-code-manager' );
170
- }
171
-
172
- $nnr_hfcm_locations = array(
173
- 'header' => esc_html__( 'Header', '99robots-header-footer-code-manager' ),
174
- 'before_content' => esc_html__( 'Before Content', '99robots-header-footer-code-manager' ),
175
- 'after_content' => esc_html__( 'After Content', '99robots-header-footer-code-manager' ),
176
- 'footer' => esc_html__( 'Footer', '99robots-header-footer-code-manager' ),
177
- );
178
- return esc_html( $nnr_hfcm_locations[ $item[ $column_name ] ] );
179
-
180
- case 'device_type':
181
-
182
- if ( 'both' === $item[ $column_name ] ) {
183
- return esc_html__( 'Show on All Devices', '99robots-header-footer-code-manager' );
184
- } elseif ( 'mobile' === $item[ $column_name ] ) {
185
- return esc_html__( 'Only Mobile Devices', '99robots-header-footer-code-manager' );
186
- } elseif ( 'desktop' === $item[ $column_name ] ) {
187
- return esc_html__( 'Only Desktop', '99robots-header-footer-code-manager' );
188
- } else {
189
- return esc_html( $item[ $column_name ] );
190
- }
191
-
192
- case 'status':
193
-
194
- if ( 'inactive' === $item[ $column_name ] ) {
195
- return '<div class="nnr-switch">
196
  <label for="nnr-round-toggle' . $item['script_id'] . '">OFF</label>
197
  <input id="nnr-round-toggle' . $item['script_id'] . '" class="round-toggle round-toggle-round-flat" type="checkbox" data-id="' . $item['script_id'] . '" />
198
  <label for="nnr-round-toggle' . $item['script_id'] . '"></label>
199
  <label for="nnr-round-toggle' . $item['script_id'] . '">ON</label>
200
  </div>
201
  ';
202
- } elseif ( 'active' === $item[ $column_name ] ) {
203
- return '<div class="nnr-switch">
204
  <label for="nnr-round-toggle' . $item['script_id'] . '">OFF</label>
205
  <input id="nnr-round-toggle' . $item['script_id'] . '" class="round-toggle round-toggle-round-flat" type="checkbox" data-id="' . $item['script_id'] . '" checked="checked" />
206
  <label for="nnr-round-toggle' . $item['script_id'] . '"></label>
207
  <label for="nnr-round-toggle' . $item['script_id'] . '">ON</label>
208
  </div>
209
  ';
210
- } else {
211
- return esc_html( $item[ $column_name ] );
212
- }
213
-
214
- case 'script_id':
215
- return esc_html( $item[ $column_name ] );
216
-
217
- case 'shortcode':
218
- return '[hfcm id="' . $item['script_id'] . '"]';
219
-
220
- default:
221
- return print_r( $item, true ); // Show the whole array for troubleshooting purposes
222
- }
223
- }
224
-
225
- /**
226
- * Render the bulk edit checkbox
227
- *
228
- * @param array $item
229
- *
230
- * @return string
231
- */
232
- function column_cb( $item ) {
233
- return sprintf(
234
- '<input type="checkbox" name="snippets[]" value="%s" />', $item['script_id']
235
- );
236
- }
237
-
238
- /**
239
- * Method for name column
240
- *
241
- * @param array $item an array of DB data
242
- *
243
- * @return string
244
- */
245
- function column_name( $item ) {
246
-
247
- $delete_nonce = wp_create_nonce( 'hfcm_delete_snippet' );
248
- $edit_nonce = wp_create_nonce( 'hfcm_edit_snippet' );
249
-
250
- $title = '<strong>' . $item['name'] . '</strong>';
251
-
252
- $actions = array(
253
- 'edit' => sprintf( '<a href="?page=%s&action=%s&id=%s&_wpnonce=%s">' . esc_html__( 'Edit', '99robots-header-footer-code-manager' ) . '</a>', esc_attr( 'hfcm-update' ), 'edit', absint( $item['script_id'] ), $edit_nonce ),
254
- 'delete' => sprintf( '<a href="?page=%s&action=%s&snippet=%s&_wpnonce=%s">' . esc_html__( 'Delete', '99robots-header-footer-code-manager' ) . '</a>', esc_attr( $_REQUEST['page'] ), 'delete', absint( $item['script_id'] ), $delete_nonce ),
255
- );
256
-
257
- return $title . $this->row_actions( $actions );
258
- }
259
-
260
- /**
261
- * Associative array of columns
262
- *
263
- * @return array
264
- */
265
- function get_columns() {
266
- $columns = array(
267
- 'cb' => '<input type="checkbox" />',
268
- 'script_id' => esc_html__( 'ID', '99robots-header-footer-code-manager' ),
269
- 'status' => esc_html__( 'Status', '99robots-header-footer-code-manager' ),
270
- 'name' => esc_html__( 'Snippet Name', '99robots-header-footer-code-manager' ),
271
- 'display_on' => esc_html__( 'Display On', '99robots-header-footer-code-manager' ),
272
- 'location' => esc_html__( 'Location', '99robots-header-footer-code-manager' ),
273
- 'device_type' => esc_html__( 'Devices', '99robots-header-footer-code-manager' ),
274
- 'shortcode' => esc_html__( 'Shortcode', '99robots-header-footer-code-manager' ),
275
- );
276
-
277
- return $columns;
278
- }
279
-
280
- /**
281
- * Columns to make sortable.
282
- *
283
- * @return array
284
- */
285
- public function get_sortable_columns() {
286
-
287
- return array(
288
- 'name' => array( 'name', true ),
289
- 'script_id' => array( 'script_id', false ),
290
- );
291
- }
292
-
293
- /**
294
- * Returns an associative array containing the bulk action
295
- *
296
- * @return array
297
- */
298
- public function get_bulk_actions() {
299
-
300
- return array(
301
- 'bulk-activate' => esc_html__( 'Activate', '99robots-header-footer-code-manager' ),
302
- 'bulk-deactivate' => esc_html__( 'Deactivate', '99robots-header-footer-code-manager' ),
303
- 'bulk-delete' => esc_html__( 'Remove', '99robots-header-footer-code-manager' ),
304
- );
305
- }
306
-
307
- /**
308
- * Handles data query and filter, sorting, and pagination.
309
- */
310
- public function prepare_items() {
311
-
312
- $columns = $this->get_columns();
313
- $hidden = array();
314
- $sortable = $this->get_sortable_columns();
315
-
316
- //Retrieve $customvar for use in query to get items.
317
- $customvar = ( isset( $_REQUEST['customvar'] ) ? $_REQUEST['customvar'] : 'all');
318
- $this->_column_headers = array( $columns, $hidden, $sortable );
319
-
320
- /** Process bulk action */
321
- $this->process_bulk_action();
322
- $this->views();
323
- $per_page = $this->get_items_per_page( 'snippets_per_page', 20 );
324
- $current_page = $this->get_pagenum();
325
- $total_items = self::record_count();
326
-
327
- $this->set_pagination_args(array(
328
- 'total_items' => $total_items,
329
- 'per_page' => $per_page,
330
- ));
331
-
332
- $this->items = self::get_snippets( $per_page, $current_page, $customvar );
333
- }
334
-
335
- public function get_views() {
336
- $views = array();
337
- $current = ( ! empty( $_REQUEST['customvar'] ) ? $_REQUEST['customvar'] : 'all');
338
-
339
- //All link
340
- $class = 'all' === $current ? ' class="current"' : '';
341
- $all_url = remove_query_arg( 'customvar' );
342
- $views['all'] = "<a href='{$all_url }' {$class} >" . esc_html__( 'All', '99robots-header-footer-code-manager' ) . ' (' . $this->record_count() . ')</a>';
343
-
344
- //Foo link
345
- $foo_url = add_query_arg( 'customvar', 'active' );
346
- $class = ( 'active' === $current ? ' class="current"' : '');
347
- $views['active'] = "<a href='{$foo_url}' {$class} >" . esc_html__( 'Active', '99robots-header-footer-code-manager' ) . ' (' . $this->record_count( 'active' ) . ')</a>';
348
-
349
- //Bar link
350
- $bar_url = add_query_arg( 'customvar', 'inactive' );
351
- $class = ( 'inactive' === $current ? ' class="current"' : '');
352
- $views['inactive'] = "<a href='{$bar_url}' {$class} >" . esc_html__( 'Inactive', '99robots-header-footer-code-manager' ) . ' (' . $this->record_count( 'inactive' ) . ')</a>';
353
-
354
- return $views;
355
- }
356
-
357
- public function process_bulk_action() {
358
-
359
- //Detect when a bulk action is being triggered...
360
- if ( 'delete' === $this->current_action() ) {
361
-
362
- // In our file that handles the request, verify the nonce.
363
- $nonce = esc_attr( $_REQUEST['_wpnonce'] );
364
-
365
- if ( ! wp_verify_nonce( $nonce, 'hfcm_delete_snippet' ) ) {
366
- die( 'Go get a life script kiddies' );
367
- } else {
368
- self::delete_snippet( absint( $_GET['snippet'] ) );
369
-
370
- NNR_HFCM::hfcm_redirect( admin_url( 'admin.php?page=hfcm-list' ) );
371
- return;
372
- }
373
- }
374
-
375
- // If the delete bulk action is triggered
376
- if (
377
- ( isset( $_POST['action'] ) && 'bulk-delete' === $_POST['action'] ) ||
378
- ( isset( $_POST['action2'] ) && 'bulk-delete' === $_POST['action2'] )
379
- ) {
380
- $delete_ids = esc_sql( $_POST['snippets'] );
381
-
382
- // loop over the array of record IDs and delete them
383
- foreach ( $delete_ids as $id ) {
384
- self::delete_snippet( $id );
385
- }
386
-
387
- NNR_HFCM::hfcm_redirect( admin_url( 'admin.php?page=hfcm-list' ) );
388
- return;
389
- } elseif (
390
- ( isset( $_POST['action'] ) && 'bulk-activate' === $_POST['action'] ) ||
391
- ( isset( $_POST['action2'] ) && 'bulk-activate' === $_POST['action2'] )
392
- ) {
393
-
394
- $activate_ids = esc_sql( $_POST['snippets'] );
395
-
396
- // loop over the array of record IDs and activate them
397
- foreach ( $activate_ids as $id ) {
398
- self::activate_snippet( $id );
399
- }
400
-
401
- NNR_HFCM::hfcm_redirect( admin_url( 'admin.php?page=hfcm-list' ) );
402
- return;
403
- } elseif (
404
- ( isset( $_POST['action'] ) && 'bulk-deactivate' === $_POST['action'] ) ||
405
- ( isset( $_POST['action2'] ) && 'bulk-deactivate' === $_POST['action2'] )
406
- ) {
407
-
408
- $delete_ids = esc_sql( $_POST['snippets'] );
409
-
410
- // loop over the array of record IDs and deactivate them
411
- foreach ( $delete_ids as $id ) {
412
- self::deactivate_snippet( $id );
413
- }
414
-
415
- NNR_HFCM::hfcm_redirect( admin_url( 'admin.php?page=hfcm-list' ) );
416
-
417
- return;
418
- }
419
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  }
421
 
1
  <?php
2
+ if (!class_exists('WP_List_Table')) {
3
+ require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
4
  }
5
 
6
+ class Hfcm_Snippets_List extends WP_List_Table
7
+ {
8
+
9
+ /** Class constructor */
10
+ public function __construct()
11
+ {
12
+
13
+ parent::__construct(
14
+ array(
15
+ 'singular' => esc_html__('Snippet', '99robots-header-footer-code-manager'),
16
+ 'plural' => esc_html__('Snippets', '99robots-header-footer-code-manager'),
17
+ 'ajax' => false,
18
+ )
19
+ );
20
+ }
21
+
22
+ /**
23
+ * Retrieve snippets data from the database
24
+ *
25
+ * @param int $per_page
26
+ * @param int $page_number
27
+ *
28
+ * @return mixed
29
+ */
30
+ public static function get_snippets($per_page = 20, $page_number = 1, $customvar = 'all')
31
+ {
32
+
33
+ global $wpdb;
34
+ $table_name = "{$wpdb->prefix}hfcm_scripts";
35
+ $sql = "SELECT * FROM $table_name";
36
+
37
+ if (in_array($customvar, array('inactive', 'active'))) {
38
+ $sql .= " where status = '$customvar'";
39
+ }
40
+
41
+ if (!empty($_REQUEST['orderby'])) {
42
+ $orderby = sanitize_sql_orderby($_REQUEST['orderby']);
43
+ }
44
+ if (!empty($_REQUEST['order'])) {
45
+ $order = strtolower(sanitize_sql_orderby($_REQUEST['order']));
46
+ }
47
+
48
+ if (!empty($orderby) && in_array($orderby, ['script_id', 'name'])) {
49
+ $sql .= ' ORDER BY ' . $orderby;
50
+ if (!empty($order) && ($order == 'desc')) {
51
+ $sql .= ' DESC';
52
+ } else {
53
+ $sql .= ' ASC';
54
+ }
55
+ }
56
+
57
+ $sql .= " LIMIT $per_page";
58
+ $sql .= ' OFFSET ' . ($page_number - 1) * $per_page;
59
+
60
+ $result = $wpdb->get_results($sql, 'ARRAY_A');
61
+ return $result;
62
+ }
63
+
64
+ /**
65
+ * Delete a snipppet record.
66
+ *
67
+ * @param int $id snippet ID
68
+ */
69
+ public static function delete_snippet($id)
70
+ {
71
+ $id = (int) $id;
72
+ if (empty($id)) {
73
+ return;
74
+ }
75
+
76
+ global $wpdb;
77
+ $table_name = "{$wpdb->prefix}hfcm_scripts";
78
+
79
+ $wpdb->delete(
80
+ $table_name, array('script_id' => $id), array('%d')
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Activate a snipppet record.
86
+ *
87
+ * @param int $id snippet ID
88
+ */
89
+ public static function activate_snippet($id)
90
+ {
91
+
92
+ $id = (int) $id;
93
+ if (empty($id)) {
94
+ return;
95
+ }
96
+
97
+ global $wpdb;
98
+ $table_name = "{$wpdb->prefix}hfcm_scripts";
99
+
100
+ $wpdb->update(
101
+ $table_name, array(
102
+ 'status' => 'active',
103
+ ), array('script_id' => $id), array('%s'), array('%d')
104
+ );
105
+ }
106
+
107
+ /**
108
+ * Deactivate a snipppet record.
109
+ *
110
+ * @param int $id snippet ID
111
+ */
112
+ public static function deactivate_snippet($id)
113
+ {
114
+
115
+ $id = (int) $id;
116
+ if (empty($id)) {
117
+ return;
118
+ }
119
+
120
+ global $wpdb;
121
+ $table_name = "{$wpdb->prefix}hfcm_scripts";
122
+
123
+ $wpdb->update(
124
+ $table_name, array(
125
+ 'status' => 'inactive',
126
+ ), array('script_id' => $id), array('%s'), array('%d')
127
+ );
128
+ }
129
+
130
+ /**
131
+ * Returns the count of records in the database.
132
+ *
133
+ * @return null|string
134
+ */
135
+ public static function record_count($customvar = 'all')
136
+ {
137
+
138
+ global $wpdb;
139
+ $table_name = "{$wpdb->prefix}hfcm_scripts";
140
+ $sql = "SELECT COUNT(*) FROM $table_name";
141
+
142
+ if (in_array($customvar, array('inactive', 'active'))) {
143
+ $sql .= " where status = '$customvar'";
144
+ }
145
+
146
+ return $wpdb->get_var($sql);
147
+ }
148
+
149
+ /** Text displayed when no snippet data is available */
150
+ public function no_items()
151
+ {
152
+ esc_html_e('No Snippets avaliable.', '99robots-header-footer-code-manager');
153
+ }
154
+
155
+ /**
156
+ * Render a column when no column specific method exist.
157
+ *
158
+ * @param array $item
159
+ * @param string $column_name
160
+ *
161
+ * @return mixed
162
+ */
163
+ public function column_default($item, $column_name)
164
+ {
165
+
166
+ switch ($column_name) {
167
+ case 'name':
168
+ return esc_html($item[$column_name]);
169
+
170
+ case 'display_on':
171
  $nnr_hfcm_display_array = array(
172
+ 'All' => esc_html__('Site Wide', '99robots-header-footer-code-manager'),
173
+ 's_posts' => esc_html__('Specific Posts', '99robots-header-footer-code-manager'),
174
+ 's_pages' => esc_html__('Specific Pages', '99robots-header-footer-code-manager'),
175
+ 's_categories' => esc_html__('Specific Categories', '99robots-header-footer-code-manager'),
176
+ 's_custom_posts' => esc_html__('Specific Custom Post Types', '99robots-header-footer-code-manager'),
177
+ 's_tags' => esc_html__('Specific Tags', '99robots-header-footer-code-manager'),
178
+ 'latest_posts' => esc_html__('Latest Posts', '99robots-header-footer-code-manager'),
179
+ 'manual' => esc_html__('Shortcode Only', '99robots-header-footer-code-manager'),
180
+ );
181
+
182
+ if ('s_posts' === $item[$column_name]) {
183
+
184
+ $empty = 1;
185
+ $s_posts = json_decode($item['s_posts']);
186
+
187
+ foreach ($s_posts as $id) {
188
+ if ('publish' === get_post_status($id)) {
189
+ $empty = 0;
190
+ break;
191
+ }
192
+ }
193
+ if ($empty) {
194
+ return '<span class="hfcm-red">' . esc_html__('No post selected', '99robots-header-footer-code-manager') . '</span>';
195
+ }
196
+ }
197
+
198
+ return esc_html($nnr_hfcm_display_array[$item[$column_name]]);
199
+
200
+ case 'location':
201
+
202
+ if (!$item[$column_name]) {
203
+ return esc_html__('N/A', '99robots-header-footer-code-manager');
204
+ }
205
+
206
+ $nnr_hfcm_locations = array(
207
+ 'header' => esc_html__('Header', '99robots-header-footer-code-manager'),
208
+ 'before_content' => esc_html__('Before Content', '99robots-header-footer-code-manager'),
209
+ 'after_content' => esc_html__('After Content', '99robots-header-footer-code-manager'),
210
+ 'footer' => esc_html__('Footer', '99robots-header-footer-code-manager'),
211
+ );
212
+ return esc_html($nnr_hfcm_locations[$item[$column_name]]);
213
+
214
+ case 'device_type':
215
+
216
+ if ('both' === $item[$column_name]) {
217
+ return esc_html__('Show on All Devices', '99robots-header-footer-code-manager');
218
+ } elseif ('mobile' === $item[$column_name]) {
219
+ return esc_html__('Only Mobile Devices', '99robots-header-footer-code-manager');
220
+ } elseif ('desktop' === $item[$column_name]) {
221
+ return esc_html__('Only Desktop', '99robots-header-footer-code-manager');
222
+ } else {
223
+ return esc_html($item[$column_name]);
224
+ }
225
+
226
+ case 'status':
227
+
228
+ if ('inactive' === $item[$column_name]) {
229
+ return '<div class="nnr-switch">
230
  <label for="nnr-round-toggle' . $item['script_id'] . '">OFF</label>
231
  <input id="nnr-round-toggle' . $item['script_id'] . '" class="round-toggle round-toggle-round-flat" type="checkbox" data-id="' . $item['script_id'] . '" />
232
  <label for="nnr-round-toggle' . $item['script_id'] . '"></label>
233
  <label for="nnr-round-toggle' . $item['script_id'] . '">ON</label>
234
  </div>
235
  ';
236
+ } elseif ('active' === $item[$column_name]) {
237
+ return '<div class="nnr-switch">
238
  <label for="nnr-round-toggle' . $item['script_id'] . '">OFF</label>
239
  <input id="nnr-round-toggle' . $item['script_id'] . '" class="round-toggle round-toggle-round-flat" type="checkbox" data-id="' . $item['script_id'] . '" checked="checked" />
240
  <label for="nnr-round-toggle' . $item['script_id'] . '"></label>
241
  <label for="nnr-round-toggle' . $item['script_id'] . '">ON</label>
242
  </div>
243
  ';
244
+ } else {
245
+ return esc_html($item[$column_name]);
246
+ }
247
+
248
+ case 'script_id':
249
+ return esc_html($item[$column_name]);
250
+
251
+ case 'shortcode':
252
+ return '[hfcm id="' . $item['script_id'] . '"]';
253
+
254
+ default:
255
+ return print_r($item, true); // Show the whole array for troubleshooting purposes
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Render the bulk edit checkbox
261
+ *
262
+ * @param array $item
263
+ *
264
+ * @return string
265
+ */
266
+ function column_cb($item)
267
+ {
268
+ return sprintf(
269
+ '<input type="checkbox" name="snippets[]" value="%s" />', $item['script_id']
270
+ );
271
+ }
272
+
273
+ /**
274
+ * Method for name column
275
+ *
276
+ * @param array $item an array of DB data
277
+ *
278
+ * @return string
279
+ */
280
+ function column_name($item)
281
+ {
282
+
283
+ $delete_nonce = wp_create_nonce('hfcm_delete_snippet');
284
+ $edit_nonce = wp_create_nonce('hfcm_edit_snippet');
285
+
286
+ $title = '<strong>' . $item['name'] . '</strong>';
287
+
288
+ $page = sanitize_text_field($_REQUEST['page']);
289
+ $actions = array(
290
+ 'edit' => sprintf('<a href="?page=%s&action=%s&id=%s&_wpnonce=%s">' . esc_html__('Edit', '99robots-header-footer-code-manager') . '</a>', esc_attr('hfcm-update'), 'edit', absint($item['script_id']), $edit_nonce),
291
+ 'delete' => sprintf('<a href="?page=%s&action=%s&snippet=%s&_wpnonce=%s">' . esc_html__('Delete', '99robots-header-footer-code-manager') . '</a>', $page, 'delete', absint($item['script_id']), $delete_nonce),
292
+ );
293
+
294
+ return $title . $this->row_actions($actions);
295
+ }
296
+
297
+ /**
298
+ * Associative array of columns
299
+ *
300
+ * @return array
301
+ */
302
+ function get_columns()
303
+ {
304
+ $columns = array(
305
+ 'cb' => '<input type="checkbox" />',
306
+ 'script_id' => esc_html__('ID', '99robots-header-footer-code-manager'),
307
+ 'status' => esc_html__('Status', '99robots-header-footer-code-manager'),
308
+ 'name' => esc_html__('Snippet Name', '99robots-header-footer-code-manager'),
309
+ 'display_on' => esc_html__('Display On', '99robots-header-footer-code-manager'),
310
+ 'location' => esc_html__('Location', '99robots-header-footer-code-manager'),
311
+ 'device_type' => esc_html__('Devices', '99robots-header-footer-code-manager'),
312
+ 'shortcode' => esc_html__('Shortcode', '99robots-header-footer-code-manager'),
313
+ );
314
+
315
+ return $columns;
316
+ }
317
+
318
+ /**
319
+ * Columns to make sortable.
320
+ *
321
+ * @return array
322
+ */
323
+ public function get_sortable_columns()
324
+ {
325
+
326
+ return array(
327
+ 'name' => array('name', true),
328
+ 'script_id' => array('script_id', false),
329
+ );
330
+ }
331
+
332
+ /**
333
+ * Returns an associative array containing the bulk action
334
+ *
335
+ * @return array
336
+ */
337
+ public function get_bulk_actions()
338
+ {
339
+
340
+ return array(
341
+ 'bulk-activate' => esc_html__('Activate', '99robots-header-footer-code-manager'),
342
+ 'bulk-deactivate' => esc_html__('Deactivate', '99robots-header-footer-code-manager'),
343
+ 'bulk-delete' => esc_html__('Remove', '99robots-header-footer-code-manager'),
344
+ );
345
+ }
346
+
347
+ /**
348
+ * Handles data query and filter, sorting, and pagination.
349
+ */
350
+ public function prepare_items()
351
+ {
352
+
353
+ $columns = $this->get_columns();
354
+ $hidden = array();
355
+ $sortable = $this->get_sortable_columns();
356
+
357
+ //Retrieve $customvar for use in query to get items.
358
+ $customvar = 'all';
359
+ if (!empty($_REQUEST['customvar'])) {
360
+ $customvar = sanitize_text_field($_REQUEST['customvar']);
361
+ if (empty($customvar) || !in_array($customvar, ['inactive', 'active', 'all'])) {
362
+ $customvar = 'all';
363
+ }
364
+ }
365
+ $this->_column_headers = array($columns, $hidden, $sortable);
366
+
367
+ /** Process bulk action */
368
+ $this->process_bulk_action();
369
+ $this->views();
370
+ $per_page = $this->get_items_per_page('snippets_per_page', 20);
371
+ $current_page = $this->get_pagenum();
372
+ $total_items = self::record_count();
373
+
374
+ $this->set_pagination_args(array(
375
+ 'total_items' => $total_items,
376
+ 'per_page' => $per_page,
377
+ ));
378
+
379
+ $this->items = self::get_snippets($per_page, $current_page, $customvar);
380
+ }
381
+
382
+ public function get_views()
383
+ {
384
+ $views = array();
385
+ $current = 'all';
386
+ if (!empty($_REQUEST['customvar'])) {
387
+ $current = sanitize_text_field($_REQUEST['customvar']);
388
+ }
389
+
390
+ //All link
391
+ $class = 'all' === $current ? ' class="current"' : '';
392
+ $all_url = remove_query_arg('customvar');
393
+ $views['all'] = "<a href='{$all_url }' {$class} >" . esc_html__('All', '99robots-header-footer-code-manager') . ' (' . $this->record_count() . ')</a>';
394
+
395
+ //Foo link
396
+ $foo_url = add_query_arg('customvar', 'active');
397
+ $class = ('active' === $current ? ' class="current"' : '');
398
+ $views['active'] = "<a href='{$foo_url}' {$class} >" . esc_html__('Active', '99robots-header-footer-code-manager') . ' (' . $this->record_count('active') . ')</a>';
399
+
400
+ //Bar link
401
+ $bar_url = add_query_arg('customvar', 'inactive');
402
+ $class = ('inactive' === $current ? ' class="current"' : '');
403
+ $views['inactive'] = "<a href='{$bar_url}' {$class} >" . esc_html__('Inactive', '99robots-header-footer-code-manager') . ' (' . $this->record_count('inactive') . ')</a>';
404
+
405
+ return $views;
406
+ }
407
+
408
+ public function process_bulk_action()
409
+ {
410
+ //Detect when a bulk action is being triggered...
411
+ if ('delete' === $this->current_action()) {
412
+
413
+ // In our file that handles the request, verify the nonce.
414
+ $nonce = sanitize_text_field($_REQUEST['_wpnonce']);
415
+
416
+ if (!wp_verify_nonce($nonce, 'hfcm_delete_snippet')) {
417
+ die('Go get a life script kiddies');
418
+ } else {
419
+ if(!empty($_GET['snippet'])) {
420
+ $snippet_id = (int) $_GET['snippet'];
421
+ if (!empty($snippet_id)) {
422
+ self::delete_snippet($snippet_id);
423
+ }
424
+ }
425
+
426
+ NNR_HFCM::hfcm_redirect(admin_url('admin.php?page=hfcm-list'));
427
+ return;
428
+ }
429
+ }
430
+
431
+ // If the delete bulk action is triggered
432
+ if (
433
+ (isset($_POST['action']) && 'bulk-delete' === $_POST['action']) ||
434
+ (isset($_POST['action2']) && 'bulk-delete' === $_POST['action2'])
435
+ ) {
436
+ $delete_ids = esc_sql($_POST['snippets']);
437
+
438
+ // loop over the array of record IDs and delete them
439
+ foreach ($delete_ids as $id) {
440
+ $id = (int) $id;
441
+ if(!empty($id)) {
442
+ self::delete_snippet($id);
443
+ }
444
+ }
445
+
446
+ NNR_HFCM::hfcm_redirect(admin_url('admin.php?page=hfcm-list'));
447
+ return;
448
+ } elseif (
449
+ (isset($_POST['action']) && 'bulk-activate' === $_POST['action']) ||
450
+ (isset($_POST['action2']) && 'bulk-activate' === $_POST['action2'])
451
+ ) {
452
+
453
+ $activate_ids = esc_sql($_POST['snippets']);
454
+
455
+ // loop over the array of record IDs and activate them
456
+ foreach ($activate_ids as $id) {
457
+ $id = (int) $id;
458
+ if(!empty($id)) {
459
+ self::activate_snippet($id);
460
+ }
461
+ }
462
+
463
+ NNR_HFCM::hfcm_redirect(admin_url('admin.php?page=hfcm-list'));
464
+ return;
465
+ } elseif (
466
+ (isset($_POST['action']) && 'bulk-deactivate' === $_POST['action']) ||
467
+ (isset($_POST['action2']) && 'bulk-deactivate' === $_POST['action2'])
468
+ ) {
469
+
470
+ $delete_ids = esc_sql($_POST['snippets']);
471
+
472
+ // loop over the array of record IDs and deactivate them
473
+ foreach ($delete_ids as $id) {
474
+ $id = (int) $id;
475
+ if(!empty($id)) {
476
+ self::deactivate_snippet($id);
477
+ }
478
+ }
479
+
480
+ NNR_HFCM::hfcm_redirect(admin_url('admin.php?page=hfcm-list'));
481
+
482
+ return;
483
+ }
484
+ }
485
  }
486
 
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: 99robots, charliepatel, DraftPress
3
  Tags: header, footer, code manager, snippet, functions.php, tracking, google analytics, adsense, verification, pixel
4
  Requires at least: 4.9
5
  Requires PHP: 5.6.20
6
- Tested up to: 5.8
7
- Stable tag: 1.1.13
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
  Donate link: https://draftpress.com
@@ -113,6 +113,11 @@ A. Free plugins rely on user feedback. Therefore, the best thing you can do for
113
  A. If your script is not supported, just let us know and we'll look into it immediately. We will do our best to ensure all reputable services are supported. When requesting support for a particular script, it would be nice to get a sample of the script so that we can see its structure.
114
 
115
  == Changelog ==
 
 
 
 
 
116
  = 1.1.13 = 2021-09-06
117
  * FIXED: bool function return type
118
  * UPDATED: Minimum required PHP version
3
  Tags: header, footer, code manager, snippet, functions.php, tracking, google analytics, adsense, verification, pixel
4
  Requires at least: 4.9
5
  Requires PHP: 5.6.20
6
+ Tested up to: 5.8.1
7
+ Stable tag: 1.1.14
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
  Donate link: https://draftpress.com
113
  A. If your script is not supported, just let us know and we'll look into it immediately. We will do our best to ensure all reputable services are supported. When requesting support for a particular script, it would be nice to get a sample of the script so that we can see its structure.
114
 
115
  == Changelog ==
116
+ = 1.1.14 = 2021-10-08
117
+ * FIXED: SQL Vulnerability with listing orderby
118
+ * FIXED: DbDelta query
119
+ * UPDATED: Compatibility with WordPress 5.8.1
120
+
121
  = 1.1.13 = 2021-09-06
122
  * FIXED: bool function return type
123
  * UPDATED: Minimum required PHP version