Content Aware Sidebars – Unlimited Widget Areas - Version 3.17

Version Description

  • [new] weglot display condition
  • [new] wordpress 5.9 support

Pro Plan:

  • [new] meta box display condition
  • [new] infuse action now uses sidebar order option as hook priority
  • [new] option to disable all widgets at once in widget cleaner
  • [fixed] pagination in buddypress groups condition
Download this release

Release Info

Developer intoxstudio
Plugin Icon 128x128 Content Aware Sidebars – Unlimited Widget Areas
Version 3.17
Comparing to
See all releases

Code changes from version 3.16.2 to 3.17

Files changed (63) hide show
  1. admin/admin.php +1 -1
  2. admin/admin_bar.php +1 -1
  3. admin/db-updates.php +1 -1
  4. admin/quick_select.php +1 -1
  5. admin/screen_widgets.php +1 -1
  6. admin/settings.php +93 -93
  7. admin/sidebar-edit.php +1010 -1010
  8. admin/sidebar-list-table.php +713 -713
  9. admin/sidebar-overview.php +333 -334
  10. app.php +2 -2
  11. assets/css/index.php +1 -1
  12. assets/css/style.css +1 -1
  13. assets/img/index.php +1 -1
  14. assets/index.php +1 -1
  15. assets/js/cas_admin.min.js +1 -1
  16. assets/js/general.min.js +1 -1
  17. assets/js/index.php +1 -1
  18. assets/js/suggest-sidebars.min.js +1 -1
  19. assets/js/widgets.min.js +1 -1
  20. cas_uninstall.php +1 -1
  21. changelog.txt +78 -0
  22. conditions/placeholder.php +1 -1
  23. content-aware-sidebars.php +76 -81
  24. freemius.php +1 -1
  25. index.php +1 -1
  26. lang/index.php +1 -1
  27. lib/wp-content-aware-engine/assets/css/index.php +2 -2
  28. lib/wp-content-aware-engine/assets/index.php +2 -2
  29. lib/wp-content-aware-engine/assets/js/index.php +2 -2
  30. lib/wp-content-aware-engine/bootstrap.php +90 -92
  31. lib/wp-content-aware-engine/core.php +1241 -1241
  32. lib/wp-content-aware-engine/index.php +2 -2
  33. lib/wp-content-aware-engine/meta.php +238 -238
  34. lib/wp-content-aware-engine/module/author.php +96 -96
  35. lib/wp-content-aware-engine/module/bbpress.php +99 -99
  36. lib/wp-content-aware-engine/module/bp_member.php +154 -154
  37. lib/wp-content-aware-engine/module/date.php +77 -77
  38. lib/wp-content-aware-engine/module/polylang.php +111 -111
  39. lib/wp-content-aware-engine/module/post_type.php +527 -527
  40. lib/wp-content-aware-engine/module/static.php +92 -92
  41. lib/wp-content-aware-engine/module/weglot.php +91 -0
  42. lib/wp-content-aware-engine/objectmanager.php +145 -145
  43. lib/wp-content-aware-engine/typemanager.php +2 -3
  44. lib/wp-content-aware-engine/view.php +124 -124
  45. lib/wp-content-aware-engine/view/condition_options.php +16 -16
  46. lib/wp-content-aware-engine/view/condition_template.php +8 -8
  47. lib/wp-content-aware-engine/view/group_template.php +10 -10
  48. lib/wp-content-aware-engine/view/index.php +2 -2
  49. lib/wp-pointer-tour/assets/index.php +1 -1
  50. lib/wp-pointer-tour/assets/js/index.php +1 -1
  51. lib/wp-pointer-tour/index.php +1 -1
  52. readme.txt +18 -82
  53. sidebar.php +1 -1
  54. view/meta_box_action.php +1 -1
  55. view/meta_box_advanced.php +1 -1
  56. view/meta_box_design.php +1 -1
  57. view/meta_box_html.php +1 -1
  58. view/meta_box_schedule.php +1 -1
  59. view/meta_box_status.php +1 -1
  60. view/meta_box_submit.php +1 -1
  61. view/meta_box_support.php +1 -1
  62. view/notice_review.php +1 -1
  63. view/sidebars_quick_select.php +1 -1
admin/admin.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
admin/admin_bar.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
admin/db-updates.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
admin/quick_select.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
admin/screen_widgets.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
admin/settings.php CHANGED
@@ -1,93 +1,93 @@
1
- <?php
2
- /**
3
- * @package Content Aware Sidebars
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- class CAS_Admin_Settings extends CAS_Admin
12
- {
13
- /**
14
- * @inheritDoc
15
- */
16
- public function admin_hooks()
17
- {
18
- }
19
-
20
- /**
21
- * @inheritDoc
22
- */
23
- public function get_screen()
24
- {
25
- $screen = add_submenu_page(
26
- CAS_App::BASE_SCREEN.'-bogus', //dont add menu item
27
- null,
28
- null,
29
- $this->authorize_user(),
30
- CAS_App::BASE_SCREEN.'-settings',
31
- [$this,'render_screen']
32
- );
33
- return $screen;
34
- }
35
-
36
- /**
37
- * @inheritDoc
38
- */
39
- public function authorize_user()
40
- {
41
- $post_type_object = $this->get_sidebar_type();
42
- return $post_type_object->cap->edit_posts;
43
- }
44
-
45
- /**
46
- * @inheritDoc
47
- */
48
- public function prepare_screen()
49
- {
50
- $this->process_actions();
51
- }
52
-
53
- /**
54
- * @inheritDoc
55
- */
56
- public function process_actions()
57
- {
58
- $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
59
-
60
- if (!$action) {
61
- return;
62
- }
63
-
64
- check_admin_referer($action);
65
-
66
- $sendback = wp_get_referer();
67
-
68
- switch ($action) {
69
- case 'update_condition_type_cache':
70
- WPCACore::cache_condition_types();
71
- break;
72
- default:
73
- break;
74
- }
75
-
76
- wp_safe_redirect($sendback);
77
- exit();
78
- }
79
-
80
- /**
81
- * @inheritDoc
82
- */
83
- public function render_screen()
84
- {
85
- }
86
-
87
- /**
88
- * @inheritDoc
89
- */
90
- public function add_scripts_styles()
91
- {
92
- }
93
- }
1
+ <?php
2
+ /**
3
+ * @package Content Aware Sidebars
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ class CAS_Admin_Settings extends CAS_Admin
12
+ {
13
+ /**
14
+ * @inheritDoc
15
+ */
16
+ public function admin_hooks()
17
+ {
18
+ }
19
+
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ public function get_screen()
24
+ {
25
+ $screen = add_submenu_page(
26
+ CAS_App::BASE_SCREEN.'-bogus', //dont add menu item
27
+ null,
28
+ null,
29
+ $this->authorize_user(),
30
+ CAS_App::BASE_SCREEN.'-settings',
31
+ [$this,'render_screen']
32
+ );
33
+ return $screen;
34
+ }
35
+
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ public function authorize_user()
40
+ {
41
+ $post_type_object = $this->get_sidebar_type();
42
+ return $post_type_object->cap->edit_posts;
43
+ }
44
+
45
+ /**
46
+ * @inheritDoc
47
+ */
48
+ public function prepare_screen()
49
+ {
50
+ $this->process_actions();
51
+ }
52
+
53
+ /**
54
+ * @inheritDoc
55
+ */
56
+ public function process_actions()
57
+ {
58
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
59
+
60
+ if (!$action) {
61
+ return;
62
+ }
63
+
64
+ check_admin_referer($action);
65
+
66
+ $sendback = wp_get_referer();
67
+
68
+ switch ($action) {
69
+ case 'update_condition_type_cache':
70
+ WPCACore::cache_condition_types();
71
+ break;
72
+ default:
73
+ break;
74
+ }
75
+
76
+ wp_safe_redirect($sendback);
77
+ exit();
78
+ }
79
+
80
+ /**
81
+ * @inheritDoc
82
+ */
83
+ public function render_screen()
84
+ {
85
+ }
86
+
87
+ /**
88
+ * @inheritDoc
89
+ */
90
+ public function add_scripts_styles()
91
+ {
92
+ }
93
+ }
admin/sidebar-edit.php CHANGED
@@ -1,1010 +1,1010 @@
1
- <?php
2
- /**
3
- * @package Content Aware Sidebars
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- final class CAS_Sidebar_Edit extends CAS_Admin
12
- {
13
-
14
- /**
15
- * Intro tour manager
16
- * @var WP_Pointer_Tour
17
- */
18
- private $_tour_manager;
19
-
20
- /**
21
- * Add filters and actions for admin dashboard
22
- * e.g. AJAX calls
23
- *
24
- * @since 3.5
25
- * @return void
26
- */
27
- public function admin_hooks()
28
- {
29
- $this->_tour_manager = new WP_Pointer_Tour(CAS_App::META_PREFIX.'cas_tour');
30
-
31
- $this->add_action('delete_post', 'remove_sidebar_widgets');
32
- $this->add_action('save_post_'.CAS_App::TYPE_SIDEBAR, 'save_post', 10, 2);
33
-
34
- $this->add_filter('wp_insert_post_data', 'add_duplicate_title_suffix', 99, 2);
35
-
36
- if (!cas_fs()->can_use_premium_code()) {
37
- $this->add_action('wpca/modules/init', 'add_modules');
38
- }
39
- }
40
-
41
- /**
42
- * Set up admin menu and get current screen
43
- *
44
- * @since 3.4
45
- * @return string
46
- */
47
- public function get_screen()
48
- {
49
- $post_type_object = $this->get_sidebar_type();
50
- return add_submenu_page(
51
- CAS_App::BASE_SCREEN,
52
- $post_type_object->labels->add_new_item,
53
- $post_type_object->labels->add_new,
54
- $post_type_object->cap->edit_posts,
55
- CAS_App::BASE_SCREEN.'-edit',
56
- [$this,'render_screen']
57
- );
58
- }
59
-
60
- /**
61
- * @since 3.5
62
- *
63
- * @return bool
64
- */
65
- public function authorize_user()
66
- {
67
- return true;
68
- }
69
-
70
- /**
71
- * @since 3.4
72
- *
73
- * @return void
74
- */
75
- public function prepare_screen()
76
- {
77
- $this->add_action('cas/admin/add_meta_boxes', 'create_meta_boxes');
78
-
79
- global $post, $title, $active_post_lock;
80
-
81
- $post_type = CAS_App::TYPE_SIDEBAR;
82
- $post_type_object = $this->get_sidebar_type();
83
- $post_id = isset($_REQUEST['sidebar_id']) ? $_REQUEST['sidebar_id'] : 0;
84
-
85
- /**
86
- * Edit mode
87
- */
88
- if ($post_id) {
89
- $this->process_actions($post_id);
90
-
91
- $post = get_post($post_id, OBJECT, 'edit');
92
-
93
- if (! $post) {
94
- wp_die(__('The sidebar no longer exists.'));
95
- }
96
- if (! current_user_can($post_type_object->cap->edit_post, $post_id)) {
97
- wp_die(__('You are not allowed to edit this sidebar.'));
98
- }
99
- if ('trash' == $post->post_status) {
100
- wp_die(__('You cannot edit this sidebar because it is in the Trash. Please restore it and try again.'));
101
- }
102
-
103
- if (! empty($_GET['get-post-lock'])) {
104
- check_admin_referer('lock-post_' . $post_id);
105
- wp_set_post_lock($post_id);
106
- wp_redirect(get_edit_post_link($post_id, 'url'));
107
- exit();
108
- }
109
-
110
- if (! wp_check_post_lock($post->ID)) {
111
- $active_post_lock = wp_set_post_lock($post->ID);
112
- }
113
-
114
- $title = $post_type_object->labels->edit_item;
115
-
116
- /**
117
- * New Mode
118
- */
119
- } else {
120
- if (! (current_user_can($post_type_object->cap->edit_posts) || current_user_can($post_type_object->cap->create_posts))) {
121
- wp_die(
122
- '<p>' . __('You are not allowed to create sidebars.', 'content-aware-sidebars') . '</p>',
123
- 403
124
- );
125
- }
126
-
127
- $post = get_default_post_to_edit($post_type, true);
128
-
129
- $title = $post_type_object->labels->add_new_item;
130
- }
131
-
132
- do_action('cas/admin/add_meta_boxes', $post);
133
- }
134
-
135
- /**
136
- * @since 3.9
137
- * @param WPCATypeManager $types
138
- *
139
- * @return void
140
- */
141
- public function add_modules($types)
142
- {
143
- if (!$types->has(CAS_App::TYPE_SIDEBAR)) {
144
- return;
145
- }
146
-
147
- $pro_label = '(Pro)';
148
- $type = $types->get(CAS_App::TYPE_SIDEBAR);
149
- $path = plugin_dir_path(dirname(__FILE__));
150
-
151
- require($path.'conditions/placeholder.php');
152
-
153
- if (!WPCACore::get_option(CAS_App::TYPE_SIDEBAR, 'legacy.date_module', false)) {
154
- $module = new CASConditionPlaceholder('cas_date', __('Dates', 'content-aware-sidebars').' '.$pro_label);
155
- $type->add($module, 'cas_date');
156
- }
157
-
158
- $module = new CASConditionPlaceholder('cas_url', __('URLs', 'content-aware-sidebars').' '.$pro_label);
159
- $type->add($module, 'cas_url');
160
- $module = new CASConditionPlaceholder('cas_ref_url', __('Referrer URLs', 'content-aware-sidebars').' '.$pro_label);
161
- $type->add($module, 'cas_ref_url');
162
-
163
- if (function_exists('bp_is_active')) {
164
- $module = new CASConditionPlaceholder('cas_bbp', __('BuddyPress Groups', 'content-aware-sidebars').' '.$pro_label, '', '', 'plugins');
165
- $type->add($module, 'cas_bbp');
166
- }
167
-
168
- if (defined('ACF')) {
169
- $module = new CASConditionPlaceholder('cas_acf', __('Advanced Custom Fields', 'content-aware-sidebars').' '.$pro_label, '', '', 'plugins');
170
- $type->add($module, 'cas_acf');
171
- }
172
- }
173
-
174
- /**
175
- * Process actions
176
- *
177
- * @since 3.4
178
- * @param int $post_id
179
- * @return void
180
- */
181
- public function process_actions($post_id)
182
- {
183
- $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
184
- if (isset($_POST['deletepost'])) {
185
- $action = 'delete';
186
- }
187
-
188
- if ($action && $post_id) {
189
- $sendback = wp_get_referer();
190
- $sendback = remove_query_arg(
191
- ['action','trashed', 'untrashed', 'deleted', 'ids'],
192
- $sendback
193
- );
194
- if (isset($_REQUEST['_cas_section']) && $_REQUEST['_cas_section']) {
195
- $sendback .= $_REQUEST['_cas_section'];
196
- }
197
-
198
- $post = get_post($post_id);
199
- if (! $post) {
200
- wp_die(__('The sidebar no longer exists.', 'content-aware-sidebars'));
201
- }
202
-
203
- check_admin_referer($action . '-post_' . $post_id);
204
-
205
- switch ($action) {
206
- case 'update':
207
-
208
- $post_id = $this->update_sidebar_type();
209
-
210
- // Session cookie flag that the post was saved
211
- if (isset($_COOKIE['wp-saving-post']) && $_COOKIE['wp-saving-post'] === $post_id . '-check') {
212
- setcookie('wp-saving-post', $post_id . '-saved', time() + DAY_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, is_ssl());
213
- }
214
-
215
- $status = get_post_status($post_id);
216
- if (isset($_POST['original_post_status']) && $_POST['original_post_status'] == $status) {
217
- $message = 1;
218
- } else {
219
- switch ($status) {
220
- case CAS_App::STATUS_SCHEDULED:
221
- //gets scheduled
222
- $message = 9;
223
- break;
224
- case CAS_App::STATUS_INACTIVE:
225
- //gets deactivated
226
- $message = 10;
227
- break;
228
- case CAS_App::STATUS_ACTIVE:
229
- //gets activated
230
- $message = 6;
231
- break;
232
- default:
233
- $message = 1;
234
- }
235
- }
236
-
237
- $sendback = add_query_arg([
238
- 'sidebar_id' => $post_id,
239
- 'message' => $message,
240
- 'page' => 'wpcas-edit'
241
- ], $sendback);
242
- wp_safe_redirect($sendback);
243
- exit();
244
- case 'trash':
245
-
246
- if (! current_user_can('delete_post', $post_id)) {
247
- wp_die(__('You are not allowed to move this sidebar to the Trash.', 'content-aware-sidebars'));
248
- }
249
-
250
- if ($user_id = wp_check_post_lock($post_id)) {
251
- $user = get_userdata($user_id);
252
- wp_die(sprintf(__('You cannot move this sidebar to the Trash. %s is currently editing.', 'content-aware-sidebars'), $user->display_name));
253
- }
254
-
255
- if (! wp_trash_post($post_id)) {
256
- wp_die(__('Error in moving to Trash.'));
257
- }
258
-
259
- $sendback = remove_query_arg('sidebar_id', $sendback);
260
-
261
- wp_safe_redirect(add_query_arg(
262
- [
263
- 'page' => 'wpcas',
264
- 'trashed' => 1,
265
- 'ids' => $post_id
266
- ],
267
- $sendback
268
- ));
269
- exit();
270
- case 'untrash':
271
-
272
- if (! current_user_can('delete_post', $post_id)) {
273
- wp_die(__('You are not allowed to restore this sidebar from the Trash.', 'content-aware-sidebars'));
274
- }
275
-
276
- if (! wp_untrash_post($post_id)) {
277
- wp_die(__('Error in restoring from Trash.'));
278
- }
279
-
280
- wp_safe_redirect(add_query_arg('untrashed', 1, $sendback));
281
- exit();
282
- case 'delete':
283
-
284
- if (! current_user_can('delete_post', $post_id)) {
285
- wp_die(__('You are not allowed to delete this sidebar.', 'content-aware-sidebars'));
286
- }
287
-
288
- if (! wp_delete_post($post_id, true)) {
289
- wp_die(__('Error in deleting.'));
290
- }
291
-
292
- $sendback = remove_query_arg('sidebar_id', $sendback);
293
- wp_safe_redirect(add_query_arg([
294
- 'page' => 'wpcas',
295
- 'deleted' => 1
296
- ], $sendback));
297
- exit();
298
- default:
299
- do_action('cas/admin/action', $action, $post);
300
- break;
301
- }
302
- }
303
- }
304
-
305
- /**
306
- * Render screen
307
- *
308
- * @since 3.4
309
- * @return void
310
- */
311
- public function render_screen()
312
- {
313
- global $post, $active_post_lock;
314
-
315
- $post_type_object = get_post_type_object($post->post_type);
316
- $post_id = isset($_REQUEST['sidebar_id']) ? $_REQUEST['sidebar_id'] : 0;
317
-
318
- $form_extra = '';
319
- if ('auto-draft' == $post->post_status) {
320
- if (isset($_REQUEST['sidebar_id'])) {
321
- $post->post_title = '';
322
- }
323
- $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />";
324
- }
325
-
326
- if ($post_id) {
327
- $title = __('Edit');
328
- } else {
329
- $title = $post_type_object->labels->new_item;
330
- }
331
-
332
- echo '<div class="wrap">';
333
- echo '<h1>';
334
- echo '<a href="'.admin_url('admin.php?page=wpcas').'">'.$post_type_object->labels->all_items.'</a> &raquo; ';
335
- echo esc_html($title);
336
- if (isset($_REQUEST['sidebar_id']) && current_user_can('edit_theme_options')) {
337
- echo ' <a href="' . esc_url(admin_url('widgets.php#'.CAS_App::SIDEBAR_PREFIX.$post->ID)) . '" class="page-title-action add-new-h2">' . __('Manage Widgets', 'content-aware-sidebars') . '</a>';
338
- }
339
-
340
- echo '</h1>';
341
-
342
- $this->sidebar_updated_messages($post);
343
-
344
- echo '<form name="post" action="admin.php?page=wpcas-edit" method="post" id="post">';
345
- $referer = wp_get_referer();
346
- wp_nonce_field('update-post_' . $post->ID);
347
- echo '<input type="hidden" id="user-id" name="user_ID" value="'.(int)get_current_user_id().'" />';
348
- echo '<input type="hidden" id="_cas_section" name="_cas_section" value="" />';
349
- echo '<input type="hidden" id="hiddenaction" name="action" value="update" />';
350
- echo '<input type="hidden" id="post_author" name="post_author" value="'.esc_attr($post->post_author).'" />';
351
- echo '<input type="hidden" id="original_post_status" name="original_post_status" value="'.esc_attr($post->post_status).'" />';
352
- echo '<input type="hidden" id="referredby" name="referredby" value="'.($referer ? esc_url($referer) : '').'" />';
353
- echo '<input type="hidden" id="post_ID" name="sidebar_id" value="'.esc_attr($post->ID).'" />';
354
- if (! empty($active_post_lock)) {
355
- echo '<input type="hidden" id="active_post_lock" value="'.esc_attr(implode(':', $active_post_lock)).'" />';
356
- }
357
- if (get_post_status($post) != CAS_App::STATUS_INACTIVE) {
358
- wp_original_referer_field(true, 'previous');
359
- }
360
- echo $form_extra;
361
-
362
- $nav_tabs = [
363
- 'conditions' => __('Conditions', 'content-aware-sidebars'),
364
- 'action' => __('Action', 'content-aware-sidebars'),
365
- 'design' => __('Design', 'content-aware-sidebars'),
366
- 'schedule' => __('Schedule', 'content-aware-sidebars'),
367
- 'advanced' => __('Options', 'content-aware-sidebars')
368
- ];
369
- $nav_tabs = apply_filters('cas/admin/nav-tabs', $nav_tabs);
370
-
371
- echo '<div id="poststuff">';
372
- echo '<div id="post-body" class="cas-metabox-holder metabox-holder columns-2">';
373
- echo '<div id="post-body-content">';
374
- echo '<div id="titlediv">';
375
- echo '<div id="titlewrap">';
376
- echo '<label class="screen-reader-text" id="title-prompt-text" for="title">'.__('Enter title here').'</label>';
377
- echo '<input type="text" name="post_title" size="30" value="'.esc_attr($post->post_title).'" id="title" spellcheck="true" autocomplete="off" />';
378
- echo '</div></div>';
379
- $this->render_section_nav($nav_tabs);
380
- echo '</div>';
381
- $this->render_sections($nav_tabs, $post, $post->post_type);
382
- echo '</div>';
383
- echo '<br class="clear" />';
384
- echo '</div></form></div>';
385
- }
386
-
387
- /**
388
- * Render tab navigation
389
- *
390
- * @since 3.4
391
- * @param array $tabs
392
- * @return void
393
- */
394
- public function render_section_nav($tabs)
395
- {
396
- echo '<h2 class="nav-tab-wrapper js-cas-tabs hide-if-no-js " style="padding-bottom:0;">';
397
- foreach ($tabs as $id => $label) {
398
- echo '<a class="js-nav-link nav-tab nav-tab-section-'.$id.'" href="#top#section-'.$id.'">'.$label.'</a>';
399
- }
400
- echo '</h2>';
401
- }
402
-
403
- /**
404
- * Render meta box sections
405
- *
406
- * @since 3.4
407
- * @param array $tabs
408
- * @param WP_Post $post
409
- * @param string $post_type
410
- * @return void
411
- */
412
- public function render_sections($tabs, $post, $post_type)
413
- {
414
- echo '<div id="postbox-container-1" class="postbox-container">';
415
- do_meta_boxes(CAS_App::BASE_SCREEN.'-edit', 'side', $post);
416
- echo '</div>';
417
- echo '<div id="postbox-container-2" class="postbox-container">';
418
- foreach ($tabs as $id => $label) {
419
- $name = 'section-'.$id;
420
- echo '<div id="'.$name.'" class="cas-section">';
421
- do_meta_boxes(CAS_App::BASE_SCREEN.'-edit', $name, $post);
422
- echo '</div>';
423
- }
424
- //boxes across sections
425
- do_meta_boxes(CAS_App::BASE_SCREEN.'-edit', 'normal', $post);
426
- echo '</div>';
427
- }
428
-
429
- /**
430
- * Update sidebar post type
431
- *
432
- * @since 3.4
433
- * @return int
434
- */
435
- public function update_sidebar_type()
436
- {
437
- global $wpdb;
438
-
439
- $post_ID = (int) $_POST['sidebar_id'];
440
- $post = get_post($post_ID);
441
- $post_data['post_type'] = CAS_App::TYPE_SIDEBAR;
442
- $post_data['ID'] = (int) $post_ID;
443
- $post_data['post_title'] = $_POST['post_title'];
444
- $post_data['comment_status'] = 'closed';
445
- $post_data['ping_status'] = 'closed';
446
- $post_data['post_author'] = get_current_user_id();
447
- $post_data['menu_order'] = intval($_POST['menu_order']);
448
-
449
- $ptype = get_post_type_object($post_data['post_type']);
450
-
451
- if (!current_user_can('edit_post', $post_ID)) {
452
- wp_die(__('You are not allowed to edit this sidebar.', 'content-aware-sidebars'));
453
- } elseif (! current_user_can($ptype->cap->create_posts)) {
454
- return new WP_Error('edit_others_posts', __('You are not allowed to create sidebars.', 'content-aware-sidebars'));
455
- } elseif ($post_data['post_author'] != $_POST['post_author']
456
- && ! current_user_can($ptype->cap->edit_others_posts)) {
457
- return new WP_Error('edit_others_posts', __('You are not allowed to edit this sidebar.', 'content-aware-sidebars'));
458
- }
459
-
460
- if (isset($_POST['post_status'])) {
461
- $post_data['post_status'] = CAS_App::STATUS_ACTIVE;
462
- //if sidebar has been future before, we need to reset date
463
- if ($_POST['post_status'] != $_POST['original_post_status']) {
464
- $post_data['post_date'] = current_time('mysql');
465
- }
466
- } elseif ($_POST['sidebar_activate']) {
467
- $_POST['post_status'] = CAS_App::STATUS_SCHEDULED; //yoast seo expects this
468
- $post_data['post_status'] = CAS_App::STATUS_SCHEDULED;
469
- $post_data['post_date'] = $_POST['sidebar_activate'];
470
- } else {
471
- $_POST['post_status'] = CAS_App::STATUS_INACTIVE;
472
- $post_data['post_status'] = CAS_App::STATUS_INACTIVE;
473
- }
474
-
475
- if ($post_data['post_status'] != CAS_App::STATUS_INACTIVE
476
- && $_POST['sidebar_deactivate']) {
477
- $this->reschedule_deactivation($post_ID, $_POST['sidebar_deactivate']);
478
- } else {
479
- $this->reschedule_deactivation($post_ID);
480
- }
481
-
482
- if (isset($post_data['post_date'])) {
483
- $post_data['post_date_gmt'] = get_gmt_from_date($post_data['post_date']);
484
- }
485
-
486
- if (post_type_supports(CAS_App::TYPE_SIDEBAR, 'revisions')) {
487
- $revisions = wp_get_post_revisions($post_ID, [
488
- 'order' => 'ASC',
489
- 'posts_per_page' => 1
490
- ]);
491
- $revision = current($revisions);
492
- // Check if the revisions have been upgraded
493
- if ($revisions && _wp_get_post_revision_version($revision) < 1) {
494
- _wp_upgrade_revisions_of_post($post, wp_get_post_revisions($post_ID));
495
- }
496
- }
497
-
498
- update_post_meta($post_ID, '_edit_last', $post_data['post_author']);
499
- wp_update_post($post_data);
500
- wp_set_post_lock($post_ID);
501
-
502
- return $post_ID;
503
- }
504
-
505
- /**
506
- * Handle schedule for deactivation
507
- *
508
- * @since 3.4
509
- * @param int $post_id
510
- * @param string $time
511
- * @return void
512
- */
513
- public function reschedule_deactivation($post_id, $time = false)
514
- {
515
- $name = 'cas/event/deactivate';
516
- if (wp_next_scheduled($name, [$post_id]) !== false) {
517
- wp_clear_scheduled_hook($name, [$post_id]);
518
- }
519
-
520
- if ($time) {
521
- //Requires to be in GMT
522
- $utime = get_gmt_from_date($time, 'U');
523
- wp_schedule_single_event($utime, $name, [$post_id]);
524
- update_post_meta($post_id, CAS_App::META_PREFIX.'deactivate_time', $time);
525
- } else {
526
- delete_post_meta($post_id, CAS_App::META_PREFIX.'deactivate_time');
527
- }
528
- }
529
-
530
- /**
531
- * Create update messages
532
- *
533
- * @param WP_Post $post
534
- *
535
- * @return void
536
- */
537
- public function sidebar_updated_messages($post)
538
- {
539
- $message_number = isset($_GET['message']) ? absint($_GET['message']) : null;
540
-
541
- if (is_null($message_number)) {
542
- return;
543
- }
544
-
545
- $manage_widgets = sprintf(' <a href="%1$s">%2$s</a>', esc_url(admin_url('widgets.php#'.CAS_App::SIDEBAR_PREFIX.$post->ID)), __('Manage widgets', 'content-aware-sidebars'));
546
- $messages = [
547
- 1 => __('Sidebar updated.', 'content-aware-sidebars').$manage_widgets,
548
- 6 => __('Sidebar activated.', 'content-aware-sidebars').$manage_widgets,
549
- 9 => sprintf(
550
- __('Sidebar scheduled for: <strong>%1$s</strong>.', 'content-aware-sidebars'),
551
- // translators: Publish box date format, see http://php.net/date
552
- date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date))
553
- ).$manage_widgets,
554
- 10 => __('Sidebar deactivated.', 'content-aware-sidebars').$manage_widgets,
555
- ];
556
- $messages = apply_filters('cas/admin/messages', $messages, $post);
557
-
558
- if (isset($messages[$message_number])) {
559
- echo '<div id="message" class="updated notice notice-success is-dismissible"><p>'.$messages[$message_number].'</p></div>';
560
- }
561
- }
562
-
563
- /**
564
- * Set pointers for tour and enqueue script
565
- *
566
- * @since 3.3
567
- * @return void
568
- */
569
- private function create_pointers()
570
- {
571
- if ($this->_tour_manager->user_has_finished_tour()) {
572
- return;
573
- }
574
-
575
- $this->_tour_manager->set_pointers([
576
- [
577
- 'content' => sprintf(
578
- '<h3>%s</h3>%s',
579
- __('Get Started in 60 Seconds', 'content-aware-sidebars'),
580
- '<p>'.__('Welcome to Content Aware Sidebars!', 'content-aware-sidebars').'</p>'.
581
- '<p>'.__('This interactive guide will show you just how easy it is to create a widget area and control where, how, and when to display it.', 'content-aware-sidebars').'</p>'
582
- ),
583
- 'ref_id' => '#titlediv',
584
- 'position' => [
585
- 'edge' => 'top',
586
- 'align' => 'center'
587
- ],
588
- 'pointerWidth' => 400,
589
- 'next' => __('Start Quick Tour', 'content-aware-sidebars'),
590
- 'dismiss' => __('Skip - I know what to do', 'content-aware-sidebars')
591
- ],
592
- [
593
- 'content' => sprintf(
594
- '<h3>%s</h3>%s',
595
- '1/5 '.__('Where to display', 'content-aware-sidebars'),
596
- '<p>'.__('Choose from the extensive Display Conditions with built-in support for other plugins. You will never be asked to enter widget logic PHP code!', 'content-aware-sidebars').'</p>'.
597
- '<p>'.__('Select anything to continue the tour. You can change it later.', 'content-aware-sidebars').'</p>'
598
- ),
599
- 'ref_id' => '.cas-group-new',
600
- 'position' => [
601
- 'edge' => 'top',
602
- 'align' => 'center'
603
- ],
604
- 'prev' => false,
605
- 'next' => '.js-wpca-add-or, .js-wpca-add-quick',
606
- 'nextEvent' => 'select2:select click',
607
- 'dismiss' => false
608
- ],
609
- [
610
- 'content' => sprintf(
611
- '<h3>%s</h3>%s',
612
- '2/5 '.__('Where to display', 'content-aware-sidebars'),
613
- '<p>'.__('Click on the input field and select the content you want - just type to search. Changes are saved automatically!', 'content-aware-sidebars').'</p>'.
614
- '<p>'.__('You can add multiple content types to the same group. Try e.g. "All Posts" and an Author to display on all posts written by that author.', 'content-aware-sidebars').'</p>'.
615
- '<p>'.sprintf('<a href="%s" target="_blank" rel="noopener">'.__('Learn more about AND vs OR conditions', 'content-aware-sidebars').'</a>', 'https://dev.institute/docs/content-aware-sidebars/getting-started/display-sidebar-advanced/').'</p>'
616
- ),
617
- 'ref_id' => '#cas-groups > ul',
618
- 'position' => [
619
- 'edge' => 'top',
620
- 'align' => 'center'
621
- ],
622
- 'dismiss' => __('Close Tour', 'content-aware-sidebars')
623
- ],
624
- [
625
- 'content' => sprintf(
626
- '<h3>%s</h3>%s',
627
- '3/5 '.__('How to display', 'content-aware-sidebars'),
628
- '<p>'.__('Replace any sidebar or widget area in your theme, or add widgets by merging with them.', 'content-aware-sidebars').'</p>'.
629
- '<p>'.__('You can also use the shortcode to display widgets inside a page or post.', 'content-aware-sidebars').'</p>'
630
- ),
631
- 'ref_id' => '.nav-tab-wrapper.js-cas-tabs .nav-tab-section-action',
632
- 'position' => [
633
- 'edge' => 'left',
634
- 'align' => 'left'
635
- ],
636
- 'dismiss' => __('Close Tour', 'content-aware-sidebars')
637
- ],
638
- [
639
- 'content' => sprintf(
640
- '<h3>%s</h3>%s',
641
- '4/5 '.__('When to activate', 'content-aware-sidebars'),
642
- '<p>'.__('Create a widget area and manage its widgets today, then publish it when you are ready.', 'content-aware-sidebars').'</p>'.
643
- '<p>'.__('To schedule automatic activation or deactivation, just pick a date and time!', 'content-aware-sidebars').'</p>'.
644
- '<p>'.__('By default, new widget areas will be activated when created.', 'content-aware-sidebars').'</p>'
645
- ),
646
- 'ref_id' => '.nav-tab-wrapper.js-cas-tabs .nav-tab-section-schedule',
647
- 'position' => [
648
- 'edge' => 'left',
649
- 'align' => 'left'
650
- ],
651
- 'dismiss' => __('Close Tour', 'content-aware-sidebars')
652
- ],
653
- [
654
- 'content' => sprintf(
655
- '<h3>%s</h3>%s',
656
- '5/5 '.__('How to look', 'content-aware-sidebars'),
657
- '<p>'.__('Personalize the styling without writing any code!', 'content-aware-sidebars').'</p>'.
658
- '<p>'.__('You can modify the HTML and CSS classes of the widget area itself, each widget, as well as widget titles.', 'content-aware-sidebars').'</p>'
659
- ),
660
- 'ref_id' => '.nav-tab-wrapper.js-cas-tabs .nav-tab-section-design',
661
- 'position' => [
662
- 'edge' => 'left',
663
- 'align' => 'left'
664
- ],
665
- 'next' => __('Finish Tour', 'content-aware-sidebars')
666
- ],
667
- [
668
- 'content' => sprintf(
669
- '<h3>%s</h3>%s',
670
- __("That's it", 'content-aware-sidebars'),
671
- '<p>'.__('Hit the Create button to save your first custom widget area.', 'content-aware-sidebars').'</p>'.
672
- '<p>'.__('If you need more help, check out the links below.', 'content-aware-sidebars').'</p>'
673
- ),
674
- 'ref_id' => '#submitdiv',
675
- 'position' => [
676
- 'edge' => 'right',
677
- 'align' => 'top'
678
- ],
679
- 'dismiss' => __('Close', 'content-aware-sidebars')
680
- ]
681
- ]);
682
- $this->_tour_manager->enqueue_scripts();
683
- }
684
-
685
- /**
686
- * Meta boxes for sidebar edit
687
- * @global object $post
688
- * @return void
689
- */
690
- public function create_meta_boxes($post)
691
- {
692
- $this->create_pointers();
693
- CAS_App::instance()->manager()->populate_metadata();
694
- $path = plugin_dir_path(dirname(__FILE__)).'view/';
695
-
696
- $boxes = [];
697
- $boxes[] = [
698
- 'id' => 'submitdiv',
699
- 'title' => __('Publish'),
700
- 'view' => 'submit',
701
- 'context' => 'side',
702
- 'priority' => 'high'
703
- ];
704
- $boxes[] = [
705
- 'id' => 'cas-options',
706
- 'title' => __('How to display', 'content-aware-sidebars'),
707
- 'view' => 'action',
708
- 'context' => 'section-action',
709
- ];
710
- $boxes[] = [
711
- 'id' => 'cas-status',
712
- 'title' => __('Status', 'content-aware-sidebars'),
713
- 'view' => 'status',
714
- 'context' => 'section-schedule',
715
- ];
716
- $boxes[] = [
717
- 'id' => 'cas-widget-html',
718
- 'title' => __('Styles', 'content-aware-sidebars'),
719
- 'view' => 'html',
720
- 'context' => 'section-design',
721
- ];
722
- $boxes[] = [
723
- 'id' => 'cas-advanced',
724
- 'title' => __('Options', 'content-aware-sidebars'),
725
- 'view' => 'advanced',
726
- 'context' => 'section-advanced',
727
- ];
728
- $boxes[] = [
729
- 'id' => 'cas-plugin-links',
730
- 'title' => __('Recommendations', 'content-aware-sidebars'),
731
- 'view' => 'support',
732
- 'context' => 'side',
733
- ];
734
- $boxes[] = [
735
- 'id' => 'cas-schedule',
736
- 'title' => __('Time Schedule', 'content-aware-sidebars').' <span class="cas-pro-label">'.__('Pro', 'content-aware-sidebars').'</span>',
737
- 'view' => 'schedule',
738
- 'context' => 'section-schedule',
739
- ];
740
- $boxes[] = [
741
- 'id' => 'cas-design',
742
- 'title' => __('Design', 'content-aware-sidebars').' <span class="cas-pro-label">'.__('Pro', 'content-aware-sidebars').'</span>',
743
- 'view' => 'design',
744
- 'context' => 'section-design',
745
- ];
746
-
747
- foreach ($boxes as $box) {
748
- $view = WPCAView::make($path.'meta_box_'.$box['view'].'.php', [
749
- 'post' => $post
750
- ]);
751
-
752
- add_meta_box(
753
- $box['id'],
754
- $box['title'],
755
- [$view,'render'],
756
- CAS_App::BASE_SCREEN.'-edit',
757
- $box['context'],
758
- isset($box['priority']) ? $box['priority'] : 'default'
759
- );
760
- }
761
-
762
- //todo: refactor add of meta box
763
- //with new bootstrapper, legacy core might be loaded
764
- if (method_exists('WPCACore', 'render_group_meta_box')) {
765
- WPCACore::render_group_meta_box($post, CAS_App::BASE_SCREEN.'-edit', 'section-conditions', 'default');
766
- }
767
- }
768
-
769
- /**
770
- * Create form field for metadata
771
- * @global object $post
772
- * @param array $setting
773
- * @return void
774
- */
775
- public static function form_field($id, $class = '', $icon = '')
776
- {
777
- $setting = CAS_App::instance()->manager()->metadata()->get($id);
778
- $current = $setting->get_data(get_the_ID(), true, $setting->get_input_type() != 'multi');
779
- $icon = $icon ? '<span class="'.$icon.'"></span> ' : '';
780
-
781
- echo '<div class="'.$class.'">'.$icon.'<strong>' . $setting->get_title() . '</strong>';
782
- echo '<p>';
783
- switch ($setting->get_input_type()) {
784
- case 'select':
785
- echo '<select style="width:250px;" name="' . $id . '" class="js-cas-'.$id.'">' . "\n";
786
- foreach ($setting->get_input_list() as $key => $value) {
787
- $disabled = '';
788
- if (is_string($key) && strpos($key, '__') === 0) {
789
- $disabled = ' disabled="disabled"';
790
- }
791
- echo '<option value="' . $key . '"' . selected($current, $key, false) . $disabled . '>' . $value . '</option>' . "\n";
792
- }
793
- echo '</select>' . "\n";
794
- break;
795
- case 'checkbox':
796
- echo '<ul>' . "\n";
797
- foreach ($setting->get_input_list() as $key => $value) {
798
- echo '<li><label><input type="checkbox" name="' . $id . '[]" class="js-cas-'.$id.'" value="' . $key . '"' . (in_array($key, $current) ? ' checked="checked"' : '') . ' /> ' . $value . '</label></li>' . "\n";
799
- }
800
- echo '</ul>' . "\n";
801
- break;
802
- case 'multi':
803
- echo '<div><select style="width:100%;" class="js-cas-'.$id.'" multiple="multiple" name="' . $id . '[]" data-value="'.implode(',', $current).'"></select></div>';
804
- break;
805
- case 'text':
806
- default:
807
- echo '<input style="width:200px;" type="text" name="' . $id . '" value="' . $current . '" />' . "\n";
808
- break;
809
- }
810
- echo '</p></div>';
811
- }
812
-
813
- /**
814
- * Save meta values for post
815
- * @param int $post_id
816
- * @return void
817
- */
818
- public function save_post($post_id, $post)
819
- {
820
-
821
- //Verify nonce, check_admin_referer dies on false
822
- if (!(isset($_POST[WPCACore::NONCE])
823
- && wp_verify_nonce($_POST[WPCACore::NONCE], WPCACore::PREFIX.$post_id))) {
824
- return;
825
- }
826
-
827
- // Check permissions
828
- if (!current_user_can(CAS_App::CAPABILITY, $post_id)) {
829
- return;
830
- }
831
-
832
- // Check autosave
833
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
834
- return;
835
- }
836
-
837
- // Save metadata
838
- // todo: wrap this in metadata manager?
839
- foreach (CAS_App::instance()->manager()->metadata() as $field) {
840
- $field->save($post_id);
841
- }
842
- }
843
-
844
- /**
845
- * Add suffix when creating sidebar with existing name
846
- * Does not stop duplicate titles on update
847
- *
848
- * @since 3.4.3
849
- * @param array $insert_data
850
- * @param array $data
851
- * @return array
852
- */
853
- public function add_duplicate_title_suffix($insert_data, $data)
854
- {
855
- if ($data['post_type'] == CAS_App::TYPE_SIDEBAR && !$data['ID']) {
856
- $sidebars = CAS_App::instance()->manager()->sidebars;
857
- $sidebar_titles = [];
858
- foreach ($sidebars as $sidebar) {
859
- $sidebar_titles[$sidebar->post_title] = 1;
860
- }
861
- //if title exists, add a suffix
862
- $i = 0;
863
- $title = wp_unslash($insert_data['post_title']);
864
- $new_title = $title;
865
- while (isset($sidebar_titles[$new_title])) {
866
- $new_title = $title.' ('.++$i.')';
867
- }
868
- if ($i) {
869
- $insert_data['post_title'] = wp_slash($new_title);
870
- }
871
- }
872
- return $insert_data;
873
- }
874
-
875
- /**
876
- * Remove widget when its sidebar is removed
877
- * @param int $post_id
878
- * @return void
879
- */
880
- public function remove_sidebar_widgets($post_id)
881
- {
882
-
883
- // Authenticate and only continue on sidebar post type
884
- if (!current_user_can(CAS_App::CAPABILITY) || get_post_type($post_id) != CAS_App::TYPE_SIDEBAR) {
885
- return;
886
- }
887
-
888
- $id = CAS_App::SIDEBAR_PREFIX . $post_id;
889
-
890
- //Get widgets
891
- $sidebars_widgets = wp_get_sidebars_widgets();
892
-
893
- // Check if sidebar exists in database
894
- if (!isset($sidebars_widgets[$id])) {
895
- return;
896
- }
897
-
898
- // Remove widgets settings from sidebar
899
- foreach ($sidebars_widgets[$id] as $widget_id) {
900
- $widget_type = preg_replace('/-[0-9]+$/', '', $widget_id);
901
- $widget_settings = get_option('widget_' . $widget_type);
902
- $widget_id = substr($widget_id, strpos($widget_id, '-') + 1);
903
- if ($widget_settings && isset($widget_settings[$widget_id])) {
904
- unset($widget_settings[$widget_id]);
905
- update_option('widget_' . $widget_type, $widget_settings);
906
- }
907
- }
908
-
909
- // Remove sidebar
910
- unset($sidebars_widgets[$id]);
911
- wp_set_sidebars_widgets($sidebars_widgets);
912
- }
913
-
914
- /**
915
- * Register and enqueue scripts styles
916
- * for screen
917
- *
918
- * @since 3.4
919
- */
920
- public function add_scripts_styles()
921
- {
922
- if (is_multisite()) {
923
- add_action('admin_footer', '_admin_notice_post_locked');
924
- } else {
925
- $check_users = get_users([ 'fields' => 'ID', 'number' => 2 ]);
926
- if (count($check_users) > 1) {
927
- add_action('admin_footer', '_admin_notice_post_locked');
928
- }
929
- }
930
-
931
- wp_enqueue_script('wp-a11y');
932
-
933
- if (wp_is_mobile()) {
934
- wp_enqueue_script('jquery-touch-punch');
935
- }
936
-
937
- WPCACore::enqueue_scripts_styles('');
938
-
939
- $this->register_script('flatpickr', 'flatpickr', [], '3.0.6');
940
- $this->register_script('cas/admin/edit', 'cas_admin', ['jquery','flatpickr','wp-color-picker']);
941
-
942
- $this->enqueue_style('flatpickr', 'flatpickr.dark.min', [], '3.0.6');
943
- wp_enqueue_style('wp-color-picker');
944
-
945
- $metadata = CAS_App::instance()->manager()->metadata();
946
- $visibility = [];
947
- $target = [];
948
- foreach ($metadata->get('visibility')->get_input_list() as $category_key => $category) {
949
-
950
- //legacy format
951
- if (!is_array($category)) {
952
- $visibility[] = [
953
- 'id' => $category_key,
954
- 'text' => $category
955
- ];
956
- continue;
957
- }
958
-
959
- $data = [
960
- 'text' => $category['label'],
961
- 'children' => []
962
- ];
963
- foreach ($category['options'] as $key => $value) {
964
- $data['children'][] = [
965
- 'id' => $key,
966
- 'text' => $value
967
- ];
968
- }
969
- $visibility[] = $data;
970
- }
971
- foreach ($metadata->get('host')->get_input_list() as $value => $label) {
972
- $target[] = [
973
- 'id' => $value,
974
- 'text' => $label
975
- ];
976
- }
977
-
978
- if (!cas_fs()->can_use_premium_code()) {
979
- $visibility[] = [
980
- 'text' => __('Upgrade to Pro for more options', 'content-aware-sidebars'),
981
- 'children' => []
982
- ];
983
- }
984
-
985
- global $wp_locale;
986
-
987
- wp_enqueue_script('cas/admin/edit');
988
- wp_localize_script('cas/admin/edit', 'CASAdmin', [
989
- 'allVisibility' => __('All Users', 'content-aware-sidebars'),
990
- 'visibility' => $visibility,
991
- 'target' => $target,
992
- 'weekdays' => [
993
- 'shorthand' => array_values($wp_locale->weekday_abbrev),
994
- 'longhand' => array_values($wp_locale->weekday)
995
- ],
996
- 'months' => [
997
- 'shorthand' => array_values($wp_locale->month_abbrev),
998
- 'longhand' => array_values($wp_locale->month)
999
- ],
1000
- 'weekStart' => get_option('start_of_week', 0),
1001
- 'timeFormat' => get_option('time_format'),
1002
- 'dateFormat' => __('F j, Y') //default long date
1003
- ]);
1004
-
1005
- //badgeos compat
1006
- //todo: check that developers respond with a fix soon
1007
- wp_register_script('badgeos-select2', '');
1008
- wp_register_style('badgeos-select2-css', '');
1009
- }
1010
- }
1
+ <?php
2
+ /**
3
+ * @package Content Aware Sidebars
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ final class CAS_Sidebar_Edit extends CAS_Admin
12
+ {
13
+
14
+ /**
15
+ * Intro tour manager
16
+ * @var WP_Pointer_Tour
17
+ */
18
+ private $_tour_manager;
19
+
20
+ /**
21
+ * Add filters and actions for admin dashboard
22
+ * e.g. AJAX calls
23
+ *
24
+ * @since 3.5
25
+ * @return void
26
+ */
27
+ public function admin_hooks()
28
+ {
29
+ $this->_tour_manager = new WP_Pointer_Tour(CAS_App::META_PREFIX.'cas_tour');
30
+
31
+ $this->add_action('delete_post', 'remove_sidebar_widgets');
32
+ $this->add_action('save_post_'.CAS_App::TYPE_SIDEBAR, 'save_post', 10, 2);
33
+
34
+ $this->add_filter('wp_insert_post_data', 'add_duplicate_title_suffix', 99, 2);
35
+
36
+ if (!cas_fs()->can_use_premium_code()) {
37
+ $this->add_action('wpca/modules/init', 'add_modules');
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Set up admin menu and get current screen
43
+ *
44
+ * @since 3.4
45
+ * @return string
46
+ */
47
+ public function get_screen()
48
+ {
49
+ $post_type_object = $this->get_sidebar_type();
50
+ return add_submenu_page(
51
+ CAS_App::BASE_SCREEN,
52
+ $post_type_object->labels->add_new_item,
53
+ $post_type_object->labels->add_new,
54
+ $post_type_object->cap->edit_posts,
55
+ CAS_App::BASE_SCREEN.'-edit',
56
+ [$this,'render_screen']
57
+ );
58
+ }
59
+
60
+ /**
61
+ * @since 3.5
62
+ *
63
+ * @return bool
64
+ */
65
+ public function authorize_user()
66
+ {
67
+ return true;
68
+ }
69
+
70
+ /**
71
+ * @since 3.4
72
+ *
73
+ * @return void
74
+ */
75
+ public function prepare_screen()
76
+ {
77
+ $this->add_action('cas/admin/add_meta_boxes', 'create_meta_boxes');
78
+
79
+ global $post, $title, $active_post_lock;
80
+
81
+ $post_type = CAS_App::TYPE_SIDEBAR;
82
+ $post_type_object = $this->get_sidebar_type();
83
+ $post_id = isset($_REQUEST['sidebar_id']) ? $_REQUEST['sidebar_id'] : 0;
84
+
85
+ /**
86
+ * Edit mode
87
+ */
88
+ if ($post_id) {
89
+ $this->process_actions($post_id);
90
+
91
+ $post = get_post($post_id, OBJECT, 'edit');
92
+
93
+ if (! $post) {
94
+ wp_die(__('The sidebar no longer exists.'));
95
+ }
96
+ if (! current_user_can($post_type_object->cap->edit_post, $post_id)) {
97
+ wp_die(__('You are not allowed to edit this sidebar.'));
98
+ }
99
+ if ('trash' == $post->post_status) {
100
+ wp_die(__('You cannot edit this sidebar because it is in the Trash. Please restore it and try again.'));
101
+ }
102
+
103
+ if (! empty($_GET['get-post-lock'])) {
104
+ check_admin_referer('lock-post_' . $post_id);
105
+ wp_set_post_lock($post_id);
106
+ wp_redirect(get_edit_post_link($post_id, 'url'));
107
+ exit();
108
+ }
109
+
110
+ if (! wp_check_post_lock($post->ID)) {
111
+ $active_post_lock = wp_set_post_lock($post->ID);
112
+ }
113
+
114
+ $title = $post_type_object->labels->edit_item;
115
+
116
+ /**
117
+ * New Mode
118
+ */
119
+ } else {
120
+ if (! (current_user_can($post_type_object->cap->edit_posts) || current_user_can($post_type_object->cap->create_posts))) {
121
+ wp_die(
122
+ '<p>' . __('You are not allowed to create sidebars.', 'content-aware-sidebars') . '</p>',
123
+ 403
124
+ );
125
+ }
126
+
127
+ $post = get_default_post_to_edit($post_type, true);
128
+
129
+ $title = $post_type_object->labels->add_new_item;
130
+ }
131
+
132
+ do_action('cas/admin/add_meta_boxes', $post);
133
+ }
134
+
135
+ /**
136
+ * @since 3.9
137
+ * @param WPCATypeManager $types
138
+ *
139
+ * @return void
140
+ */
141
+ public function add_modules($types)
142
+ {
143
+ if (!$types->has(CAS_App::TYPE_SIDEBAR)) {
144
+ return;
145
+ }
146
+
147
+ $pro_label = '(Pro)';
148
+ $type = $types->get(CAS_App::TYPE_SIDEBAR);
149
+ $path = plugin_dir_path(dirname(__FILE__));
150
+
151
+ require($path.'conditions/placeholder.php');
152
+
153
+ if (!WPCACore::get_option(CAS_App::TYPE_SIDEBAR, 'legacy.date_module', false)) {
154
+ $module = new CASConditionPlaceholder('cas_date', __('Dates', 'content-aware-sidebars').' '.$pro_label);
155
+ $type->add($module, 'cas_date');
156
+ }
157
+
158
+ $module = new CASConditionPlaceholder('cas_url', __('URLs', 'content-aware-sidebars').' '.$pro_label);
159
+ $type->add($module, 'cas_url');
160
+ $module = new CASConditionPlaceholder('cas_ref_url', __('Referrer URLs', 'content-aware-sidebars').' '.$pro_label);
161
+ $type->add($module, 'cas_ref_url');
162
+
163
+ if (function_exists('bp_is_active')) {
164
+ $module = new CASConditionPlaceholder('cas_bbp', __('BuddyPress Groups', 'content-aware-sidebars').' '.$pro_label, '', '', 'plugins');
165
+ $type->add($module, 'cas_bbp');
166
+ }
167
+
168
+ if (defined('ACF')) {
169
+ $module = new CASConditionPlaceholder('cas_acf', __('Advanced Custom Fields', 'content-aware-sidebars').' '.$pro_label, '', '', 'plugins');
170
+ $type->add($module, 'cas_acf');
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Process actions
176
+ *
177
+ * @since 3.4
178
+ * @param int $post_id
179
+ * @return void
180
+ */
181
+ public function process_actions($post_id)
182
+ {
183
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
184
+ if (isset($_POST['deletepost'])) {
185
+ $action = 'delete';
186
+ }
187
+
188
+ if ($action && $post_id) {
189
+ $sendback = wp_get_referer();
190
+ $sendback = remove_query_arg(
191
+ ['action','trashed', 'untrashed', 'deleted', 'ids'],
192
+ $sendback
193
+ );
194
+ if (isset($_REQUEST['_cas_section']) && $_REQUEST['_cas_section']) {
195
+ $sendback .= $_REQUEST['_cas_section'];
196
+ }
197
+
198
+ $post = get_post($post_id);
199
+ if (! $post) {
200
+ wp_die(__('The sidebar no longer exists.', 'content-aware-sidebars'));
201
+ }
202
+
203
+ check_admin_referer($action . '-post_' . $post_id);
204
+
205
+ switch ($action) {
206
+ case 'update':
207
+
208
+ $post_id = $this->update_sidebar_type();
209
+
210
+ // Session cookie flag that the post was saved
211
+ if (isset($_COOKIE['wp-saving-post']) && $_COOKIE['wp-saving-post'] === $post_id . '-check') {
212
+ setcookie('wp-saving-post', $post_id . '-saved', time() + DAY_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, is_ssl());
213
+ }
214
+
215
+ $status = get_post_status($post_id);
216
+ if (isset($_POST['original_post_status']) && $_POST['original_post_status'] == $status) {
217
+ $message = 1;
218
+ } else {
219
+ switch ($status) {
220
+ case CAS_App::STATUS_SCHEDULED:
221
+ //gets scheduled
222
+ $message = 9;
223
+ break;
224
+ case CAS_App::STATUS_INACTIVE:
225
+ //gets deactivated
226
+ $message = 10;
227
+ break;
228
+ case CAS_App::STATUS_ACTIVE:
229
+ //gets activated
230
+ $message = 6;
231
+ break;
232
+ default:
233
+ $message = 1;
234
+ }
235
+ }
236
+
237
+ $sendback = add_query_arg([
238
+ 'sidebar_id' => $post_id,
239
+ 'message' => $message,
240
+ 'page' => 'wpcas-edit'
241
+ ], $sendback);
242
+ wp_safe_redirect($sendback);
243
+ exit();
244
+ case 'trash':
245
+
246
+ if (! current_user_can('delete_post', $post_id)) {
247
+ wp_die(__('You are not allowed to move this sidebar to the Trash.', 'content-aware-sidebars'));
248
+ }
249
+
250
+ if ($user_id = wp_check_post_lock($post_id)) {
251
+ $user = get_userdata($user_id);
252
+ wp_die(sprintf(__('You cannot move this sidebar to the Trash. %s is currently editing.', 'content-aware-sidebars'), $user->display_name));
253
+ }
254
+
255
+ if (! wp_trash_post($post_id)) {
256
+ wp_die(__('Error in moving to Trash.'));
257
+ }
258
+
259
+ $sendback = remove_query_arg('sidebar_id', $sendback);
260
+
261
+ wp_safe_redirect(add_query_arg(
262
+ [
263
+ 'page' => 'wpcas',
264
+ 'trashed' => 1,
265
+ 'ids' => $post_id
266
+ ],
267
+ $sendback
268
+ ));
269
+ exit();
270
+ case 'untrash':
271
+
272
+ if (! current_user_can('delete_post', $post_id)) {
273
+ wp_die(__('You are not allowed to restore this sidebar from the Trash.', 'content-aware-sidebars'));
274
+ }
275
+
276
+ if (! wp_untrash_post($post_id)) {
277
+ wp_die(__('Error in restoring from Trash.'));
278
+ }
279
+
280
+ wp_safe_redirect(add_query_arg('untrashed', 1, $sendback));
281
+ exit();
282
+ case 'delete':
283
+
284
+ if (! current_user_can('delete_post', $post_id)) {
285
+ wp_die(__('You are not allowed to delete this sidebar.', 'content-aware-sidebars'));
286
+ }
287
+
288
+ if (! wp_delete_post($post_id, true)) {
289
+ wp_die(__('Error in deleting.'));
290
+ }
291
+
292
+ $sendback = remove_query_arg('sidebar_id', $sendback);
293
+ wp_safe_redirect(add_query_arg([
294
+ 'page' => 'wpcas',
295
+ 'deleted' => 1
296
+ ], $sendback));
297
+ exit();
298
+ default:
299
+ do_action('cas/admin/action', $action, $post);
300
+ break;
301
+ }
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Render screen
307
+ *
308
+ * @since 3.4
309
+ * @return void
310
+ */
311
+ public function render_screen()
312
+ {
313
+ global $post, $active_post_lock;
314
+
315
+ $post_type_object = get_post_type_object($post->post_type);
316
+ $post_id = isset($_REQUEST['sidebar_id']) ? $_REQUEST['sidebar_id'] : 0;
317
+
318
+ $form_extra = '';
319
+ if ('auto-draft' == $post->post_status) {
320
+ if (isset($_REQUEST['sidebar_id'])) {
321
+ $post->post_title = '';
322
+ }
323
+ $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />";
324
+ }
325
+
326
+ if ($post_id) {
327
+ $title = __('Edit');
328
+ } else {
329
+ $title = $post_type_object->labels->new_item;
330
+ }
331
+
332
+ echo '<div class="wrap">';
333
+ echo '<h1>';
334
+ echo '<a href="'.admin_url('admin.php?page=wpcas').'">'.$post_type_object->labels->all_items.'</a> &raquo; ';
335
+ echo esc_html($title);
336
+ if (isset($_REQUEST['sidebar_id']) && current_user_can('edit_theme_options')) {
337
+ echo ' <a href="' . esc_url(admin_url('widgets.php#'.CAS_App::SIDEBAR_PREFIX.$post->ID)) . '" class="page-title-action add-new-h2">' . __('Manage Widgets', 'content-aware-sidebars') . '</a>';
338
+ }
339
+
340
+ echo '</h1>';
341
+
342
+ $this->sidebar_updated_messages($post);
343
+
344
+ echo '<form name="post" action="admin.php?page=wpcas-edit" method="post" id="post">';
345
+ $referer = wp_get_referer();
346
+ wp_nonce_field('update-post_' . $post->ID);
347
+ echo '<input type="hidden" id="user-id" name="user_ID" value="'.(int)get_current_user_id().'" />';
348
+ echo '<input type="hidden" id="_cas_section" name="_cas_section" value="" />';
349
+ echo '<input type="hidden" id="hiddenaction" name="action" value="update" />';
350
+ echo '<input type="hidden" id="post_author" name="post_author" value="'.esc_attr($post->post_author).'" />';
351
+ echo '<input type="hidden" id="original_post_status" name="original_post_status" value="'.esc_attr($post->post_status).'" />';
352
+ echo '<input type="hidden" id="referredby" name="referredby" value="'.($referer ? esc_url($referer) : '').'" />';
353
+ echo '<input type="hidden" id="post_ID" name="sidebar_id" value="'.esc_attr($post->ID).'" />';
354
+ if (! empty($active_post_lock)) {
355
+ echo '<input type="hidden" id="active_post_lock" value="'.esc_attr(implode(':', $active_post_lock)).'" />';
356
+ }
357
+ if (get_post_status($post) != CAS_App::STATUS_INACTIVE) {
358
+ wp_original_referer_field(true, 'previous');
359
+ }
360
+ echo $form_extra;
361
+
362
+ $nav_tabs = [
363
+ 'conditions' => __('Conditions', 'content-aware-sidebars'),
364
+ 'action' => __('Action', 'content-aware-sidebars'),
365
+ 'design' => __('Design', 'content-aware-sidebars'),
366
+ 'schedule' => __('Schedule', 'content-aware-sidebars'),
367
+ 'advanced' => __('Options', 'content-aware-sidebars')
368
+ ];
369
+ $nav_tabs = apply_filters('cas/admin/nav-tabs', $nav_tabs);
370
+
371
+ echo '<div id="poststuff">';
372
+ echo '<div id="post-body" class="cas-metabox-holder metabox-holder columns-2">';
373
+ echo '<div id="post-body-content">';
374
+ echo '<div id="titlediv">';
375
+ echo '<div id="titlewrap">';
376
+ echo '<label class="screen-reader-text" id="title-prompt-text" for="title">'.__('Enter title here').'</label>';
377
+ echo '<input type="text" name="post_title" size="30" value="'.esc_attr($post->post_title).'" id="title" spellcheck="true" autocomplete="off" />';
378
+ echo '</div></div>';
379
+ $this->render_section_nav($nav_tabs);
380
+ echo '</div>';
381
+ $this->render_sections($nav_tabs, $post, $post->post_type);
382
+ echo '</div>';
383
+ echo '<br class="clear" />';
384
+ echo '</div></form></div>';
385
+ }
386
+
387
+ /**
388
+ * Render tab navigation
389
+ *
390
+ * @since 3.4
391
+ * @param array $tabs
392
+ * @return void
393
+ */
394
+ public function render_section_nav($tabs)
395
+ {
396
+ echo '<h2 class="nav-tab-wrapper js-cas-tabs hide-if-no-js " style="padding-bottom:0;">';
397
+ foreach ($tabs as $id => $label) {
398
+ echo '<a class="js-nav-link nav-tab nav-tab-section-'.$id.'" href="#top#section-'.$id.'">'.$label.'</a>';
399
+ }
400
+ echo '</h2>';
401
+ }
402
+
403
+ /**
404
+ * Render meta box sections
405
+ *
406
+ * @since 3.4
407
+ * @param array $tabs
408
+ * @param WP_Post $post
409
+ * @param string $post_type
410
+ * @return void
411
+ */
412
+ public function render_sections($tabs, $post, $post_type)
413
+ {
414
+ echo '<div id="postbox-container-1" class="postbox-container">';
415
+ do_meta_boxes(CAS_App::BASE_SCREEN.'-edit', 'side', $post);
416
+ echo '</div>';
417
+ echo '<div id="postbox-container-2" class="postbox-container">';
418
+ foreach ($tabs as $id => $label) {
419
+ $name = 'section-'.$id;
420
+ echo '<div id="'.$name.'" class="cas-section">';
421
+ do_meta_boxes(CAS_App::BASE_SCREEN.'-edit', $name, $post);
422
+ echo '</div>';
423
+ }
424
+ //boxes across sections
425
+ do_meta_boxes(CAS_App::BASE_SCREEN.'-edit', 'normal', $post);
426
+ echo '</div>';
427
+ }
428
+
429
+ /**
430
+ * Update sidebar post type
431
+ *
432
+ * @since 3.4
433
+ * @return int
434
+ */
435
+ public function update_sidebar_type()
436
+ {
437
+ global $wpdb;
438
+
439
+ $post_ID = (int) $_POST['sidebar_id'];
440
+ $post = get_post($post_ID);
441
+ $post_data['post_type'] = CAS_App::TYPE_SIDEBAR;
442
+ $post_data['ID'] = (int) $post_ID;
443
+ $post_data['post_title'] = $_POST['post_title'];
444
+ $post_data['comment_status'] = 'closed';
445
+ $post_data['ping_status'] = 'closed';
446
+ $post_data['post_author'] = get_current_user_id();
447
+ $post_data['menu_order'] = intval($_POST['menu_order']);
448
+
449
+ $ptype = get_post_type_object($post_data['post_type']);
450
+
451
+ if (!current_user_can('edit_post', $post_ID)) {
452
+ wp_die(__('You are not allowed to edit this sidebar.', 'content-aware-sidebars'));
453
+ } elseif (! current_user_can($ptype->cap->create_posts)) {
454
+ return new WP_Error('edit_others_posts', __('You are not allowed to create sidebars.', 'content-aware-sidebars'));
455
+ } elseif ($post_data['post_author'] != $_POST['post_author']
456
+ && ! current_user_can($ptype->cap->edit_others_posts)) {
457
+ return new WP_Error('edit_others_posts', __('You are not allowed to edit this sidebar.', 'content-aware-sidebars'));
458
+ }
459
+
460
+ if (isset($_POST['post_status'])) {
461
+ $post_data['post_status'] = CAS_App::STATUS_ACTIVE;
462
+ //if sidebar has been future before, we need to reset date
463
+ if ($_POST['post_status'] != $_POST['original_post_status']) {
464
+ $post_data['post_date'] = current_time('mysql');
465
+ }
466
+ } elseif ($_POST['sidebar_activate']) {
467
+ $_POST['post_status'] = CAS_App::STATUS_SCHEDULED; //yoast seo expects this
468
+ $post_data['post_status'] = CAS_App::STATUS_SCHEDULED;
469
+ $post_data['post_date'] = $_POST['sidebar_activate'];
470
+ } else {
471
+ $_POST['post_status'] = CAS_App::STATUS_INACTIVE;
472
+ $post_data['post_status'] = CAS_App::STATUS_INACTIVE;
473
+ }
474
+
475
+ if ($post_data['post_status'] != CAS_App::STATUS_INACTIVE
476
+ && $_POST['sidebar_deactivate']) {
477
+ $this->reschedule_deactivation($post_ID, $_POST['sidebar_deactivate']);
478
+ } else {
479
+ $this->reschedule_deactivation($post_ID);
480
+ }
481
+
482
+ if (isset($post_data['post_date'])) {
483
+ $post_data['post_date_gmt'] = get_gmt_from_date($post_data['post_date']);
484
+ }
485
+
486
+ if (post_type_supports(CAS_App::TYPE_SIDEBAR, 'revisions')) {
487
+ $revisions = wp_get_post_revisions($post_ID, [
488
+ 'order' => 'ASC',
489
+ 'posts_per_page' => 1
490
+ ]);
491
+ $revision = current($revisions);
492
+ // Check if the revisions have been upgraded
493
+ if ($revisions && _wp_get_post_revision_version($revision) < 1) {
494
+ _wp_upgrade_revisions_of_post($post, wp_get_post_revisions($post_ID));
495
+ }
496
+ }
497
+
498
+ update_post_meta($post_ID, '_edit_last', $post_data['post_author']);
499
+ wp_update_post($post_data);
500
+ wp_set_post_lock($post_ID);
501
+
502
+ return $post_ID;
503
+ }
504
+
505
+ /**
506
+ * Handle schedule for deactivation
507
+ *
508
+ * @since 3.4
509
+ * @param int $post_id
510
+ * @param string $time
511
+ * @return void
512
+ */
513
+ public function reschedule_deactivation($post_id, $time = false)
514
+ {
515
+ $name = 'cas/event/deactivate';
516
+ if (wp_next_scheduled($name, [$post_id]) !== false) {
517
+ wp_clear_scheduled_hook($name, [$post_id]);
518
+ }
519
+
520
+ if ($time) {
521
+ //Requires to be in GMT
522
+ $utime = get_gmt_from_date($time, 'U');
523
+ wp_schedule_single_event($utime, $name, [$post_id]);
524
+ update_post_meta($post_id, CAS_App::META_PREFIX.'deactivate_time', $time);
525
+ } else {
526
+ delete_post_meta($post_id, CAS_App::META_PREFIX.'deactivate_time');
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Create update messages
532
+ *
533
+ * @param WP_Post $post
534
+ *
535
+ * @return void
536
+ */
537
+ public function sidebar_updated_messages($post)
538
+ {
539
+ $message_number = isset($_GET['message']) ? absint($_GET['message']) : null;
540
+
541
+ if (is_null($message_number)) {
542
+ return;
543
+ }
544
+
545
+ $manage_widgets = sprintf(' <a href="%1$s">%2$s</a>', esc_url(admin_url('widgets.php#'.CAS_App::SIDEBAR_PREFIX.$post->ID)), __('Manage widgets', 'content-aware-sidebars'));
546
+ $messages = [
547
+ 1 => __('Sidebar updated.', 'content-aware-sidebars').$manage_widgets,
548
+ 6 => __('Sidebar activated.', 'content-aware-sidebars').$manage_widgets,
549
+ 9 => sprintf(
550
+ __('Sidebar scheduled for: <strong>%1$s</strong>.', 'content-aware-sidebars'),
551
+ // translators: Publish box date format, see http://php.net/date
552
+ date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date))
553
+ ).$manage_widgets,
554
+ 10 => __('Sidebar deactivated.', 'content-aware-sidebars').$manage_widgets,
555
+ ];
556
+ $messages = apply_filters('cas/admin/messages', $messages, $post);
557
+
558
+ if (isset($messages[$message_number])) {
559
+ echo '<div id="message" class="updated notice notice-success is-dismissible"><p>'.$messages[$message_number].'</p></div>';
560
+ }
561
+ }
562
+
563
+ /**
564
+ * Set pointers for tour and enqueue script
565
+ *
566
+ * @since 3.3
567
+ * @return void
568
+ */
569
+ private function create_pointers()
570
+ {
571
+ if ($this->_tour_manager->user_has_finished_tour()) {
572
+ return;
573
+ }
574
+
575
+ $this->_tour_manager->set_pointers([
576
+ [
577
+ 'content' => sprintf(
578
+ '<h3>%s</h3>%s',
579
+ __('Get Started in 60 Seconds', 'content-aware-sidebars'),
580
+ '<p>'.__('Welcome to Content Aware Sidebars!', 'content-aware-sidebars').'</p>'.
581
+ '<p>'.__('This interactive guide will show you just how easy it is to create a widget area and control where, how, and when to display it.', 'content-aware-sidebars').'</p>'
582
+ ),
583
+ 'ref_id' => '#titlediv',
584
+ 'position' => [
585
+ 'edge' => 'top',
586
+ 'align' => 'center'
587
+ ],
588
+ 'pointerWidth' => 400,
589
+ 'next' => __('Start Quick Tour', 'content-aware-sidebars'),
590
+ 'dismiss' => __('Skip - I know what to do', 'content-aware-sidebars')
591
+ ],
592
+ [
593
+ 'content' => sprintf(
594
+ '<h3>%s</h3>%s',
595
+ '1/5 '.__('Where to display', 'content-aware-sidebars'),
596
+ '<p>'.__('Choose from the extensive Display Conditions with built-in support for other plugins. You will never be asked to enter widget logic PHP code!', 'content-aware-sidebars').'</p>'.
597
+ '<p>'.__('Select anything to continue the tour. You can change it later.', 'content-aware-sidebars').'</p>'
598
+ ),
599
+ 'ref_id' => '.cas-group-new',
600
+ 'position' => [
601
+ 'edge' => 'top',
602
+ 'align' => 'center'
603
+ ],
604
+ 'prev' => false,
605
+ 'next' => '.js-wpca-add-or, .js-wpca-add-quick',
606
+ 'nextEvent' => 'select2:select click',
607
+ 'dismiss' => false
608
+ ],
609
+ [
610
+ 'content' => sprintf(
611
+ '<h3>%s</h3>%s',
612
+ '2/5 '.__('Where to display', 'content-aware-sidebars'),
613
+ '<p>'.__('Click on the input field and select the content you want - just type to search. Changes are saved automatically!', 'content-aware-sidebars').'</p>'.
614
+ '<p>'.__('You can add multiple content types to the same group. Try e.g. "All Posts" and an Author to display on all posts written by that author.', 'content-aware-sidebars').'</p>'.
615
+ '<p>'.sprintf('<a href="%s" target="_blank" rel="noopener">'.__('Learn more about AND vs OR conditions', 'content-aware-sidebars').'</a>', 'https://dev.institute/docs/content-aware-sidebars/getting-started/display-sidebar-advanced/').'</p>'
616
+ ),
617
+ 'ref_id' => '#cas-groups > ul',
618
+ 'position' => [
619
+ 'edge' => 'top',
620
+ 'align' => 'center'
621
+ ],
622
+ 'dismiss' => __('Close Tour', 'content-aware-sidebars')
623
+ ],
624
+ [
625
+ 'content' => sprintf(
626
+ '<h3>%s</h3>%s',
627
+ '3/5 '.__('How to display', 'content-aware-sidebars'),
628
+ '<p>'.__('Replace any sidebar or widget area in your theme, or add widgets by merging with them.', 'content-aware-sidebars').'</p>'.
629
+ '<p>'.__('You can also use the shortcode to display widgets inside a page or post.', 'content-aware-sidebars').'</p>'
630
+ ),
631
+ 'ref_id' => '.nav-tab-wrapper.js-cas-tabs .nav-tab-section-action',
632
+ 'position' => [
633
+ 'edge' => 'left',
634
+ 'align' => 'left'
635
+ ],
636
+ 'dismiss' => __('Close Tour', 'content-aware-sidebars')
637
+ ],
638
+ [
639
+ 'content' => sprintf(
640
+ '<h3>%s</h3>%s',
641
+ '4/5 '.__('When to activate', 'content-aware-sidebars'),
642
+ '<p>'.__('Create a widget area and manage its widgets today, then publish it when you are ready.', 'content-aware-sidebars').'</p>'.
643
+ '<p>'.__('To schedule automatic activation or deactivation, just pick a date and time!', 'content-aware-sidebars').'</p>'.
644
+ '<p>'.__('By default, new widget areas will be activated when created.', 'content-aware-sidebars').'</p>'
645
+ ),
646
+ 'ref_id' => '.nav-tab-wrapper.js-cas-tabs .nav-tab-section-schedule',
647
+ 'position' => [
648
+ 'edge' => 'left',
649
+ 'align' => 'left'
650
+ ],
651
+ 'dismiss' => __('Close Tour', 'content-aware-sidebars')
652
+ ],
653
+ [
654
+ 'content' => sprintf(
655
+ '<h3>%s</h3>%s',
656
+ '5/5 '.__('How to look', 'content-aware-sidebars'),
657
+ '<p>'.__('Personalize the styling without writing any code!', 'content-aware-sidebars').'</p>'.
658
+ '<p>'.__('You can modify the HTML and CSS classes of the widget area itself, each widget, as well as widget titles.', 'content-aware-sidebars').'</p>'
659
+ ),
660
+ 'ref_id' => '.nav-tab-wrapper.js-cas-tabs .nav-tab-section-design',
661
+ 'position' => [
662
+ 'edge' => 'left',
663
+ 'align' => 'left'
664
+ ],
665
+ 'next' => __('Finish Tour', 'content-aware-sidebars')
666
+ ],
667
+ [
668
+ 'content' => sprintf(
669
+ '<h3>%s</h3>%s',
670
+ __("That's it", 'content-aware-sidebars'),
671
+ '<p>'.__('Hit the Create button to save your first custom widget area.', 'content-aware-sidebars').'</p>'.
672
+ '<p>'.__('If you need more help, check out the links below.', 'content-aware-sidebars').'</p>'
673
+ ),
674
+ 'ref_id' => '#submitdiv',
675
+ 'position' => [
676
+ 'edge' => 'right',
677
+ 'align' => 'top'
678
+ ],
679
+ 'dismiss' => __('Close', 'content-aware-sidebars')
680
+ ]
681
+ ]);
682
+ $this->_tour_manager->enqueue_scripts();
683
+ }
684
+
685
+ /**
686
+ * Meta boxes for sidebar edit
687
+ * @global object $post
688
+ * @return void
689
+ */
690
+ public function create_meta_boxes($post)
691
+ {
692
+ $this->create_pointers();
693
+ CAS_App::instance()->manager()->populate_metadata();
694
+ $path = plugin_dir_path(dirname(__FILE__)).'view/';
695
+
696
+ $boxes = [];
697
+ $boxes[] = [
698
+ 'id' => 'submitdiv',
699
+ 'title' => __('Publish'),
700
+ 'view' => 'submit',
701
+ 'context' => 'side',
702
+ 'priority' => 'high'
703
+ ];
704
+ $boxes[] = [
705
+ 'id' => 'cas-options',
706
+ 'title' => __('How to display', 'content-aware-sidebars'),
707
+ 'view' => 'action',
708
+ 'context' => 'section-action',
709
+ ];
710
+ $boxes[] = [
711
+ 'id' => 'cas-status',
712
+ 'title' => __('Status', 'content-aware-sidebars'),
713
+ 'view' => 'status',
714
+ 'context' => 'section-schedule',
715
+ ];
716
+ $boxes[] = [
717
+ 'id' => 'cas-widget-html',
718
+ 'title' => __('Styles', 'content-aware-sidebars'),
719
+ 'view' => 'html',
720
+ 'context' => 'section-design',
721
+ ];
722
+ $boxes[] = [
723
+ 'id' => 'cas-advanced',
724
+ 'title' => __('Options', 'content-aware-sidebars'),
725
+ 'view' => 'advanced',
726
+ 'context' => 'section-advanced',
727
+ ];
728
+ $boxes[] = [
729
+ 'id' => 'cas-plugin-links',
730
+ 'title' => __('Recommendations', 'content-aware-sidebars'),
731
+ 'view' => 'support',
732
+ 'context' => 'side',
733
+ ];
734
+ $boxes[] = [
735
+ 'id' => 'cas-schedule',
736
+ 'title' => __('Time Schedule', 'content-aware-sidebars').' <span class="cas-pro-label">'.__('Pro', 'content-aware-sidebars').'</span>',
737
+ 'view' => 'schedule',
738
+ 'context' => 'section-schedule',
739
+ ];
740
+ $boxes[] = [
741
+ 'id' => 'cas-design',
742
+ 'title' => __('Design', 'content-aware-sidebars').' <span class="cas-pro-label">'.__('Pro', 'content-aware-sidebars').'</span>',
743
+ 'view' => 'design',
744
+ 'context' => 'section-design',
745
+ ];
746
+
747
+ foreach ($boxes as $box) {
748
+ $view = WPCAView::make($path.'meta_box_'.$box['view'].'.php', [
749
+ 'post' => $post
750
+ ]);
751
+
752
+ add_meta_box(
753
+ $box['id'],
754
+ $box['title'],
755
+ [$view,'render'],
756
+ CAS_App::BASE_SCREEN.'-edit',
757
+ $box['context'],
758
+ isset($box['priority']) ? $box['priority'] : 'default'
759
+ );
760
+ }
761
+
762
+ //todo: refactor add of meta box
763
+ //with new bootstrapper, legacy core might be loaded
764
+ if (method_exists('WPCACore', 'render_group_meta_box')) {
765
+ WPCACore::render_group_meta_box($post, CAS_App::BASE_SCREEN.'-edit', 'section-conditions', 'default');
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Create form field for metadata
771
+ * @global object $post
772
+ * @param array $setting
773
+ * @return void
774
+ */
775
+ public static function form_field($id, $class = '', $icon = '')
776
+ {
777
+ $setting = CAS_App::instance()->manager()->metadata()->get($id);
778
+ $current = $setting->get_data(get_the_ID(), true, $setting->get_input_type() != 'multi');
779
+ $icon = $icon ? '<span class="'.$icon.'"></span> ' : '';
780
+
781
+ echo '<div class="'.$class.'">'.$icon.'<strong>' . $setting->get_title() . '</strong>';
782
+ echo '<p>';
783
+ switch ($setting->get_input_type()) {
784
+ case 'select':
785
+ echo '<select style="width:250px;" name="' . $id . '" class="js-cas-'.$id.'">' . "\n";
786
+ foreach ($setting->get_input_list() as $key => $value) {
787
+ $disabled = '';
788
+ if (is_string($key) && strpos($key, '__') === 0) {
789
+ $disabled = ' disabled="disabled"';
790
+ }
791
+ echo '<option value="' . $key . '"' . selected($current, $key, false) . $disabled . '>' . $value . '</option>' . "\n";
792
+ }
793
+ echo '</select>' . "\n";
794
+ break;
795
+ case 'checkbox':
796
+ echo '<ul>' . "\n";
797
+ foreach ($setting->get_input_list() as $key => $value) {
798
+ echo '<li><label><input type="checkbox" name="' . $id . '[]" class="js-cas-'.$id.'" value="' . $key . '"' . (in_array($key, $current) ? ' checked="checked"' : '') . ' /> ' . $value . '</label></li>' . "\n";
799
+ }
800
+ echo '</ul>' . "\n";
801
+ break;
802
+ case 'multi':
803
+ echo '<div><select style="width:100%;" class="js-cas-'.$id.'" multiple="multiple" name="' . $id . '[]" data-value="'.implode(',', $current).'"></select></div>';
804
+ break;
805
+ case 'text':
806
+ default:
807
+ echo '<input style="width:200px;" type="text" name="' . $id . '" value="' . $current . '" />' . "\n";
808
+ break;
809
+ }
810
+ echo '</p></div>';
811
+ }
812
+
813
+ /**
814
+ * Save meta values for post
815
+ * @param int $post_id
816
+ * @return void
817
+ */
818
+ public function save_post($post_id, $post)
819
+ {
820
+
821
+ //Verify nonce, check_admin_referer dies on false
822
+ if (!(isset($_POST[WPCACore::NONCE])
823
+ && wp_verify_nonce($_POST[WPCACore::NONCE], WPCACore::PREFIX.$post_id))) {
824
+ return;
825
+ }
826
+
827
+ // Check permissions
828
+ if (!current_user_can(CAS_App::CAPABILITY, $post_id)) {
829
+ return;
830
+ }
831
+
832
+ // Check autosave
833
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
834
+ return;
835
+ }
836
+
837
+ // Save metadata
838
+ // todo: wrap this in metadata manager?
839
+ foreach (CAS_App::instance()->manager()->metadata() as $field) {
840
+ $field->save($post_id);
841
+ }
842
+ }
843
+
844
+ /**
845
+ * Add suffix when creating sidebar with existing name
846
+ * Does not stop duplicate titles on update
847
+ *
848
+ * @since 3.4.3
849
+ * @param array $insert_data
850
+ * @param array $data
851
+ * @return array
852
+ */
853
+ public function add_duplicate_title_suffix($insert_data, $data)
854
+ {
855
+ if ($data['post_type'] == CAS_App::TYPE_SIDEBAR && !$data['ID']) {
856
+ $sidebars = CAS_App::instance()->manager()->sidebars;
857
+ $sidebar_titles = [];
858
+ foreach ($sidebars as $sidebar) {
859
+ $sidebar_titles[$sidebar->post_title] = 1;
860
+ }
861
+ //if title exists, add a suffix
862
+ $i = 0;
863
+ $title = wp_unslash($insert_data['post_title']);
864
+ $new_title = $title;
865
+ while (isset($sidebar_titles[$new_title])) {
866
+ $new_title = $title.' ('.++$i.')';
867
+ }
868
+ if ($i) {
869
+ $insert_data['post_title'] = wp_slash($new_title);
870
+ }
871
+ }
872
+ return $insert_data;
873
+ }
874
+
875
+ /**
876
+ * Remove widget when its sidebar is removed
877
+ * @param int $post_id
878
+ * @return void
879
+ */
880
+ public function remove_sidebar_widgets($post_id)
881
+ {
882
+
883
+ // Authenticate and only continue on sidebar post type
884
+ if (!current_user_can(CAS_App::CAPABILITY) || get_post_type($post_id) != CAS_App::TYPE_SIDEBAR) {
885
+ return;
886
+ }
887
+
888
+ $id = CAS_App::SIDEBAR_PREFIX . $post_id;
889
+
890
+ //Get widgets
891
+ $sidebars_widgets = wp_get_sidebars_widgets();
892
+
893
+ // Check if sidebar exists in database
894
+ if (!isset($sidebars_widgets[$id])) {
895
+ return;
896
+ }
897
+
898
+ // Remove widgets settings from sidebar
899
+ foreach ($sidebars_widgets[$id] as $widget_id) {
900
+ $widget_type = preg_replace('/-[0-9]+$/', '', $widget_id);
901
+ $widget_settings = get_option('widget_' . $widget_type);
902
+ $widget_id = substr($widget_id, strpos($widget_id, '-') + 1);
903
+ if ($widget_settings && isset($widget_settings[$widget_id])) {
904
+ unset($widget_settings[$widget_id]);
905
+ update_option('widget_' . $widget_type, $widget_settings);
906
+ }
907
+ }
908
+
909
+ // Remove sidebar
910
+ unset($sidebars_widgets[$id]);
911
+ wp_set_sidebars_widgets($sidebars_widgets);
912
+ }
913
+
914
+ /**
915
+ * Register and enqueue scripts styles
916
+ * for screen
917
+ *
918
+ * @since 3.4
919
+ */
920
+ public function add_scripts_styles()
921
+ {
922
+ if (is_multisite()) {
923
+ add_action('admin_footer', '_admin_notice_post_locked');
924
+ } else {
925
+ $check_users = get_users([ 'fields' => 'ID', 'number' => 2 ]);
926
+ if (count($check_users) > 1) {
927
+ add_action('admin_footer', '_admin_notice_post_locked');
928
+ }
929
+ }
930
+
931
+ wp_enqueue_script('wp-a11y');
932
+
933
+ if (wp_is_mobile()) {
934
+ wp_enqueue_script('jquery-touch-punch');
935
+ }
936
+
937
+ WPCACore::enqueue_scripts_styles('');
938
+
939
+ $this->register_script('flatpickr', 'flatpickr', [], '3.0.6');
940
+ $this->register_script('cas/admin/edit', 'cas_admin', ['jquery','flatpickr','wp-color-picker']);
941
+
942
+ $this->enqueue_style('flatpickr', 'flatpickr.dark.min', [], '3.0.6');
943
+ wp_enqueue_style('wp-color-picker');
944
+
945
+ $metadata = CAS_App::instance()->manager()->metadata();
946
+ $visibility = [];
947
+ $target = [];
948
+ foreach ($metadata->get('visibility')->get_input_list() as $category_key => $category) {
949
+
950
+ //legacy format
951
+ if (!is_array($category)) {
952
+ $visibility[] = [
953
+ 'id' => $category_key,
954
+ 'text' => $category
955
+ ];
956
+ continue;
957
+ }
958
+
959
+ $data = [
960
+ 'text' => $category['label'],
961
+ 'children' => []
962
+ ];
963
+ foreach ($category['options'] as $key => $value) {
964
+ $data['children'][] = [
965
+ 'id' => $key,
966
+ 'text' => $value
967
+ ];
968
+ }
969
+ $visibility[] = $data;
970
+ }
971
+ foreach ($metadata->get('host')->get_input_list() as $value => $label) {
972
+ $target[] = [
973
+ 'id' => $value,
974
+ 'text' => $label
975
+ ];
976
+ }
977
+
978
+ if (!cas_fs()->can_use_premium_code()) {
979
+ $visibility[] = [
980
+ 'text' => __('Upgrade to Pro for more options', 'content-aware-sidebars'),
981
+ 'children' => []
982
+ ];
983
+ }
984
+
985
+ global $wp_locale;
986
+
987
+ wp_enqueue_script('cas/admin/edit');
988
+ wp_localize_script('cas/admin/edit', 'CASAdmin', [
989
+ 'allVisibility' => __('All Users', 'content-aware-sidebars'),
990
+ 'visibility' => $visibility,
991
+ 'target' => $target,
992
+ 'weekdays' => [
993
+ 'shorthand' => array_values($wp_locale->weekday_abbrev),
994
+ 'longhand' => array_values($wp_locale->weekday)
995
+ ],
996
+ 'months' => [
997
+ 'shorthand' => array_values($wp_locale->month_abbrev),
998
+ 'longhand' => array_values($wp_locale->month)
999
+ ],
1000
+ 'weekStart' => get_option('start_of_week', 0),
1001
+ 'timeFormat' => get_option('time_format'),
1002
+ 'dateFormat' => __('F j, Y') //default long date
1003
+ ]);
1004
+
1005
+ //badgeos compat
1006
+ //todo: check that developers respond with a fix soon
1007
+ wp_register_script('badgeos-select2', '');
1008
+ wp_register_style('badgeos-select2-css', '');
1009
+ }
1010
+ }
admin/sidebar-list-table.php CHANGED
@@ -1,713 +1,713 @@
1
- <?php
2
- /**
3
- * @package Content Aware Sidebars
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- if (! class_exists('WP_List_Table')) {
12
- require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
13
- }
14
-
15
- class CAS_Sidebar_List_Table extends WP_List_Table
16
- {
17
-
18
- /**
19
- * Trash view
20
- * @var boolean
21
- */
22
- private $is_trash;
23
-
24
- private $visibility = [];
25
-
26
- public function __construct($args = [])
27
- {
28
- parent::__construct([
29
- 'singular' => 'sidebar',
30
- 'plural' => 'sidebars',
31
- 'ajax' => false,
32
- 'screen' => isset($args['screen']) ? $args['screen'] : null
33
- ]);
34
- }
35
-
36
- /**
37
- * Load filtered sidebars for current query
38
- *
39
- * @since 3.4
40
- * @return void
41
- */
42
- public function prepare_items()
43
- {
44
- global $avail_post_stati, $wp_query;
45
-
46
- $this->_column_headers = $this->get_column_info();
47
-
48
- $avail_post_stati = get_available_post_statuses(CAS_App::TYPE_SIDEBAR);
49
-
50
- $per_page = $this->get_items_per_page('cas_sidebars_per_page', 20);
51
- $current_page = $this->get_pagenum();
52
-
53
- $args = [
54
- 'post_type' => CAS_App::TYPE_SIDEBAR,
55
- 'post_status' => [
56
- CAS_App::STATUS_ACTIVE,
57
- CAS_App::STATUS_INACTIVE,
58
- CAS_App::STATUS_SCHEDULED
59
- ],
60
- 'posts_per_page' => $per_page,
61
- 'paged' => $current_page,
62
- 'orderby' => 'title',
63
- 'order' => 'asc',
64
- 'update_post_term_cache' => false
65
- ];
66
-
67
- if (isset($_REQUEST['s']) && strlen($_REQUEST['s'])) {
68
- $args['s'] = $_REQUEST['s'];
69
- }
70
-
71
- //Make sure post_status!=all if present to avoid auto-drafts
72
- if (isset($_REQUEST['post_status']) && $_REQUEST['post_status'] != 'all') {
73
- $args['post_status'] = $_REQUEST['post_status'];
74
- }
75
-
76
- if (isset($_REQUEST['orderby'])) {
77
- $meta = str_replace('meta_', '', $_REQUEST['orderby']);
78
- if ($meta != $_REQUEST['orderby']) {
79
- $args['orderby'] = 'meta_value';
80
- $args['meta_key'] = CAS_App::META_PREFIX . $meta;
81
- } else {
82
- $args['orderby'] = $_REQUEST['orderby'];
83
- }
84
- }
85
-
86
- if (isset($_REQUEST['order'])) {
87
- $args['order'] = $_REQUEST['order'] == 'asc' ? 'asc' : 'desc';
88
- }
89
-
90
- $wp_query = new WP_Query($args);
91
-
92
- if ($wp_query->found_posts || $current_page === 1) {
93
- $total_items = $wp_query->found_posts;
94
- } else {
95
- $post_counts = (array) wp_count_posts(CAS_App::TYPE_SIDEBAR);
96
-
97
- if (isset($_REQUEST['post_status']) && in_array($_REQUEST['post_status'], $avail_post_stati)) {
98
- $total_items = $post_counts[ $_REQUEST['post_status'] ];
99
- } else {
100
- $total_items = array_sum($post_counts);
101
-
102
- // Subtract post types that are not included in the admin all list.
103
- foreach (get_post_stati([ 'show_in_admin_all_list' => false ]) as $state) {
104
- $total_items -= $post_counts[ $state ];
105
- }
106
- }
107
- }
108
-
109
- $this->items = $wp_query->posts;
110
- $this->is_trash = isset($_REQUEST['post_status']) && $_REQUEST['post_status'] == 'trash';
111
- $this->set_pagination_args([
112
- 'total_items' => $total_items,
113
- 'total_pages' => ceil($total_items / $per_page),
114
- 'per_page' => $per_page
115
- ]);
116
-
117
- //Make sure filter is run
118
- CAS_App::instance()->manager()->populate_metadata();
119
- }
120
-
121
- /**
122
- * Render on no items
123
- *
124
- * @since 3.4
125
- * @return void
126
- */
127
- public function no_items()
128
- {
129
- if ($this->is_trash) {
130
- echo get_post_type_object(CAS_App::TYPE_SIDEBAR)->labels->not_found_in_trash;
131
- } else {
132
- //todo show more text to get started
133
- echo get_post_type_object(CAS_App::TYPE_SIDEBAR)->labels->not_found;
134
- }
135
- }
136
-
137
- /**
138
- * Get link to view
139
- *
140
- * @since 3.4
141
- * @param array $args
142
- * @param string $label
143
- * @param string $class
144
- * @return string
145
- */
146
- public function get_view_link($args, $label, $class = '')
147
- {
148
- $screen = get_current_screen();
149
- $args['page'] = $screen->parent_base;
150
- $url = add_query_arg($args, 'admin.php');
151
-
152
- $class_html = '';
153
- if (! empty($class)) {
154
- $class_html = sprintf(
155
- ' class="%s"',
156
- esc_attr($class)
157
- );
158
- }
159
-
160
- return sprintf(
161
- '<a href="%s"%s>%s</a>',
162
- esc_url($url),
163
- $class_html,
164
- $label
165
- );
166
- }
167
-
168
- /**
169
- * Get views (sidebar statuses)
170
- *
171
- * @since 3.4
172
- * @return array
173
- */
174
- public function get_views()
175
- {
176
- global $locked_post_status, $avail_post_stati;
177
-
178
- if (!empty($locked_post_status)) {
179
- return [];
180
- }
181
-
182
- $status_links = [];
183
- $num_posts = wp_count_posts(CAS_App::TYPE_SIDEBAR); //do not include private
184
- $total_posts = array_sum((array) $num_posts);
185
- $class = '';
186
-
187
- // Subtract post types that are not included in the admin all list.
188
- foreach (get_post_stati([ 'show_in_admin_all_list' => false ]) as $state) {
189
- $total_posts -= $num_posts->$state;
190
- }
191
-
192
- if (empty($class) && (!isset($_REQUEST['post_status']) || isset($_REQUEST['all_posts']))) {
193
- $class = 'current';
194
- }
195
-
196
- $all_inner_html = sprintf(
197
- _nx(
198
- 'All <span class="count">(%s)</span>',
199
- 'All <span class="count">(%s)</span>',
200
- $total_posts,
201
- 'sidebars',
202
- 'content-aware-sidebars'
203
- ),
204
- number_format_i18n($total_posts)
205
- );
206
-
207
- $status_links['all'] = $this->get_view_link([], $all_inner_html, $class);
208
-
209
- //no way to change post status per post type, replace here instead
210
- $label_replacement = [
211
- CAS_App::STATUS_ACTIVE => _n_noop('Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', 'content-aware-sidebars'),
212
- CAS_App::STATUS_INACTIVE => _n_noop('Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', 'content-aware-sidebars')
213
- ];
214
-
215
- foreach (get_post_stati(['show_in_admin_status_list' => true], 'objects') as $status) {
216
- $class = '';
217
-
218
- $status_name = $status->name;
219
-
220
- if (! in_array($status_name, $avail_post_stati) || empty($num_posts->$status_name)) {
221
- continue;
222
- }
223
-
224
- if (isset($_REQUEST['post_status']) && $status_name == $_REQUEST['post_status']) {
225
- $class = 'current';
226
- }
227
-
228
- $status_args = [
229
- 'post_status' => $status_name
230
- ];
231
-
232
- $label_count = $status->label_count;
233
- if (isset($label_replacement[$status->name])) {
234
- $label_count = $label_replacement[$status->name];
235
- }
236
-
237
- $status_label = sprintf(
238
- translate_nooped_plural($label_count, $num_posts->$status_name),
239
- number_format_i18n($num_posts->$status_name)
240
- );
241
-
242
- $status_links[ $status_name ] = $this->get_view_link($status_args, $status_label, $class);
243
- }
244
-
245
- return $status_links;
246
- }
247
-
248
- /**
249
- * Get bulk actions
250
- *
251
- * @since 3.4
252
- * @return array
253
- */
254
- public function get_bulk_actions()
255
- {
256
- $actions = [];
257
- $post_type_obj = get_post_type_object(CAS_App::TYPE_SIDEBAR);
258
-
259
- if (current_user_can($post_type_obj->cap->edit_posts)) {
260
- if ($this->is_trash) {
261
- $actions['untrash'] = __('Restore');
262
- } else {
263
- $actions['activate'] = __('Activate');
264
- $actions['deactivate'] = __('Deactivate');
265
- }
266
- }
267
-
268
- if (current_user_can($post_type_obj->cap->delete_posts)) {
269
- if ($this->is_trash || ! EMPTY_TRASH_DAYS) {
270
- $actions['delete'] = __('Delete Permanently');
271
- } else {
272
- $actions['trash'] = __('Move to Trash');
273
- }
274
- }
275
-
276
- //todo: add filter
277
- return $actions;
278
- }
279
-
280
- /**
281
- * Render extra table navigation and actions
282
- *
283
- * @since 3.4
284
- * @param string $which
285
- * @return void
286
- */
287
- public function extra_tablenav($which)
288
- {
289
- echo '<div class="alignleft actions">';
290
- if ($this->is_trash && current_user_can(get_post_type_object(CAS_App::TYPE_SIDEBAR)->cap->edit_others_posts)) {
291
- submit_button(__('Empty Trash'), 'apply', 'delete_all', false);
292
- }
293
- echo '</div>';
294
- }
295
-
296
- /**
297
- * Get current action
298
- *
299
- * @since 3.4
300
- * @return string
301
- */
302
- public function current_action()
303
- {
304
- if (isset($_REQUEST['delete_all']) || isset($_REQUEST['delete_all2'])) {
305
- return 'delete_all';
306
- }
307
-
308
- return parent::current_action();
309
- }
310
-
311
- /**
312
- * Get columns
313
- *
314
- * @since 3.4
315
- * @return array
316
- */
317
- public function get_columns()
318
- {
319
- $posts_columns = [];
320
- $posts_columns['cb'] = '<input type="checkbox" />';
321
- $posts_columns['title'] = _x('Title', 'column name');
322
- $posts_columns['handler'] = _x('Action', 'option', 'content-aware-sidebars');
323
- $posts_columns['widgets'] = __('Widgets');
324
- $posts_columns['visibility'] = __('Visibility', 'content-aware-sidebars');
325
- $posts_columns['status'] = __('Status');
326
-
327
- return apply_filters('cas/admin/columns', $posts_columns);
328
- }
329
-
330
- /**
331
- * Get sortable columns
332
- *
333
- * @since 3.4
334
- * @return array
335
- */
336
- public function get_sortable_columns()
337
- {
338
- return [
339
- 'title' => ['title', true],
340
- 'status' => 'post_status',
341
- 'handler' => 'meta_handle'
342
- ];
343
- }
344
-
345
- /**
346
- * Get default column name
347
- *
348
- * @since 3.4
349
- * @return string
350
- */
351
- protected function get_default_primary_column_name()
352
- {
353
- return 'title';
354
- }
355
-
356
- /**
357
- * Get classes for rows
358
- * Older WP versions do not add striped
359
- *
360
- * @since 3.4
361
- * @return array
362
- */
363
- public function get_table_classes()
364
- {
365
- return [ 'widefat', 'fixed', 'striped', $this->_args['plural'] ];
366
- }
367
-
368
- /**
369
- * Render checkbox column
370
- *
371
- * @since 3.4
372
- * @param WP_Post $post
373
- * @return void
374
- */
375
- public function column_cb($post)
376
- {
377
- if (current_user_can('edit_post', $post->ID)): ?>
378
- <label class="screen-reader-text"
379
- for="cb-select-<?php echo $post->ID; ?>"><?php
380
- printf(__('Select %s'), _draft_or_post_title($post)); ?></label>
381
- <input id="cb-select-<?php echo $post->ID; ?>" type="checkbox"
382
- name="post[]" value="<?php echo $post->ID; ?>" />
383
- <div class="locked-indicator"></div>
384
- <?php endif;
385
- }
386
-
387
- /**
388
- * Render title column wrapper
389
- *
390
- * @since 3.4
391
- * @param WP_Post $post
392
- * @param array $classes
393
- * @param array $data
394
- * @param string $primary
395
- * @return void
396
- */
397
- protected function _column_title($post, $classes, $data, $primary)
398
- {
399
- echo '<td class="' . $classes . ' page-title" ', $data, '>';
400
- echo $this->column_title($post);
401
- echo '</td>';
402
- }
403
-
404
- /**
405
- * Render title column
406
- *
407
- * @since 3.4
408
- * @param WP_Post $post
409
- * @return void
410
- */
411
- public function column_title($post)
412
- {
413
- echo '<strong>';
414
-
415
- $can_edit_post = current_user_can('edit_post', $post->ID);
416
- $title = _draft_or_post_title($post);
417
-
418
- if ($can_edit_post && $post->post_status != 'trash') {
419
- printf(
420
- '<a class="" href="%s" aria-label="%s">%s</a>',
421
- get_edit_post_link($post->ID),
422
- /* translators: %s: post title */
423
- esc_attr(sprintf(__('&#8220;%s&#8221; (Edit)'), $title)),
424
- $title
425
- );
426
- } else {
427
- echo $title;
428
- }
429
-
430
- echo "</strong>\n";
431
-
432
- if ($can_edit_post && $post->post_status != 'trash') {
433
- $lock_holder = wp_check_post_lock($post->ID);
434
-
435
- if ($lock_holder) {
436
- $lock_holder = get_userdata($lock_holder);
437
- $locked_avatar = get_avatar($lock_holder->ID, 18);
438
- $locked_text = esc_html(sprintf(__('%s is currently editing'), $lock_holder->display_name));
439
- } else {
440
- $locked_avatar = $locked_text = '';
441
- }
442
-
443
- echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
444
- }
445
-
446
- echo $this->handle_row_actions($post, 'title', 'title');
447
- }
448
-
449
- /**
450
- * Render sidebar action column
451
- *
452
- * @since 3.4
453
- * @param WP_Post $post
454
- * @return void
455
- */
456
- public function column_handler($post)
457
- {
458
- $metadata = CAS_App::instance()->manager()->metadata();
459
- $action = $metadata->get('handle');
460
-
461
- if ($action) {
462
- switch ($action->get_data($post->ID)) {
463
- case CAS_App::ACTION_REPLACE:
464
- case CAS_App::ACTION_MERGE:
465
- case CAS_App::ACTION_REPLACE_FORCED:
466
- $return = $action->get_list_data($post->ID);
467
- $data = [];
468
- $hosts = $metadata->get('host')->get_data($post->ID, false, false);
469
- if ($hosts) {
470
- $list = $metadata->get('host')->get_input_list();
471
- foreach ($hosts as $host) {
472
- if (isset($list[$host])) {
473
- $data[] = $list[$host];
474
- }
475
- }
476
- }
477
-
478
- if (empty($data)) {
479
- $data[] = '<span style="color:red;">' . __('Target not found', 'content-aware-sidebars') . '</span>';
480
- }
481
- $return .= ':<br> ' . implode(', ', $data);
482
-
483
- if ($action->get_data($post->ID) == 1) {
484
- $pos = $metadata->get('merge_pos')->get_data($post->ID, true);
485
- $pos_icon = $pos ? 'up' : 'down';
486
- $pos_title = [
487
- __('Add sidebar at the top during merge', 'content-aware-sidebars'),
488
- __('Add sidebar at the bottom during merge', 'content-aware-sidebars')
489
- ];
490
- $return .= '<span title="'.$pos_title[$pos].'" class="dashicons dashicons-arrow-'.$pos_icon.'-alt"></span>';
491
- }
492
- echo $return;
493
- break;
494
- case CAS_App::ACTION_SHORTCODE:
495
- echo "<input type='text' value='[ca-sidebar id=\"$post->ID\"]' readonly />";
496
- break;
497
- default:
498
- do_action('cas/admin/columns/action', $post, $action);
499
- break;
500
- }
501
- }
502
- }
503
-
504
- /**
505
- * Render sidebar widgets column
506
- *
507
- * @since 3.4
508
- * @param WP_Post $post
509
- * @return void
510
- */
511
- public function column_widgets($post)
512
- {
513
- $sidebars_widgets = wp_get_sidebars_widgets();
514
- $count = isset($sidebars_widgets[CAS_App::SIDEBAR_PREFIX . $post->ID]) ? count($sidebars_widgets[CAS_App::SIDEBAR_PREFIX . $post->ID]) : 0;
515
- echo '<a href="'.admin_url('widgets.php#'.CAS_App::SIDEBAR_PREFIX.$post->ID).'" title="' . esc_attr__('Manage Widgets', 'content-aware-sidebars') . '">' .$count . '</a>';
516
- }
517
-
518
- /**
519
- * Render sidebar visibility column
520
- *
521
- * @since 3.4
522
- * @param WP_Post $post
523
- * @return void
524
- */
525
- public function column_visibility($post)
526
- {
527
- $metadata = CAS_App::instance()->manager()->metadata()->get('visibility');
528
- if ($metadata) {
529
- $data = $metadata->get_data($post->ID, true, false);
530
- if ($data) {
531
- if (!$this->visibility) {
532
- $visibility = $metadata->get_input_list();
533
- foreach ($visibility as $key => $options) {
534
- if (is_array($options)) {
535
- $this->visibility = $options['options'] + $this->visibility;
536
- } else {
537
- $this->visibility[$key] = $options;
538
- }
539
- }
540
- }
541
-
542
- $list = $this->visibility;
543
- foreach ($data as $k => $v) {
544
- if (!isset($list[$v])) {
545
- continue;
546
- }
547
- $data[$k] = $list[$v];
548
- }
549
- echo implode(', ', $data);
550
- return;
551
- }
552
- }
553
- _e('All Users', 'content-aware-sidebars');
554
- }
555
-
556
- /**
557
- * Render sidebar status column
558
- *
559
- * @since 3.4
560
- * @param WP_Post $sidebar
561
- * @return void
562
- */
563
- public function column_status($sidebar)
564
- {
565
- $icon = '';
566
- switch ($sidebar->post_status) {
567
- case CAS_App::STATUS_ACTIVE:
568
- $status = __('Active', 'content-aware-sidebars');
569
- $deactivate_date = get_post_meta($sidebar->ID, CAS_App::META_PREFIX.'deactivate_time', true);
570
- if ($deactivate_date) {
571
- $t_time = mysql2date(get_option('date_format'), $deactivate_date);
572
-
573
- $icon = sprintf(__('Until %s', 'content-aware-sidebars'), $t_time);
574
- }
575
-
576
- break;
577
- case CAS_App::STATUS_SCHEDULED:
578
- $status = __('Scheduled');
579
-
580
- $t_time = get_post_time(get_option('date_format'), false, $sidebar, true);
581
- $time_diff = time() - get_post_time('G', true, $sidebar);
582
-
583
- $icon = sprintf(__('Scheduled for %s', 'content-aware-sidebars'), $t_time);
584
-
585
- if ($time_diff > 0) {
586
- $icon .= ' ' . __('Missed schedule') . '!';
587
- }
588
-
589
- break;
590
- default:
591
- $status = __('Inactive', 'content-aware-sidebars');
592
- }
593
-
594
- echo '<div class="sidebar-status">';
595
- echo '<input type="checkbox" class="sidebar-status-input sidebar-status-'.$sidebar->post_status.'"
596
- id="cas-status-'.$sidebar->ID.'" data-nonce="'.wp_create_nonce(CAS_Admin::NONCE_PREFIX_1CLICK.$sidebar->ID).'"
597
- value="'.$sidebar->ID.'" '.checked($sidebar->post_status, CAS_App::STATUS_ACTIVE, false).'>';
598
- echo '<label title="'.$status.'" class="sidebar-status-label" for="cas-status-'.$sidebar->ID.'">';
599
- echo '</label>';
600
- echo '</div>';
601
-
602
- if ($icon) {
603
- echo '<span class="dashicons dashicons-clock" title="'.$icon.'">';
604
- echo '</span>';
605
- echo '<span class="screen-reader-text">'.$icon.'</span>';
606
- }
607
- }
608
-
609
- /**
610
- * Render arbitrary column
611
- *
612
- * @since 3.4
613
- * @param WP_post $post
614
- * @param string $column_name
615
- * @return void
616
- */
617
- public function column_default($post, $column_name)
618
- {
619
- do_action('cas/admin/columns/default', $post, $column_name);
620
- }
621
-
622
- /**
623
- * Render row
624
- *
625
- * @since 3.4
626
- * @param WP_Post $item
627
- * @return void
628
- */
629
- public function single_row($item)
630
- {
631
- $class = '';
632
- if ($item->post_status == CAS_App::STATUS_ACTIVE) {
633
- $class = ' class="active"';
634
- }
635
- echo '<tr'.$class.'>';
636
- $this->single_row_columns($item);
637
- echo '</tr>';
638
- }
639
-
640
- /**
641
- * Get row actions
642
- *
643
- * @since 3.4
644
- * @param WP_Post $post
645
- * @param string $column_name
646
- * @param string $primary
647
- * @return string
648
- */
649
- protected function handle_row_actions($post, $column_name, $primary)
650
- {
651
- if ($primary !== $column_name) {
652
- return '';
653
- }
654
-
655
- $post_type_object = get_post_type_object($post->post_type);
656
- $actions = [];
657
- $title = _draft_or_post_title();
658
- $cas_fs = cas_fs();
659
-
660
- if (current_user_can('edit_post', $post->ID) && $post->post_status != 'trash') {
661
- $actions['edit'] = sprintf(
662
- '<a href="%s" aria-label="%s">%s</a>',
663
- get_edit_post_link($post->ID),
664
- /* translators: %s: sidebar title */
665
- esc_attr(sprintf(__('Edit &#8220;%s&#8221;'), $title)),
666
- __('Edit')
667
- );
668
- $actions['duplicate'] = sprintf(
669
- '<a href="%s" aria-label="%s">%s</a>',
670
- esc_url($cas_fs->get_upgrade_url()),
671
- /* translators: %s: sidebar title */
672
- esc_attr(sprintf(__('Duplicate %s', 'content-aware-sidebars'), $title)),
673
- __('Duplicate', 'content-aware-sidebars')
674
- );
675
-
676
- $link = admin_url('post.php?post='.$post->ID);
677
- $actions['widget_revisions'] = '<a href="'.add_query_arg('action', 'cas-revisions', $link).'" title="' . esc_attr__('Widget Revisions', 'content-aware-sidebars') . '">' . __('Widget Revisions', 'content-aware-sidebars') . '</a>';
678
- }
679
-
680
- if (current_user_can('delete_post', $post->ID)) {
681
- if ($post->post_status == 'trash') {
682
- $actions['untrash'] = sprintf(
683
- '<a href="%s" aria-label="%s">%s</a>',
684
- wp_nonce_url(get_edit_post_link($post->ID, 'display').'&amp;action=untrash', 'untrash-post_' . $post->ID),
685
- /* translators: %s: post title */
686
- esc_attr(sprintf(__('Restore &#8220;%s&#8221; from the Trash'), $title)),
687
- __('Restore')
688
- );
689
- } elseif (EMPTY_TRASH_DAYS) {
690
- $actions['trash'] = sprintf(
691
- '<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
692
- get_delete_post_link($post->ID),
693
- /* translators: %s: post title */
694
- esc_attr(sprintf(__('Move &#8220;%s&#8221; to the Trash'), $title)),
695
- _x('Trash', 'verb')
696
- );
697
- }
698
- if ($post->post_status == 'trash' || ! EMPTY_TRASH_DAYS) {
699
- $actions['delete'] = sprintf(
700
- '<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
701
- get_delete_post_link($post->ID, '', true),
702
- /* translators: %s: post title */
703
- esc_attr(sprintf(__('Delete &#8220;%s&#8221; permanently'), $title)),
704
- __('Delete Permanently')
705
- );
706
- }
707
- }
708
-
709
- return $this->row_actions(
710
- apply_filters('cas/admin/row_actions', $actions, $post)
711
- );
712
- }
713
- }
1
+ <?php
2
+ /**
3
+ * @package Content Aware Sidebars
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ if (!class_exists('WP_List_Table')) {
12
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
13
+ }
14
+
15
+ class CAS_Sidebar_List_Table extends WP_List_Table
16
+ {
17
+ /**
18
+ * Trash view
19
+ * @var boolean
20
+ */
21
+ private $is_trash;
22
+
23
+ private $visibility = [];
24
+
25
+ public function __construct($args = [])
26
+ {
27
+ parent::__construct([
28
+ 'singular' => 'sidebar',
29
+ 'plural' => 'sidebars',
30
+ 'ajax' => false,
31
+ 'screen' => isset($args['screen']) ? $args['screen'] : null
32
+ ]);
33
+ }
34
+
35
+ /**
36
+ * Load filtered sidebars for current query
37
+ *
38
+ * @since 3.4
39
+ * @return void
40
+ */
41
+ public function prepare_items()
42
+ {
43
+ global $avail_post_stati, $wp_query;
44
+
45
+ $this->_column_headers = $this->get_column_info();
46
+
47
+ $avail_post_stati = get_available_post_statuses(CAS_App::TYPE_SIDEBAR);
48
+
49
+ $per_page = $this->get_items_per_page('cas_sidebars_per_page', 20);
50
+ $current_page = $this->get_pagenum();
51
+
52
+ $args = [
53
+ 'post_type' => CAS_App::TYPE_SIDEBAR,
54
+ 'post_status' => [
55
+ CAS_App::STATUS_ACTIVE,
56
+ CAS_App::STATUS_INACTIVE,
57
+ CAS_App::STATUS_SCHEDULED
58
+ ],
59
+ 'posts_per_page' => $per_page,
60
+ 'paged' => $current_page,
61
+ 'orderby' => 'title',
62
+ 'order' => 'asc',
63
+ 'update_post_term_cache' => false
64
+ ];
65
+
66
+ if (isset($_REQUEST['s']) && strlen($_REQUEST['s'])) {
67
+ $args['s'] = $_REQUEST['s'];
68
+ }
69
+
70
+ //Make sure post_status!=all if present to avoid auto-drafts
71
+ if (isset($_REQUEST['post_status']) && $_REQUEST['post_status'] != 'all') {
72
+ $args['post_status'] = $_REQUEST['post_status'];
73
+ }
74
+
75
+ if (isset($_REQUEST['orderby'])) {
76
+ $meta = str_replace('meta_', '', $_REQUEST['orderby']);
77
+ if ($meta != $_REQUEST['orderby']) {
78
+ $args['orderby'] = 'meta_value';
79
+ $args['meta_key'] = CAS_App::META_PREFIX . $meta;
80
+ } else {
81
+ $args['orderby'] = $_REQUEST['orderby'];
82
+ }
83
+ }
84
+
85
+ if (isset($_REQUEST['order'])) {
86
+ $args['order'] = $_REQUEST['order'] == 'asc' ? 'asc' : 'desc';
87
+ }
88
+
89
+ $wp_query = new WP_Query($args);
90
+
91
+ if ($wp_query->found_posts || $current_page === 1) {
92
+ $total_items = $wp_query->found_posts;
93
+ } else {
94
+ $post_counts = (array) wp_count_posts(CAS_App::TYPE_SIDEBAR);
95
+
96
+ if (isset($_REQUEST['post_status']) && in_array($_REQUEST['post_status'], $avail_post_stati)) {
97
+ $total_items = $post_counts[$_REQUEST['post_status']];
98
+ } else {
99
+ $total_items = array_sum($post_counts);
100
+
101
+ // Subtract post types that are not included in the admin all list.
102
+ foreach (get_post_stati(['show_in_admin_all_list' => false]) as $state) {
103
+ $total_items -= $post_counts[$state];
104
+ }
105
+ }
106
+ }
107
+
108
+ $this->items = $wp_query->posts;
109
+ $this->is_trash = isset($_REQUEST['post_status']) && $_REQUEST['post_status'] == 'trash';
110
+ $this->set_pagination_args([
111
+ 'total_items' => $total_items,
112
+ 'total_pages' => ceil($total_items / $per_page),
113
+ 'per_page' => $per_page
114
+ ]);
115
+
116
+ //Make sure filter is run
117
+ CAS_App::instance()->manager()->populate_metadata();
118
+ }
119
+
120
+ /**
121
+ * Render on no items
122
+ *
123
+ * @since 3.4
124
+ * @return void
125
+ */
126
+ public function no_items()
127
+ {
128
+ if ($this->is_trash) {
129
+ echo get_post_type_object(CAS_App::TYPE_SIDEBAR)->labels->not_found_in_trash;
130
+ } else {
131
+ //todo show more text to get started
132
+ echo get_post_type_object(CAS_App::TYPE_SIDEBAR)->labels->not_found;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Get link to view
138
+ *
139
+ * @since 3.4
140
+ * @param array $args
141
+ * @param string $label
142
+ * @param string $class
143
+ * @return string
144
+ */
145
+ public function get_view_link($args, $label, $class = '')
146
+ {
147
+ $screen = get_current_screen();
148
+ $args['page'] = $screen->parent_base;
149
+ $url = add_query_arg($args, 'admin.php');
150
+
151
+ $class_html = '';
152
+ if (!empty($class)) {
153
+ $class_html = sprintf(
154
+ ' class="%s"',
155
+ esc_attr($class)
156
+ );
157
+ }
158
+
159
+ return sprintf(
160
+ '<a href="%s"%s>%s</a>',
161
+ esc_url($url),
162
+ $class_html,
163
+ $label
164
+ );
165
+ }
166
+
167
+ /**
168
+ * Get views (sidebar statuses)
169
+ *
170
+ * @since 3.4
171
+ * @return array
172
+ */
173
+ public function get_views()
174
+ {
175
+ global $locked_post_status, $avail_post_stati;
176
+
177
+ if (!empty($locked_post_status)) {
178
+ return [];
179
+ }
180
+
181
+ $status_links = [];
182
+ $num_posts = wp_count_posts(CAS_App::TYPE_SIDEBAR); //do not include private
183
+ $total_posts = array_sum((array) $num_posts);
184
+ $class = '';
185
+
186
+ // Subtract post types that are not included in the admin all list.
187
+ foreach (get_post_stati(['show_in_admin_all_list' => false]) as $state) {
188
+ $total_posts -= $num_posts->$state;
189
+ }
190
+
191
+ if (empty($class) && (!isset($_REQUEST['post_status']) || isset($_REQUEST['all_posts']))) {
192
+ $class = 'current';
193
+ }
194
+
195
+ $all_inner_html = sprintf(
196
+ _nx(
197
+ 'All <span class="count">(%s)</span>',
198
+ 'All <span class="count">(%s)</span>',
199
+ $total_posts,
200
+ 'sidebars',
201
+ 'content-aware-sidebars'
202
+ ),
203
+ number_format_i18n($total_posts)
204
+ );
205
+
206
+ $status_links['all'] = $this->get_view_link([], $all_inner_html, $class);
207
+
208
+ //no way to change post status per post type, replace here instead
209
+ $label_replacement = [
210
+ CAS_App::STATUS_ACTIVE => _n_noop('Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', 'content-aware-sidebars'),
211
+ CAS_App::STATUS_INACTIVE => _n_noop('Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', 'content-aware-sidebars')
212
+ ];
213
+
214
+ foreach (get_post_stati(['show_in_admin_status_list' => true], 'objects') as $status) {
215
+ $class = '';
216
+
217
+ $status_name = $status->name;
218
+
219
+ if (!in_array($status_name, $avail_post_stati) || empty($num_posts->$status_name)) {
220
+ continue;
221
+ }
222
+
223
+ if (isset($_REQUEST['post_status']) && $status_name == $_REQUEST['post_status']) {
224
+ $class = 'current';
225
+ }
226
+
227
+ $status_args = [
228
+ 'post_status' => $status_name
229
+ ];
230
+
231
+ $label_count = $status->label_count;
232
+ if (isset($label_replacement[$status->name])) {
233
+ $label_count = $label_replacement[$status->name];
234
+ }
235
+
236
+ $status_label = sprintf(
237
+ translate_nooped_plural($label_count, $num_posts->$status_name),
238
+ number_format_i18n($num_posts->$status_name)
239
+ );
240
+
241
+ $status_links[$status_name] = $this->get_view_link($status_args, $status_label, $class);
242
+ }
243
+
244
+ return $status_links;
245
+ }
246
+
247
+ /**
248
+ * Get bulk actions
249
+ *
250
+ * @since 3.4
251
+ * @return array
252
+ */
253
+ public function get_bulk_actions()
254
+ {
255
+ $actions = [];
256
+ $post_type_obj = get_post_type_object(CAS_App::TYPE_SIDEBAR);
257
+
258
+ if (current_user_can($post_type_obj->cap->edit_posts)) {
259
+ if ($this->is_trash) {
260
+ $actions['untrash'] = __('Restore');
261
+ } else {
262
+ $actions['activate'] = __('Activate');
263
+ $actions['deactivate'] = __('Deactivate');
264
+ }
265
+ }
266
+
267
+ if (current_user_can($post_type_obj->cap->delete_posts)) {
268
+ if ($this->is_trash || !EMPTY_TRASH_DAYS) {
269
+ $actions['delete'] = __('Delete Permanently');
270
+ } else {
271
+ $actions['trash'] = __('Move to Trash');
272
+ }
273
+ }
274
+
275
+ //todo: add filter
276
+ return $actions;
277
+ }
278
+
279
+ /**
280
+ * Render extra table navigation and actions
281
+ *
282
+ * @since 3.4
283
+ * @param string $which
284
+ * @return void
285
+ */
286
+ public function extra_tablenav($which)
287
+ {
288
+ echo '<div class="alignleft actions">';
289
+ if ($this->is_trash && current_user_can(get_post_type_object(CAS_App::TYPE_SIDEBAR)->cap->edit_others_posts)) {
290
+ submit_button(__('Empty Trash'), 'apply', 'delete_all', false);
291
+ }
292
+ echo '</div>';
293
+ }
294
+
295
+ /**
296
+ * Get current action
297
+ *
298
+ * @since 3.4
299
+ * @return string
300
+ */
301
+ public function current_action()
302
+ {
303
+ if (isset($_REQUEST['delete_all']) || isset($_REQUEST['delete_all2'])) {
304
+ return 'delete_all';
305
+ }
306
+
307
+ return parent::current_action();
308
+ }
309
+
310
+ /**
311
+ * Get columns
312
+ *
313
+ * @since 3.4
314
+ * @return array
315
+ */
316
+ public function get_columns()
317
+ {
318
+ $posts_columns = [];
319
+ $posts_columns['cb'] = '<input type="checkbox" />';
320
+ $posts_columns['title'] = _x('Title', 'column name');
321
+ $posts_columns['handler'] = _x('Action', 'option', 'content-aware-sidebars');
322
+ $posts_columns['widgets'] = __('Widgets');
323
+ $posts_columns['visibility'] = __('Visibility', 'content-aware-sidebars');
324
+ $posts_columns['status'] = __('Status');
325
+
326
+ return apply_filters('cas/admin/columns', $posts_columns);
327
+ }
328
+
329
+ /**
330
+ * Get sortable columns
331
+ *
332
+ * @since 3.4
333
+ * @return array
334
+ */
335
+ public function get_sortable_columns()
336
+ {
337
+ return [
338
+ 'title' => ['title', true],
339
+ 'status' => 'post_status',
340
+ 'handler' => 'meta_handle'
341
+ ];
342
+ }
343
+
344
+ /**
345
+ * Get default column name
346
+ *
347
+ * @since 3.4
348
+ * @return string
349
+ */
350
+ protected function get_default_primary_column_name()
351
+ {
352
+ return 'title';
353
+ }
354
+
355
+ /**
356
+ * Get classes for rows
357
+ * Older WP versions do not add striped
358
+ *
359
+ * @since 3.4
360
+ * @return array
361
+ */
362
+ public function get_table_classes()
363
+ {
364
+ return ['widefat', 'fixed', 'striped', $this->_args['plural']];
365
+ }
366
+
367
+ /**
368
+ * Render checkbox column
369
+ *
370
+ * @since 3.4
371
+ * @param WP_Post $post
372
+ * @return void
373
+ */
374
+ public function column_cb($post)
375
+ {
376
+ if (current_user_can('edit_post', $post->ID)): ?>
377
+ <label class="screen-reader-text"
378
+ for="cb-select-<?php echo $post->ID; ?>"><?php
379
+ printf(__('Select %s'), _draft_or_post_title($post)); ?></label>
380
+ <input id="cb-select-<?php echo $post->ID; ?>" type="checkbox"
381
+ name="post[]" value="<?php echo $post->ID; ?>" />
382
+ <div class="locked-indicator"></div>
383
+ <?php endif;
384
+ }
385
+
386
+ /**
387
+ * Render title column wrapper
388
+ *
389
+ * @since 3.4
390
+ * @param WP_Post $post
391
+ * @param array $classes
392
+ * @param array $data
393
+ * @param string $primary
394
+ * @return void
395
+ */
396
+ protected function _column_title($post, $classes, $data, $primary)
397
+ {
398
+ echo '<td class="' . $classes . ' page-title" ', $data, '>';
399
+ echo $this->column_title($post);
400
+ echo '</td>';
401
+ }
402
+
403
+ /**
404
+ * Render title column
405
+ *
406
+ * @since 3.4
407
+ * @param WP_Post $post
408
+ * @return void
409
+ */
410
+ public function column_title($post)
411
+ {
412
+ echo '<strong>';
413
+
414
+ $can_edit_post = current_user_can('edit_post', $post->ID);
415
+ $title = _draft_or_post_title($post);
416
+
417
+ if ($can_edit_post && $post->post_status != 'trash') {
418
+ printf(
419
+ '<a class="" href="%s" aria-label="%s">%s</a>',
420
+ get_edit_post_link($post->ID),
421
+ /* translators: %s: post title */
422
+ esc_attr(sprintf(__('&#8220;%s&#8221; (Edit)'), $title)),
423
+ $title
424
+ );
425
+ } else {
426
+ echo $title;
427
+ }
428
+
429
+ echo "</strong>\n";
430
+
431
+ if ($can_edit_post && $post->post_status != 'trash') {
432
+ $lock_holder = wp_check_post_lock($post->ID);
433
+
434
+ if ($lock_holder) {
435
+ $lock_holder = get_userdata($lock_holder);
436
+ $locked_avatar = get_avatar($lock_holder->ID, 18);
437
+ $locked_text = esc_html(sprintf(__('%s is currently editing'), $lock_holder->display_name));
438
+ } else {
439
+ $locked_avatar = $locked_text = '';
440
+ }
441
+
442
+ echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
443
+ }
444
+
445
+ echo $this->handle_row_actions($post, 'title', 'title');
446
+ }
447
+
448
+ /**
449
+ * Render sidebar action column
450
+ *
451
+ * @since 3.4
452
+ * @param WP_Post $post
453
+ * @return void
454
+ */
455
+ public function column_handler($post)
456
+ {
457
+ $metadata = CAS_App::instance()->manager()->metadata();
458
+ $action = $metadata->get('handle');
459
+
460
+ if ($action) {
461
+ switch ($action->get_data($post->ID)) {
462
+ case CAS_App::ACTION_REPLACE:
463
+ case CAS_App::ACTION_MERGE:
464
+ case CAS_App::ACTION_REPLACE_FORCED:
465
+ $return = $action->get_list_data($post->ID);
466
+ $data = [];
467
+ $hosts = $metadata->get('host')->get_data($post->ID, false, false);
468
+ if ($hosts) {
469
+ $list = $metadata->get('host')->get_input_list();
470
+ foreach ($hosts as $host) {
471
+ if (isset($list[$host])) {
472
+ $data[] = $list[$host];
473
+ }
474
+ }
475
+ }
476
+
477
+ if (empty($data)) {
478
+ $data[] = '<span style="color:red;">' . __('Target not found', 'content-aware-sidebars') . '</span>';
479
+ }
480
+ $return .= ':<br> ' . implode(', ', $data);
481
+
482
+ if ($action->get_data($post->ID) == 1) {
483
+ $pos = $metadata->get('merge_pos')->get_data($post->ID, true);
484
+ $pos_icon = $pos ? 'up' : 'down';
485
+ $pos_title = [
486
+ __('Add sidebar at the top during merge', 'content-aware-sidebars'),
487
+ __('Add sidebar at the bottom during merge', 'content-aware-sidebars')
488
+ ];
489
+ $return .= '<span title="' . $pos_title[$pos] . '" class="dashicons dashicons-arrow-' . $pos_icon . '-alt"></span>';
490
+ }
491
+ echo $return;
492
+ break;
493
+ case CAS_App::ACTION_SHORTCODE:
494
+ echo $action->get_list_data($post->ID) . ':<br>';
495
+ echo "<input type='text' value='[ca-sidebar id=\"$post->ID\"]' readonly />";
496
+ break;
497
+ default:
498
+ do_action('cas/admin/columns/action', $post, $action);
499
+ break;
500
+ }
501
+ }
502
+ }
503
+
504
+ /**
505
+ * Render sidebar widgets column
506
+ *
507
+ * @since 3.4
508
+ * @param WP_Post $post
509
+ * @return void
510
+ */
511
+ public function column_widgets($post)
512
+ {
513
+ $sidebars_widgets = wp_get_sidebars_widgets();
514
+ $count = isset($sidebars_widgets[CAS_App::SIDEBAR_PREFIX . $post->ID]) ? count($sidebars_widgets[CAS_App::SIDEBAR_PREFIX . $post->ID]) : 0;
515
+ echo '<a href="' . admin_url('widgets.php#' . CAS_App::SIDEBAR_PREFIX . $post->ID) . '" title="' . esc_attr__('Manage Widgets', 'content-aware-sidebars') . '">' . $count . '</a>';
516
+ }
517
+
518
+ /**
519
+ * Render sidebar visibility column
520
+ *
521
+ * @since 3.4
522
+ * @param WP_Post $post
523
+ * @return void
524
+ */
525
+ public function column_visibility($post)
526
+ {
527
+ $metadata = CAS_App::instance()->manager()->metadata()->get('visibility');
528
+ if ($metadata) {
529
+ $data = $metadata->get_data($post->ID, true, false);
530
+ if ($data) {
531
+ if (!$this->visibility) {
532
+ $visibility = $metadata->get_input_list();
533
+ foreach ($visibility as $key => $options) {
534
+ if (is_array($options)) {
535
+ $this->visibility = $options['options'] + $this->visibility;
536
+ } else {
537
+ $this->visibility[$key] = $options;
538
+ }
539
+ }
540
+ }
541
+
542
+ $list = $this->visibility;
543
+ foreach ($data as $k => $v) {
544
+ if (!isset($list[$v])) {
545
+ continue;
546
+ }
547
+ $data[$k] = $list[$v];
548
+ }
549
+ echo implode(', ', $data);
550
+ return;
551
+ }
552
+ }
553
+ _e('All Users', 'content-aware-sidebars');
554
+ }
555
+
556
+ /**
557
+ * Render sidebar status column
558
+ *
559
+ * @since 3.4
560
+ * @param WP_Post $sidebar
561
+ * @return void
562
+ */
563
+ public function column_status($sidebar)
564
+ {
565
+ $icon = '';
566
+ switch ($sidebar->post_status) {
567
+ case CAS_App::STATUS_ACTIVE:
568
+ $status = __('Active', 'content-aware-sidebars');
569
+ $deactivate_date = get_post_meta($sidebar->ID, CAS_App::META_PREFIX . 'deactivate_time', true);
570
+ if ($deactivate_date) {
571
+ $t_time = mysql2date(get_option('date_format'), $deactivate_date);
572
+
573
+ $icon = sprintf(__('Until %s', 'content-aware-sidebars'), $t_time);
574
+ }
575
+
576
+ break;
577
+ case CAS_App::STATUS_SCHEDULED:
578
+ $status = __('Scheduled');
579
+
580
+ $t_time = get_post_time(get_option('date_format'), false, $sidebar, true);
581
+ $time_diff = time() - get_post_time('G', true, $sidebar);
582
+
583
+ $icon = sprintf(__('Scheduled for %s', 'content-aware-sidebars'), $t_time);
584
+
585
+ if ($time_diff > 0) {
586
+ $icon .= ' ' . __('Missed schedule') . '!';
587
+ }
588
+
589
+ break;
590
+ default:
591
+ $status = __('Inactive', 'content-aware-sidebars');
592
+ }
593
+
594
+ echo '<div class="sidebar-status">';
595
+ echo '<input type="checkbox" class="sidebar-status-input sidebar-status-' . $sidebar->post_status . '"
596
+ id="cas-status-' . $sidebar->ID . '" data-nonce="' . wp_create_nonce(CAS_Admin::NONCE_PREFIX_1CLICK . $sidebar->ID) . '"
597
+ value="' . $sidebar->ID . '" ' . checked($sidebar->post_status, CAS_App::STATUS_ACTIVE, false) . '>';
598
+ echo '<label title="' . $status . '" class="sidebar-status-label" for="cas-status-' . $sidebar->ID . '">';
599
+ echo '</label>';
600
+ echo '</div>';
601
+
602
+ if ($icon) {
603
+ echo '<span class="dashicons dashicons-clock" title="' . $icon . '">';
604
+ echo '</span>';
605
+ echo '<span class="screen-reader-text">' . $icon . '</span>';
606
+ }
607
+ }
608
+
609
+ /**
610
+ * Render arbitrary column
611
+ *
612
+ * @since 3.4
613
+ * @param WP_post $post
614
+ * @param string $column_name
615
+ * @return void
616
+ */
617
+ public function column_default($post, $column_name)
618
+ {
619
+ do_action('cas/admin/columns/default', $post, $column_name);
620
+ }
621
+
622
+ /**
623
+ * Render row
624
+ *
625
+ * @since 3.4
626
+ * @param WP_Post $item
627
+ * @return void
628
+ */
629
+ public function single_row($item)
630
+ {
631
+ $class = '';
632
+ if ($item->post_status == CAS_App::STATUS_ACTIVE) {
633
+ $class = ' class="active"';
634
+ }
635
+ echo '<tr' . $class . '>';
636
+ $this->single_row_columns($item);
637
+ echo '</tr>';
638
+ }
639
+
640
+ /**
641
+ * Get row actions
642
+ *
643
+ * @since 3.4
644
+ * @param WP_Post $post
645
+ * @param string $column_name
646
+ * @param string $primary
647
+ * @return string
648
+ */
649
+ protected function handle_row_actions($post, $column_name, $primary)
650
+ {
651
+ if ($primary !== $column_name) {
652
+ return '';
653
+ }
654
+
655
+ $post_type_object = get_post_type_object($post->post_type);
656
+ $actions = [];
657
+ $title = _draft_or_post_title();
658
+ $cas_fs = cas_fs();
659
+
660
+ if (current_user_can('edit_post', $post->ID) && $post->post_status != 'trash') {
661
+ $actions['edit'] = sprintf(
662
+ '<a href="%s" aria-label="%s">%s</a>',
663
+ get_edit_post_link($post->ID),
664
+ /* translators: %s: sidebar title */
665
+ esc_attr(sprintf(__('Edit &#8220;%s&#8221;'), $title)),
666
+ __('Edit')
667
+ );
668
+ $actions['duplicate'] = sprintf(
669
+ '<a href="%s" aria-label="%s">%s</a>',
670
+ esc_url($cas_fs->get_upgrade_url()),
671
+ /* translators: %s: sidebar title */
672
+ esc_attr(sprintf(__('Duplicate %s', 'content-aware-sidebars'), $title)),
673
+ __('Duplicate', 'content-aware-sidebars')
674
+ );
675
+
676
+ $link = admin_url('post.php?post=' . $post->ID);
677
+ $actions['widget_revisions'] = '<a href="' . add_query_arg('action', 'cas-revisions', $link) . '" title="' . esc_attr__('Widget Revisions', 'content-aware-sidebars') . '">' . __('Widget Revisions', 'content-aware-sidebars') . '</a>';
678
+ }
679
+
680
+ if (current_user_can('delete_post', $post->ID)) {
681
+ if ($post->post_status == 'trash') {
682
+ $actions['untrash'] = sprintf(
683
+ '<a href="%s" aria-label="%s">%s</a>',
684
+ wp_nonce_url(get_edit_post_link($post->ID, 'display') . '&amp;action=untrash', 'untrash-post_' . $post->ID),
685
+ /* translators: %s: post title */
686
+ esc_attr(sprintf(__('Restore &#8220;%s&#8221; from the Trash'), $title)),
687
+ __('Restore')
688
+ );
689
+ } elseif (EMPTY_TRASH_DAYS) {
690
+ $actions['trash'] = sprintf(
691
+ '<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
692
+ get_delete_post_link($post->ID),
693
+ /* translators: %s: post title */
694
+ esc_attr(sprintf(__('Move &#8220;%s&#8221; to the Trash'), $title)),
695
+ _x('Trash', 'verb')
696
+ );
697
+ }
698
+ if ($post->post_status == 'trash' || !EMPTY_TRASH_DAYS) {
699
+ $actions['delete'] = sprintf(
700
+ '<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
701
+ get_delete_post_link($post->ID, '', true),
702
+ /* translators: %s: post title */
703
+ esc_attr(sprintf(__('Delete &#8220;%s&#8221; permanently'), $title)),
704
+ __('Delete Permanently')
705
+ );
706
+ }
707
+ }
708
+
709
+ return $this->row_actions(
710
+ apply_filters('cas/admin/row_actions', $actions, $post)
711
+ );
712
+ }
713
+ }
admin/sidebar-overview.php CHANGED
@@ -1,334 +1,333 @@
1
- <?php
2
- /**
3
- * @package Content Aware Sidebars
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- final class CAS_Sidebar_Overview extends CAS_Admin
12
- {
13
-
14
- /**
15
- * Sidebar table
16
- * @var CAS_Sidebar_List_Table
17
- */
18
- public $table;
19
-
20
- /**
21
- * Add filters and actions for admin dashboard
22
- * e.g. AJAX calls
23
- *
24
- * @since 3.5
25
- * @return void
26
- */
27
- public function admin_hooks()
28
- {
29
- $this->add_filter('set-screen-option', 'set_screen_option', 10, 3);
30
- }
31
-
32
- /**
33
- * Setup admin menus and get current screen
34
- *
35
- * @since 3.4
36
- * @return string
37
- */
38
- public function get_screen()
39
- {
40
- $post_type_object = $this->get_sidebar_type();
41
- $notification_label = $this->notification_count ? sprintf(' <span class="awaiting-mod">%d</span>', $this->notification_count) : '';
42
-
43
- add_menu_page(
44
- $post_type_object->labels->name,
45
- __('Content Aware', 'content-aware-sidebars') . $notification_label,
46
- $post_type_object->cap->edit_posts,
47
- CAS_App::BASE_SCREEN,
48
- [$this,'render_screen'],
49
- $post_type_object->menu_icon,
50
- 60 //after Appearance
51
- );
52
-
53
- return add_submenu_page(
54
- CAS_App::BASE_SCREEN,
55
- $post_type_object->labels->name,
56
- $post_type_object->labels->all_items,
57
- $post_type_object->cap->edit_posts,
58
- CAS_App::BASE_SCREEN,
59
- [$this,'render_screen']
60
- );
61
- }
62
-
63
- /**
64
- * @since 3.5
65
- *
66
- * @return bool
67
- */
68
- public function authorize_user()
69
- {
70
- return current_user_can($this->get_sidebar_type()->cap->edit_posts);
71
- }
72
-
73
- /**
74
- * @since 3.4
75
- *
76
- * @return void
77
- */
78
- public function prepare_screen()
79
- {
80
- add_screen_option('per_page', [
81
- 'default' => 20,
82
- 'option' => 'cas_sidebars_per_page'
83
- ]);
84
-
85
- $this->table = new CAS_Sidebar_List_Table();
86
- $this->process_actions();//todo:add func to table to actions
87
- $this->table->prepare_items();
88
- }
89
-
90
- /**
91
- * Render screen
92
- *
93
- * @since 3.4
94
- * @return void
95
- */
96
- public function render_screen()
97
- {
98
- $post_type_object = $this->get_sidebar_type();
99
-
100
- echo '<div class="wrap">';
101
- echo '<h1>';
102
- echo esc_html($post_type_object->labels->name);
103
-
104
- if (current_user_can($post_type_object->cap->create_posts)) {
105
- echo ' <a href="' . esc_url(admin_url('admin.php?page=wpcas-edit')) . '" class="add-new-h2 page-title-action">' . esc_html($post_type_object->labels->add_new) . '</a>';
106
- }
107
- if (current_user_can('edit_theme_options')) {
108
- echo ' <a href="' . esc_url(admin_url('widgets.php')) . '" class="page-title-action add-new-h2">' . __('Manage Widgets', 'content-aware-sidebars') . '</a>';
109
- }
110
- if (isset($_REQUEST['s']) && strlen($_REQUEST['s'])) {
111
- /* translators: %s: search keywords */
112
- printf(' <span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', get_search_query());
113
- }
114
-
115
- echo '</h1>';
116
-
117
- $this->bulk_messages();
118
-
119
- $_SERVER['REQUEST_URI'] = remove_query_arg([ 'locked', 'skipped', 'deleted', 'trashed', 'untrashed' ], $_SERVER['REQUEST_URI']);
120
-
121
- $this->table->views();
122
-
123
- echo '<form id="posts-filter" method="get">';
124
-
125
- $this->table->search_box($post_type_object->labels->search_items, 'post');
126
-
127
- echo '<input type="hidden" name="page" value="wpcas" />';
128
- echo '<input type="hidden" name="post_status" class="post_status_page" value="'.(!empty($_REQUEST['post_status']) ? esc_attr($_REQUEST['post_status']) : 'all').'" />';
129
-
130
- $this->table->display();
131
-
132
- echo '</form></div>';
133
- }
134
-
135
- /**
136
- * Process actions
137
- *
138
- * @since 3.4
139
- * @return void
140
- */
141
- public function process_actions()
142
- {
143
- $doaction = $this->table->current_action();
144
-
145
- if ($doaction) {
146
- check_admin_referer('bulk-sidebars');
147
-
148
- $pagenum = $this->table->get_pagenum();
149
-
150
- $sendback = remove_query_arg(['activated','deactivated','trashed', 'untrashed', 'deleted', 'locked', 'ids'], wp_get_referer());
151
- $sendback = add_query_arg('paged', $pagenum, $sendback);
152
-
153
- if ('delete_all' == $doaction) {
154
- global $wpdb;
155
- $post_ids = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_type=%s AND post_status = %s", CAS_App::TYPE_SIDEBAR, 'trash'));
156
-
157
- $doaction = 'delete';
158
- } elseif (isset($_REQUEST['ids'])) {
159
- $post_ids = explode(',', $_REQUEST['ids']);
160
- } elseif (!empty($_REQUEST['post'])) {
161
- $post_ids = array_map('intval', $_REQUEST['post']);
162
- }
163
-
164
- if (!isset($post_ids)) {
165
- wp_redirect($sendback);
166
- exit;
167
- }
168
-
169
- $post_ids = (array)$post_ids;
170
- $handled = 0;
171
-
172
- switch ($doaction) {
173
- case 'activate':
174
- case 'deactivate':
175
- $locked = 0;
176
-
177
- foreach ($post_ids as $post_id) {
178
- if (!current_user_can('edit_post', $post_id)) {
179
- wp_die(__('You are not allowed to update this item.'));
180
- }
181
-
182
- if (wp_check_post_lock($post_id)) {
183
- $locked++;
184
- continue;
185
- }
186
-
187
- if ($doaction == 'activate') {
188
- $data = [
189
- 'ID' => $post_id,
190
- 'post_status' => CAS_App::STATUS_ACTIVE,
191
- 'post_date' => current_time('mysql'),
192
- 'post_date_gmt' => current_time('mysql', true)
193
- ];
194
- } else {
195
- $data = [
196
- 'ID' => $post_id,
197
- 'post_status' => CAS_App::STATUS_INACTIVE
198
- ];
199
- }
200
-
201
- if (!wp_update_post($data)) {
202
- wp_die(__('Error in updating status.'));
203
- }
204
-
205
- $handled++;
206
- }
207
- $sendback = add_query_arg([$doaction.'d' => $handled, 'ids' => join(',', $post_ids), 'locked' => $locked ], $sendback);
208
- break;
209
- case 'trash':
210
- $locked = 0;
211
-
212
- foreach ($post_ids as $post_id) {
213
- if (!current_user_can('delete_post', $post_id)) {
214
- wp_die(__('You are not allowed to move this item to the Trash.'));
215
- }
216
-
217
- if (wp_check_post_lock($post_id)) {
218
- $locked++;
219
- continue;
220
- }
221
-
222
- if (!wp_trash_post($post_id)) {
223
- wp_die(__('Error in moving to Trash.'));
224
- }
225
-
226
- $handled++;
227
- }
228
-
229
- $sendback = add_query_arg(['trashed' => $handled, 'ids' => join(',', $post_ids), 'locked' => $locked ], $sendback);
230
- break;
231
- case 'untrash':
232
- foreach ($post_ids as $post_id) {
233
- if (!current_user_can('delete_post', $post_id)) {
234
- wp_die(__('You are not allowed to restore this item from the Trash.'));
235
- }
236
-
237
- if (!wp_untrash_post($post_id)) {
238
- wp_die(__('Error in restoring from Trash.'));
239
- }
240
-
241
- $handled++;
242
- }
243
- $sendback = add_query_arg('untrashed', $handled, $sendback);
244
- break;
245
- case 'delete':
246
- foreach ($post_ids as $post_id) {
247
- if (!current_user_can('delete_post', $post_id)) {
248
- wp_die(__('You are not allowed to delete this item.'));
249
- }
250
-
251
- if (!wp_delete_post($post_id)) {
252
- wp_die(__('Error in deleting.'));
253
- }
254
- $handled++;
255
- }
256
- $sendback = add_query_arg('deleted', $handled, $sendback);
257
- break;
258
- default:
259
- break;
260
- }
261
-
262
- $sendback = remove_query_arg(['action', 'action2', 'post_status', 'post', 'bulk_edit'], $sendback);
263
-
264
- wp_safe_redirect($sendback);
265
- exit;
266
- }
267
- if (! empty($_REQUEST['_wp_http_referer'])) {
268
- wp_safe_redirect(remove_query_arg(['_wp_http_referer', '_wpnonce'], wp_unslash($_SERVER['REQUEST_URI'])));
269
- exit;
270
- }
271
- }
272
-
273
- /**
274
- * Set screen options on save
275
- *
276
- * @since 3.4
277
- * @param string $status
278
- * @param string $option
279
- * @param string $value
280
- */
281
- public function set_screen_option($status, $option, $value)
282
- {
283
- if ($option == 'cas_sidebars_per_page') {
284
- return $value;
285
- }
286
- return $status;
287
- }
288
-
289
- public function bulk_messages()
290
- {
291
- $bulk_messages = [
292
- 'updated' => _n_noop('%s sidebar updated.', '%s sidebars updated.', 'content-aware-sidebars'),
293
- 'locked' => _n_noop('%s sidebar not updated, somebody is editing it.', '%s sidebars not updated, somebody is editing them.', 'content-aware-sidebars'),
294
- 'activated' => _n_noop('%s sidebar activated.', '%s sidebars activated.', 'content-aware-sidebars'),
295
- 'deactivated' => _n_noop('%s sidebar deactivated.', '%s sidebars deactivated.', 'content-aware-sidebars'),
296
- 'deleted' => _n_noop('%s sidebar permanently deleted.', '%s sidebars permanently deleted.', 'content-aware-sidebars'),
297
- 'trashed' => _n_noop('%s sidebar moved to the Trash.', '%s sidebars moved to the Trash.', 'content-aware-sidebars'),
298
- 'untrashed' => _n_noop('%s sidebar restored from the Trash.', '%s sidebars restored from the Trash.', 'content-aware-sidebars'),
299
- ];
300
- $bulk_messages = apply_filters('cas/admin/bulk_messages', $bulk_messages);
301
-
302
- $messages = [];
303
- foreach ($bulk_messages as $key => $message) {
304
- if (isset($_REQUEST[$key])) {
305
- $count = absint($_REQUEST[$key]);
306
- if ($count) {
307
- $messages[] = sprintf(
308
- translate_nooped_plural($message, $count),
309
- number_format_i18n($count)
310
- );
311
-
312
- if ($key == 'trashed' && isset($_REQUEST['ids'])) {
313
- $ids = preg_replace('/[^0-9,]/', '', $_REQUEST['ids']);
314
- $messages[] = '<a href="' . esc_url(wp_nonce_url("admin.php?page=wpcas&doaction=undo&action=untrash&ids=$ids", 'bulk-sidebars')) . '">' . __('Undo') . '</a>';
315
- }
316
- }
317
- }
318
- }
319
-
320
- if ($messages) {
321
- echo '<div id="message" class="updated notice is-dismissible"><p>' . join(' ', $messages) . '</p></div>';
322
- }
323
- }
324
-
325
- /**
326
- * Register and enqueue scripts styles
327
- * for screen
328
- *
329
- * @since 3.4
330
- */
331
- public function add_scripts_styles()
332
- {
333
- }
334
- }
1
+ <?php
2
+ /**
3
+ * @package Content Aware Sidebars
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ final class CAS_Sidebar_Overview extends CAS_Admin
12
+ {
13
+ /**
14
+ * Sidebar table
15
+ * @var CAS_Sidebar_List_Table
16
+ */
17
+ public $table;
18
+
19
+ /**
20
+ * Add filters and actions for admin dashboard
21
+ * e.g. AJAX calls
22
+ *
23
+ * @since 3.5
24
+ * @return void
25
+ */
26
+ public function admin_hooks()
27
+ {
28
+ $this->add_filter('set-screen-option', 'set_screen_option', 10, 3);
29
+ }
30
+
31
+ /**
32
+ * Setup admin menus and get current screen
33
+ *
34
+ * @since 3.4
35
+ * @return string
36
+ */
37
+ public function get_screen()
38
+ {
39
+ $post_type_object = $this->get_sidebar_type();
40
+ $notification_label = $this->notification_count ? sprintf(' <span class="awaiting-mod">%d</span>', $this->notification_count) : '';
41
+
42
+ add_menu_page(
43
+ $post_type_object->labels->name,
44
+ __('Content Aware', 'content-aware-sidebars') . $notification_label,
45
+ $post_type_object->cap->edit_posts,
46
+ CAS_App::BASE_SCREEN,
47
+ [$this,'render_screen'],
48
+ $post_type_object->menu_icon,
49
+ 60 //after Appearance
50
+ );
51
+
52
+ return add_submenu_page(
53
+ CAS_App::BASE_SCREEN,
54
+ $post_type_object->labels->name,
55
+ $post_type_object->labels->all_items,
56
+ $post_type_object->cap->edit_posts,
57
+ CAS_App::BASE_SCREEN,
58
+ [$this,'render_screen']
59
+ );
60
+ }
61
+
62
+ /**
63
+ * @since 3.5
64
+ *
65
+ * @return bool
66
+ */
67
+ public function authorize_user()
68
+ {
69
+ return current_user_can($this->get_sidebar_type()->cap->edit_posts);
70
+ }
71
+
72
+ /**
73
+ * @since 3.4
74
+ *
75
+ * @return void
76
+ */
77
+ public function prepare_screen()
78
+ {
79
+ add_screen_option('per_page', [
80
+ 'default' => 20,
81
+ 'option' => 'cas_sidebars_per_page'
82
+ ]);
83
+
84
+ $this->table = new CAS_Sidebar_List_Table();
85
+ $this->process_actions();//todo:add func to table to actions
86
+ $this->table->prepare_items();
87
+ }
88
+
89
+ /**
90
+ * Render screen
91
+ *
92
+ * @since 3.4
93
+ * @return void
94
+ */
95
+ public function render_screen()
96
+ {
97
+ $post_type_object = $this->get_sidebar_type();
98
+
99
+ echo '<div class="wrap">';
100
+ echo '<h1>';
101
+ echo esc_html($post_type_object->labels->name);
102
+
103
+ if (current_user_can($post_type_object->cap->create_posts)) {
104
+ echo ' <a href="' . esc_url(admin_url('admin.php?page=wpcas-edit')) . '" class="add-new-h2 page-title-action">' . esc_html($post_type_object->labels->add_new) . '</a>';
105
+ }
106
+ if (current_user_can('edit_theme_options')) {
107
+ echo ' <a href="' . esc_url(admin_url('widgets.php')) . '" class="page-title-action add-new-h2">' . __('Manage Widgets', 'content-aware-sidebars') . '</a>';
108
+ }
109
+ if (isset($_REQUEST['s']) && strlen($_REQUEST['s'])) {
110
+ /* translators: %s: search keywords */
111
+ printf(' <span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', get_search_query());
112
+ }
113
+
114
+ echo '</h1>';
115
+
116
+ $this->bulk_messages();
117
+
118
+ $_SERVER['REQUEST_URI'] = remove_query_arg(['locked', 'skipped', 'deleted', 'trashed', 'untrashed'], $_SERVER['REQUEST_URI']);
119
+
120
+ $this->table->views();
121
+
122
+ echo '<form id="posts-filter" method="get">';
123
+
124
+ $this->table->search_box($post_type_object->labels->search_items, 'post');
125
+
126
+ echo '<input type="hidden" name="page" value="wpcas" />';
127
+ echo '<input type="hidden" name="post_status" class="post_status_page" value="' . (!empty($_REQUEST['post_status']) ? esc_attr($_REQUEST['post_status']) : 'all') . '" />';
128
+
129
+ $this->table->display();
130
+
131
+ echo '</form></div>';
132
+ }
133
+
134
+ /**
135
+ * Process actions
136
+ *
137
+ * @since 3.4
138
+ * @return void
139
+ */
140
+ public function process_actions()
141
+ {
142
+ $doaction = $this->table->current_action();
143
+
144
+ if ($doaction) {
145
+ check_admin_referer('bulk-sidebars');
146
+
147
+ $pagenum = $this->table->get_pagenum();
148
+
149
+ $sendback = remove_query_arg(['activated','deactivated','trashed', 'untrashed', 'deleted', 'locked', 'ids'], wp_get_referer());
150
+ $sendback = add_query_arg('paged', $pagenum, $sendback);
151
+
152
+ if ('delete_all' == $doaction) {
153
+ global $wpdb;
154
+ $post_ids = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_type=%s AND post_status = %s", CAS_App::TYPE_SIDEBAR, 'trash'));
155
+
156
+ $doaction = 'delete';
157
+ } elseif (isset($_REQUEST['ids'])) {
158
+ $post_ids = explode(',', $_REQUEST['ids']);
159
+ } elseif (!empty($_REQUEST['post'])) {
160
+ $post_ids = array_map('intval', $_REQUEST['post']);
161
+ }
162
+
163
+ if (!isset($post_ids)) {
164
+ wp_redirect($sendback);
165
+ exit;
166
+ }
167
+
168
+ $post_ids = (array)$post_ids;
169
+ $handled = 0;
170
+
171
+ switch ($doaction) {
172
+ case 'activate':
173
+ case 'deactivate':
174
+ $locked = 0;
175
+
176
+ foreach ($post_ids as $post_id) {
177
+ if (!current_user_can('edit_post', $post_id)) {
178
+ wp_die(__('You are not allowed to update this item.'));
179
+ }
180
+
181
+ if (wp_check_post_lock($post_id)) {
182
+ $locked++;
183
+ continue;
184
+ }
185
+
186
+ if ($doaction == 'activate') {
187
+ $data = [
188
+ 'ID' => $post_id,
189
+ 'post_status' => CAS_App::STATUS_ACTIVE,
190
+ 'post_date' => current_time('mysql'),
191
+ 'post_date_gmt' => current_time('mysql', true)
192
+ ];
193
+ } else {
194
+ $data = [
195
+ 'ID' => $post_id,
196
+ 'post_status' => CAS_App::STATUS_INACTIVE
197
+ ];
198
+ }
199
+
200
+ if (!wp_update_post($data)) {
201
+ wp_die(__('Error in updating status.'));
202
+ }
203
+
204
+ $handled++;
205
+ }
206
+ $sendback = add_query_arg([$doaction . 'd' => $handled, 'ids' => join(',', $post_ids), 'locked' => $locked], $sendback);
207
+ break;
208
+ case 'trash':
209
+ $locked = 0;
210
+
211
+ foreach ($post_ids as $post_id) {
212
+ if (!current_user_can('delete_post', $post_id)) {
213
+ wp_die(__('You are not allowed to move this item to the Trash.'));
214
+ }
215
+
216
+ if (wp_check_post_lock($post_id)) {
217
+ $locked++;
218
+ continue;
219
+ }
220
+
221
+ if (!wp_trash_post($post_id)) {
222
+ wp_die(__('Error in moving to Trash.'));
223
+ }
224
+
225
+ $handled++;
226
+ }
227
+
228
+ $sendback = add_query_arg(['trashed' => $handled, 'ids' => join(',', $post_ids), 'locked' => $locked], $sendback);
229
+ break;
230
+ case 'untrash':
231
+ foreach ($post_ids as $post_id) {
232
+ if (!current_user_can('delete_post', $post_id)) {
233
+ wp_die(__('You are not allowed to restore this item from the Trash.'));
234
+ }
235
+
236
+ if (!wp_untrash_post($post_id)) {
237
+ wp_die(__('Error in restoring from Trash.'));
238
+ }
239
+
240
+ $handled++;
241
+ }
242
+ $sendback = add_query_arg('untrashed', $handled, $sendback);
243
+ break;
244
+ case 'delete':
245
+ foreach ($post_ids as $post_id) {
246
+ if (!current_user_can('delete_post', $post_id)) {
247
+ wp_die(__('You are not allowed to delete this item.'));
248
+ }
249
+
250
+ if (!wp_delete_post($post_id)) {
251
+ wp_die(__('Error in deleting.'));
252
+ }
253
+ $handled++;
254
+ }
255
+ $sendback = add_query_arg('deleted', $handled, $sendback);
256
+ break;
257
+ default:
258
+ break;
259
+ }
260
+
261
+ $sendback = remove_query_arg(['action', 'action2', 'post_status', 'post', 'bulk_edit'], $sendback);
262
+
263
+ wp_safe_redirect($sendback);
264
+ exit;
265
+ }
266
+ if (!empty($_REQUEST['_wp_http_referer'])) {
267
+ wp_safe_redirect(remove_query_arg(['_wp_http_referer', '_wpnonce'], wp_unslash($_SERVER['REQUEST_URI'])));
268
+ exit;
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Set screen options on save
274
+ *
275
+ * @since 3.4
276
+ * @param string $status
277
+ * @param string $option
278
+ * @param string $value
279
+ */
280
+ public function set_screen_option($status, $option, $value)
281
+ {
282
+ if ($option == 'cas_sidebars_per_page') {
283
+ return $value;
284
+ }
285
+ return $status;
286
+ }
287
+
288
+ public function bulk_messages()
289
+ {
290
+ $bulk_messages = [
291
+ 'updated' => _n_noop('%s sidebar updated.', '%s sidebars updated.', 'content-aware-sidebars'),
292
+ 'locked' => _n_noop('%s sidebar not updated, somebody is editing it.', '%s sidebars not updated, somebody is editing them.', 'content-aware-sidebars'),
293
+ 'activated' => _n_noop('%s sidebar activated.', '%s sidebars activated.', 'content-aware-sidebars'),
294
+ 'deactivated' => _n_noop('%s sidebar deactivated.', '%s sidebars deactivated.', 'content-aware-sidebars'),
295
+ 'deleted' => _n_noop('%s sidebar permanently deleted.', '%s sidebars permanently deleted.', 'content-aware-sidebars'),
296
+ 'trashed' => _n_noop('%s sidebar moved to the Trash.', '%s sidebars moved to the Trash.', 'content-aware-sidebars'),
297
+ 'untrashed' => _n_noop('%s sidebar restored from the Trash.', '%s sidebars restored from the Trash.', 'content-aware-sidebars'),
298
+ ];
299
+ $bulk_messages = apply_filters('cas/admin/bulk_messages', $bulk_messages);
300
+
301
+ $messages = [];
302
+ foreach ($bulk_messages as $key => $message) {
303
+ if (isset($_REQUEST[$key])) {
304
+ $count = absint($_REQUEST[$key]);
305
+ if ($count) {
306
+ $messages[] = sprintf(
307
+ translate_nooped_plural($message, $count),
308
+ number_format_i18n($count)
309
+ );
310
+
311
+ if ($key == 'trashed' && isset($_REQUEST['ids'])) {
312
+ $ids = preg_replace('/[^0-9,]/', '', $_REQUEST['ids']);
313
+ $messages[] = '<a href="' . esc_url(wp_nonce_url("admin.php?page=wpcas&doaction=undo&action=untrash&ids=$ids", 'bulk-sidebars')) . '">' . __('Undo') . '</a>';
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ if ($messages) {
320
+ echo '<div id="message" class="updated notice is-dismissible"><p>' . join(' ', $messages) . '</p></div>';
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Register and enqueue scripts styles
326
+ * for screen
327
+ *
328
+ * @since 3.4
329
+ */
330
+ public function add_scripts_styles()
331
+ {
332
+ }
333
+ }
 
app.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
@@ -11,7 +11,7 @@ defined('ABSPATH') || exit;
11
  final class CAS_App
12
  {
13
  const PLUGIN_VERSION_KEY = 'cas_db_version';
14
- const PLUGIN_VERSION = '3.16.2';
15
 
16
  /**
17
  * Prefix for sidebar id
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
11
  final class CAS_App
12
  {
13
  const PLUGIN_VERSION_KEY = 'cas_db_version';
14
+ const PLUGIN_VERSION = '3.17';
15
 
16
  /**
17
  * Prefix for sidebar id
assets/css/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
assets/css/style.css CHANGED
@@ -2,5 +2,5 @@
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
- * @copyright 2021 by Joachim Jensen
6
  */#cas-rules .cas-heart{color:#ac170a}body.js .js-cas-visibility{max-height:30px;overflow:hidden}.cas-section,.js-cas-action{display:none}.nav-tab-wrapper.js-cas-tabs .nav-tab{position:relative}.nav-tab-active:focus{box-shadow:none}.cas-input-inline{display:inline-block}.cas-input-sm{max-width:80px;font-size:.8em;vertical-align:middle}.cas-metabox-holder .hndle{cursor:auto!important}#submitdiv .handlediv,#submitdiv .hndle,#submitdiv .postbox-header,.cas-metabox-holder .handle-actions,.cas-metabox-holder .handlediv{display:none!important}#submitdiv .cas-save{background:#f5f5f5;border-bottom:1px solid #ddd;overflow:hidden;padding:7px 10px}#submitdiv .cas-overview-actions{padding:0 10px}#submitdiv .cas-overview-actions .dashicons{color:#82878c}#submitdiv .cas-overview-actions>li{margin:0}#submitdiv .cas-overview-actions>li:not(:last-of-type){padding:0 0 10px;margin:0 0 10px;border-bottom:1px solid #eee}.cas-pro-label{font-size:.8em;background-color:#31c455;border-radius:5px;color:#fff;padding:2px 6px;text-transform:uppercase;vertical-align:baseline;white-space:nowrap;font-weight:700}.button.button-cas-delete{color:#fff;text-decoration:none;background-color:#a00;border:1px solid #000}.button.button-cas-delete:hover{color:#fff;background-color:red}a.cas-delete{color:#a00;text-decoration:none}a.cas-delete:hover{color:red}.cas-schedule-slide.ui-slider{position:relative;margin:12px;border-radius:4px;background:#c5c5c5;color:#333}.cas-schedule-slide.ui-slider .ui-slider-handle{position:absolute;z-index:2;height:24px;width:24px;touch-action:none;text-align:center;border-radius:12px;transition:background .2s}.cas-schedule-slide.ui-slider .ui-slider-handle.ui-state-default{border:1px solid #c5c5c5;background:#fff;box-shadow:0 0 0 9px #fff inset,0 1px 2px rgba(0,0,0,.15)}.cas-schedule-slide.ui-slider .ui-slider-handle.ui-state-active{background:#7ad03a;border-color:#999}.cas-schedule-slide.ui-slider .ui-slider-handle.ui-state-focus:focus{outline:0}.cas-schedule-slide.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background:#7ad03a}.cas-schedule-slide.ui-slider.ui-state-disabled{opacity:.35;cursor:default!important;pointer-events:none}.cas-schedule-slide.ui-slider.ui-slider-horizontal{height:4px}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-handle{margin-left:-12px;top:-12px}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-range-min{left:0}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-range-max{right:0}.button.button-cas-upgrade{background:#dd1d0c;color:#fff;border-color:#ac170a;font-weight:700;box-shadow:0 0 0 1px rgba(255,255,255,.3) inset,0 1px 0 #ac170a}.button.button-cas-upgrade:hover{color:#fff;border-color:#ac170a;background:#eb5c50}.button.button-cas-upgrade:active,.button.button-cas-upgrade:focus{color:#fff;background:#dd1d0c;border-color:#ac170a;box-shadow:inset 0 2px 0 #ac170a;vertical-align:top}#cas-plugin-links.postbox{background-color:#ddecf4;border-color:#9fcadf;box-shadow:0 0 0 1px #fff inset,0 1px 1px rgba(0,0,0,.04)}#cas-plugin-links .postbox-header{border-bottom-color:#9fcadf;box-shadow:0 -1px #fff inset}#cas-plugin-links .handle-actions{display:none!important}.wp-list-table.fixed.striped>tbody>:nth-child(2n+1){background-color:#f9f9f9}.wp-list-table.fixed .column-handler,.wp-list-table.fixed .column-visibility{width:20%}.wp-list-table.fixed .column-status,.wp-list-table.fixed .column-widgets{width:80px}.wp-list-table.fixed .column-status .dashicons{color:#999}.wp-list-table.fixed .column-status .sidebar-status{display:inline-block;margin-right:6px}.sidebar-status{margin:2px 0 0;position:relative;width:28px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;box-sizing:border-box}.sidebar-status .sidebar-status-input{display:none}.sidebar-status .sidebar-status-label{display:block;overflow:hidden;cursor:pointer;height:16px;padding:0;line-height:16px;border-radius:16px;background-color:#dc3232;box-shadow:0 0 2px rgba(0,0,0,.2) inset;transition:background-color .2s ease-in}.sidebar-status .sidebar-status-label:before{content:"";display:block;width:12px;height:12px;margin:0;background:#fff;position:absolute;top:2px;bottom:0;right:14px;border-radius:16px;transition:right .2s ease-in;box-shadow:0 1px 2px rgba(0,0,0,.2)}.sidebar-status .sidebar-status-input:checked+.sidebar-status-label{background-color:#7ad03a}.sidebar-status .sidebar-status-input:checked+.sidebar-status-label:before{right:2px}.sidebar-status .sidebar-status-input.sidebar-status-future:not(:checked)+.sidebar-status-label{background-color:#ffb900}.sidebar-status .sidebar-status-input:disabled+.sidebar-status-label{cursor:auto}.widget-liquid-right .widgets-holder-wrap .sidebar-name h2,.widget-liquid-right .widgets-holder-wrap .sidebar-name h3{text-overflow:ellipsis}.widget-liquid-right .widgets-holder-wrap .cas-settings{border-top:1px solid #dfdfdf;border-bottom:1px solid #dfdfdf;background-color:#f7f7f7;margin-left:-8px;margin-right:-8px;margin-bottom:10px;overflow:hidden}.widget-liquid-right .widgets-holder-wrap .sidebar-status{float:right;margin:10px 10px 0}.widget-liquid-right .widgets-holder-wrap .cas-sidebar-link{display:inline-block;border-right:1px solid #dfdfdf;padding:8px 10px;color:#888;text-decoration:none;transition:.4s;box-shadow:none}.widget-liquid-right .widgets-holder-wrap .cas-sidebar-link:hover{background-color:#fff;color:#222}.widget-liquid-right .widgets-holder-wrap.closed .cas-settings{display:none}.widget-liquid-right .widgets-holder-wrap div[id^=ca-sidebar],.wp-block-widget-area .components-panel__body-title{box-shadow:inset 0 4px #75d7ef}.cas-form-table{width:97%;margin:0 auto}.cas-form-table tr td:first-child{min-width:30%}.cas-form-table tr td{border-bottom:1px solid #eee}.cas-schedule-days{text-transform:uppercase;overflow:hidden;display:inline-block;border:1px solid #dfdfdf;margin:0;border-radius:3px}.cas-schedule-days li{float:left;margin:0}.cas-schedule-days input{display:none}.cas-schedule-days label{transition:background .2s;background:#0085ba;display:block;padding:8px 12px;color:#fff}.cas-schedule-days label:hover{background:#007aab}.cas-schedule-days input:checked+label{color:inherit;background:#f1f1f1}.cas-schedule-days input:checked+label:hover{background:#e9e9e9}.cas-filter-sidebar{max-width:calc(900px + 2%);margin:10px 0;vertical-align:middle}.cas-filter-sidebar .sidebars-toggle{margin:16px 0 0 10px;display:inline-block}.cas-filter-sidebar .sidebars-toggle a{outline:0;box-shadow:none}.cas-filter-sidebar .button{margin:10px 0}.cas-filter-sidebar input{float:right}input.cas-filter{margin:10px 0}.wp-header-end{visibility:visible;margin:14px -20px 0;clear:both}@media (min-width:783px){.cas-widget-manager:not(.widgets_access) #screen-meta{z-index:20}.cas-widget-manager:not(.widgets_access) .widget-liquid-left{position:absolute;top:50px}.cas-widget-manager:not(.widgets_access) .wrap .error,.cas-widget-manager:not(.widgets_access) .wrap .notice,.cas-widget-manager:not(.widgets_access) .wrap .postbox,.cas-widget-manager:not(.widgets_access) .wrap .updated,.cas-widget-manager:not(.widgets_access) .wrap h1{margin:0 0 0 calc(38% + 56px)}.cas-widget-manager:not(.widgets_access) .update-nag{margin-left:calc(38% + 50px)}.cas-widget-manager:not(.widgets_access) #available-widgets{z-index:1;position:fixed;top:32px;padding:0 10px;background:#fafafa;box-shadow:0 0 4px 0 rgba(0,0,0,.1);width:32%;border-color:#dfdfdf;border-style:solid;border-width:0 1px 1px 0;left:160px}.cas-widget-manager:not(.widgets_access) #available-widgets input.cas-filter{width:100%}.cas-widget-manager:not(.widgets_access) #available-widgets .widget{padding-bottom:10px}.cas-widget-manager:not(.widgets_access) #available-widgets #widget-list{border-top:1px solid #dfdfdf;padding:3px;margin:0 -10px;background:#fff}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed){min-height:600px;bottom:0;border-bottom-width:0}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name{position:static}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name .handlediv,.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name .sidebar-name-arrow{display:block;bottom:auto;right:10px}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name .toggle-indicator{display:block}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) #removing-widget{box-sizing:border-box;padding:10px 0 0;color:#c00;z-index:2;text-align:center;position:absolute;background-color:rgba(255,255,255,.6);border:4px dashed #c00;top:0;left:0;right:0;height:100%}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .description{display:none}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) #widget-list{position:fixed;top:120px;padding:12px 10px;overflow-y:auto;overflow-x:hidden;width:calc(32% - 1px);bottom:0}.cas-widget-manager:not(.widgets_access).folded #available-widgets{left:36px;width:37.5%}.cas-widget-manager:not(.widgets_access).folded #available-widgets:not(.closed) #widget-list{width:calc(37.5% - 1px)}.cas-widget-manager:not(.widgets_access).rtl .wrap .error,.cas-widget-manager:not(.widgets_access).rtl .wrap .notice,.cas-widget-manager:not(.widgets_access).rtl .wrap .postbox,.cas-widget-manager:not(.widgets_access).rtl .wrap .update-nag,.cas-widget-manager:not(.widgets_access).rtl .wrap .updated,.cas-widget-manager:not(.widgets_access).rtl .wrap h1{margin:0 calc(38% + 56px) 0 0}.cas-widget-manager:not(.widgets_access).rtl .update-nag{margin-right:calc(38% + 50px)}.cas-widget-manager:not(.widgets_access).rtl #available-widgets{box-shadow:0 0 5px 0 rgba(0,0,0,.1);right:160px;left:auto;border-width:0 0 1px 1px}.cas-widget-manager:not(.widgets_access).rtl #available-widgets:not(.closed) .sidebar-name .handlediv,.cas-widget-manager:not(.widgets_access).rtl #available-widgets:not(.closed) .sidebar-name .sidebar-name-arrow{left:10px;right:auto}.cas-widget-manager:not(.widgets_access).rtl.folded #available-widgets{left:auto;right:36px}.cas-widget-manager:not(.widgets_access) #widgets-right .widgets-sortables{z-index:2}.cas-widget-manager div.widget-liquid-right{padding:0;margin:0;width:58%;float:right;background:0 0}.cas-widget-manager div.widget-liquid-left{width:38%;margin:0;float:left;padding:0}.cas-widget-manager .fw-ext-sidebars-wrap-container{float:right}}@media (min-width:783px) and (max-width:960px){.cas-widget-manager.auto-fold:not(.widgets_access) #available-widgets{left:36px;width:36%}.cas-widget-manager.auto-fold:not(.widgets_access) #available-widgets:not(.closed) #widget-list{width:calc(36% - 1px)}.cas-widget-manager.auto-fold:not(.widgets_access).rtl #available-widgets{left:auto;right:36px}}@media (max-width:782px){input.cas-filter{width:100%}}@media (max-width:1249px){div#widgets-right .sidebars-column-1,div#widgets-right .sidebars-column-2{max-width:inherit}}@media (min-width:1250px){.cas-widget-manager:not(.widgets_access) #widgets-left #available-widgets .widget:nth-child(even){float:left;margin:0 0 0 2%}.cas-widget-manager:not(.widgets_access) #available-widgets{width:34.5%}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) #widget-list{width:calc(34.5% - 1px)}.cas-widget-manager:not(.widgets_access).rtl #widgets-left #available-widgets .widget{float:right;padding-left:2%}.cas-widget-manager:not(.widgets_access).rtl #widgets-left #available-widgets .widget:nth-child(odd){margin-right:-2%}}.widgets-php #wpcontent .wrap .cs-wrap{margin:0!important}#cs-title-options,.custom-sidebars-add-new,div[id^=ca-sidebar]+.cs-toolbar{display:none}
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
+ * @copyright 2022 by Joachim Jensen
6
  */#cas-rules .cas-heart{color:#ac170a}body.js .js-cas-visibility{max-height:30px;overflow:hidden}.cas-section,.js-cas-action{display:none}.nav-tab-wrapper.js-cas-tabs .nav-tab{position:relative}.nav-tab-active:focus{box-shadow:none}.cas-input-inline{display:inline-block}.cas-input-sm{max-width:80px;font-size:.8em;vertical-align:middle}.cas-metabox-holder .hndle{cursor:auto!important}#submitdiv .handlediv,#submitdiv .hndle,#submitdiv .postbox-header,.cas-metabox-holder .handle-actions,.cas-metabox-holder .handlediv{display:none!important}#submitdiv .cas-save{background:#f5f5f5;border-bottom:1px solid #ddd;overflow:hidden;padding:7px 10px}#submitdiv .cas-overview-actions{padding:0 10px}#submitdiv .cas-overview-actions .dashicons{color:#82878c}#submitdiv .cas-overview-actions>li{margin:0}#submitdiv .cas-overview-actions>li:not(:last-of-type){padding:0 0 10px;margin:0 0 10px;border-bottom:1px solid #eee}.cas-pro-label{font-size:.8em;background-color:#31c455;border-radius:5px;color:#fff;padding:2px 6px;text-transform:uppercase;vertical-align:baseline;white-space:nowrap;font-weight:700}.button.button-cas-delete{color:#fff;text-decoration:none;background-color:#a00;border:1px solid #000}.button.button-cas-delete:hover{color:#fff;background-color:red}a.cas-delete{color:#a00;text-decoration:none}a.cas-delete:hover{color:red}.cas-schedule-slide.ui-slider{position:relative;margin:12px;border-radius:4px;background:#c5c5c5;color:#333}.cas-schedule-slide.ui-slider .ui-slider-handle{position:absolute;z-index:2;height:24px;width:24px;touch-action:none;text-align:center;border-radius:12px;transition:background .2s}.cas-schedule-slide.ui-slider .ui-slider-handle.ui-state-default{border:1px solid #c5c5c5;background:#fff;box-shadow:0 0 0 9px #fff inset,0 1px 2px rgba(0,0,0,.15)}.cas-schedule-slide.ui-slider .ui-slider-handle.ui-state-active{background:#7ad03a;border-color:#999}.cas-schedule-slide.ui-slider .ui-slider-handle.ui-state-focus:focus{outline:0}.cas-schedule-slide.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background:#7ad03a}.cas-schedule-slide.ui-slider.ui-state-disabled{opacity:.35;cursor:default!important;pointer-events:none}.cas-schedule-slide.ui-slider.ui-slider-horizontal{height:4px}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-handle{margin-left:-12px;top:-12px}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-range-min{left:0}.cas-schedule-slide.ui-slider.ui-slider-horizontal .ui-slider-range-max{right:0}.button.button-cas-upgrade{background:#dd1d0c;color:#fff;border-color:#ac170a;font-weight:700;box-shadow:0 0 0 1px rgba(255,255,255,.3) inset,0 1px 0 #ac170a}.button.button-cas-upgrade:hover{color:#fff;border-color:#ac170a;background:#eb5c50}.button.button-cas-upgrade:active,.button.button-cas-upgrade:focus{color:#fff;background:#dd1d0c;border-color:#ac170a;box-shadow:inset 0 2px 0 #ac170a;vertical-align:top}#cas-plugin-links.postbox{background-color:#ddecf4;border-color:#9fcadf;box-shadow:0 0 0 1px #fff inset,0 1px 1px rgba(0,0,0,.04)}#cas-plugin-links .postbox-header{border-bottom-color:#9fcadf;box-shadow:0 -1px #fff inset}#cas-plugin-links .handle-actions{display:none!important}.wp-list-table.fixed.striped>tbody>:nth-child(2n+1){background-color:#f9f9f9}.wp-list-table.fixed .column-handler,.wp-list-table.fixed .column-visibility{width:20%}.wp-list-table.fixed .column-status,.wp-list-table.fixed .column-widgets{width:80px}.wp-list-table.fixed .column-status .dashicons{color:#999}.wp-list-table.fixed .column-status .sidebar-status{display:inline-block;margin-right:6px}.sidebar-status{margin:2px 0 0;position:relative;width:28px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;box-sizing:border-box}.sidebar-status .sidebar-status-input{display:none}.sidebar-status .sidebar-status-label{display:block;overflow:hidden;cursor:pointer;height:16px;padding:0;line-height:16px;border-radius:16px;background-color:#dc3232;box-shadow:0 0 2px rgba(0,0,0,.2) inset;transition:background-color .2s ease-in}.sidebar-status .sidebar-status-label:before{content:"";display:block;width:12px;height:12px;margin:0;background:#fff;position:absolute;top:2px;bottom:0;right:14px;border-radius:16px;transition:right .2s ease-in;box-shadow:0 1px 2px rgba(0,0,0,.2)}.sidebar-status .sidebar-status-input:checked+.sidebar-status-label{background-color:#7ad03a}.sidebar-status .sidebar-status-input:checked+.sidebar-status-label:before{right:2px}.sidebar-status .sidebar-status-input.sidebar-status-future:not(:checked)+.sidebar-status-label{background-color:#ffb900}.sidebar-status .sidebar-status-input:disabled+.sidebar-status-label{cursor:auto}.widget-liquid-right .widgets-holder-wrap .sidebar-name h2,.widget-liquid-right .widgets-holder-wrap .sidebar-name h3{text-overflow:ellipsis}.widget-liquid-right .widgets-holder-wrap .cas-settings{border-top:1px solid #dfdfdf;border-bottom:1px solid #dfdfdf;background-color:#f7f7f7;margin-left:-8px;margin-right:-8px;margin-bottom:10px;overflow:hidden}.widget-liquid-right .widgets-holder-wrap .sidebar-status{float:right;margin:10px 10px 0}.widget-liquid-right .widgets-holder-wrap .cas-sidebar-link{display:inline-block;border-right:1px solid #dfdfdf;padding:8px 10px;color:#888;text-decoration:none;transition:.4s;box-shadow:none}.widget-liquid-right .widgets-holder-wrap .cas-sidebar-link:hover{background-color:#fff;color:#222}.widget-liquid-right .widgets-holder-wrap.closed .cas-settings{display:none}.widget-liquid-right .widgets-holder-wrap div[id^=ca-sidebar],.wp-block-widget-area .components-panel__body-title{box-shadow:inset 0 4px #75d7ef}.cas-form-table{width:97%;margin:0 auto}.cas-form-table tr td:first-child{min-width:30%}.cas-form-table tr td{border-bottom:1px solid #eee}.cas-schedule-days{text-transform:uppercase;overflow:hidden;display:inline-block;border:1px solid #dfdfdf;margin:0;border-radius:3px}.cas-schedule-days li{float:left;margin:0}.cas-schedule-days input{display:none}.cas-schedule-days label{transition:background .2s;background:#0085ba;display:block;padding:8px 12px;color:#fff}.cas-schedule-days label:hover{background:#007aab}.cas-schedule-days input:checked+label{color:inherit;background:#f1f1f1}.cas-schedule-days input:checked+label:hover{background:#e9e9e9}.cas-filter-sidebar{max-width:calc(900px + 2%);margin:10px 0;vertical-align:middle}.cas-filter-sidebar .sidebars-toggle{margin:16px 0 0 10px;display:inline-block}.cas-filter-sidebar .sidebars-toggle a{outline:0;box-shadow:none}.cas-filter-sidebar .button{margin:10px 0}.cas-filter-sidebar input{float:right}input.cas-filter{margin:10px 0}.wp-header-end{visibility:visible;margin:14px -20px 0;clear:both}@media (min-width:783px){.cas-widget-manager:not(.widgets_access) #screen-meta{z-index:20}.cas-widget-manager:not(.widgets_access) .widget-liquid-left{position:absolute;top:50px}.cas-widget-manager:not(.widgets_access) .wrap .error,.cas-widget-manager:not(.widgets_access) .wrap .notice,.cas-widget-manager:not(.widgets_access) .wrap .postbox,.cas-widget-manager:not(.widgets_access) .wrap .updated,.cas-widget-manager:not(.widgets_access) .wrap h1{margin:0 0 0 calc(38% + 56px)}.cas-widget-manager:not(.widgets_access) .update-nag{margin-left:calc(38% + 50px)}.cas-widget-manager:not(.widgets_access) #available-widgets{z-index:1;position:fixed;top:32px;padding:0 10px;background:#fafafa;box-shadow:0 0 4px 0 rgba(0,0,0,.1);width:32%;border-color:#dfdfdf;border-style:solid;border-width:0 1px 1px 0;left:160px}.cas-widget-manager:not(.widgets_access) #available-widgets input.cas-filter{width:100%}.cas-widget-manager:not(.widgets_access) #available-widgets .widget{padding-bottom:10px}.cas-widget-manager:not(.widgets_access) #available-widgets #widget-list{border-top:1px solid #dfdfdf;padding:3px;margin:0 -10px;background:#fff}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed){min-height:600px;bottom:0;border-bottom-width:0}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name{position:static}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name .handlediv,.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name .sidebar-name-arrow{display:block;bottom:auto;right:10px}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .sidebar-name .toggle-indicator{display:block}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) #removing-widget{box-sizing:border-box;padding:10px 0 0;color:#c00;z-index:2;text-align:center;position:absolute;background-color:rgba(255,255,255,.6);border:4px dashed #c00;top:0;left:0;right:0;height:100%}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) .description{display:none}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) #widget-list{position:fixed;top:120px;padding:12px 10px;overflow-y:auto;overflow-x:hidden;width:calc(32% - 1px);bottom:0}.cas-widget-manager:not(.widgets_access).folded #available-widgets{left:36px;width:37.5%}.cas-widget-manager:not(.widgets_access).folded #available-widgets:not(.closed) #widget-list{width:calc(37.5% - 1px)}.cas-widget-manager:not(.widgets_access).rtl .wrap .error,.cas-widget-manager:not(.widgets_access).rtl .wrap .notice,.cas-widget-manager:not(.widgets_access).rtl .wrap .postbox,.cas-widget-manager:not(.widgets_access).rtl .wrap .update-nag,.cas-widget-manager:not(.widgets_access).rtl .wrap .updated,.cas-widget-manager:not(.widgets_access).rtl .wrap h1{margin:0 calc(38% + 56px) 0 0}.cas-widget-manager:not(.widgets_access).rtl .update-nag{margin-right:calc(38% + 50px)}.cas-widget-manager:not(.widgets_access).rtl #available-widgets{box-shadow:0 0 5px 0 rgba(0,0,0,.1);right:160px;left:auto;border-width:0 0 1px 1px}.cas-widget-manager:not(.widgets_access).rtl #available-widgets:not(.closed) .sidebar-name .handlediv,.cas-widget-manager:not(.widgets_access).rtl #available-widgets:not(.closed) .sidebar-name .sidebar-name-arrow{left:10px;right:auto}.cas-widget-manager:not(.widgets_access).rtl.folded #available-widgets{left:auto;right:36px}.cas-widget-manager:not(.widgets_access) #widgets-right .widgets-sortables{z-index:2}.cas-widget-manager div.widget-liquid-right{padding:0;margin:0;width:58%;float:right;background:0 0}.cas-widget-manager div.widget-liquid-left{width:38%;margin:0;float:left;padding:0}.cas-widget-manager .fw-ext-sidebars-wrap-container{float:right}}@media (min-width:783px) and (max-width:960px){.cas-widget-manager.auto-fold:not(.widgets_access) #available-widgets{left:36px;width:36%}.cas-widget-manager.auto-fold:not(.widgets_access) #available-widgets:not(.closed) #widget-list{width:calc(36% - 1px)}.cas-widget-manager.auto-fold:not(.widgets_access).rtl #available-widgets{left:auto;right:36px}}@media (max-width:782px){input.cas-filter{width:100%}}@media (max-width:1249px){div#widgets-right .sidebars-column-1,div#widgets-right .sidebars-column-2{max-width:inherit}}@media (min-width:1250px){.cas-widget-manager:not(.widgets_access) #widgets-left #available-widgets .widget:nth-child(even){float:left;margin:0 0 0 2%}.cas-widget-manager:not(.widgets_access) #available-widgets{width:34.5%}.cas-widget-manager:not(.widgets_access) #available-widgets:not(.closed) #widget-list{width:calc(34.5% - 1px)}.cas-widget-manager:not(.widgets_access).rtl #widgets-left #available-widgets .widget{float:right;padding-left:2%}.cas-widget-manager:not(.widgets_access).rtl #widgets-left #available-widgets .widget:nth-child(odd){margin-right:-2%}}.widgets-php #wpcontent .wrap .cs-wrap{margin:0!important}#cs-title-options,.custom-sidebars-add-new,div[id^=ca-sidebar]+.cs-toolbar{display:none}
assets/img/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
assets/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
assets/js/cas_admin.min.js CHANGED
@@ -2,6 +2,6 @@
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
- * @copyright 2021 by Joachim Jensen
6
  */
7
  !function($){"use strict";var e={current_section:0,sections:[],init:function(){this.tabController(),this.actionOptionHandler(),this.suggestVisibility(),this.suggestTarget(),this.initSidebarActivation(),$(".js-cas-color-field").wpColorPicker(),$(".js-cas-html").on("change",function(t){var e=$(this);$(e.data("target")).attr("disabled",!e.is(":checked"))}).trigger("change")},initSidebarActivation:function(){flatpickr.l10ns.default.weekdays=CASAdmin.weekdays,flatpickr.l10ns.default.months=CASAdmin.months,flatpickr.l10ns.default.firstDayOfWeek=CASAdmin.weekStart;var t=-1===CASAdmin.timeFormat.toLowerCase().indexOf("a"),i=flatpickr(".js-cas-activation",{wrap:!0,clickOpens:!0,enableTime:!0,time_24hr:t,allowInput:!0,enableSeconds:!0,onChange:function(t,e,n){(e||a.config.minDate)&&a.set("minDate",e?new Date(t):null),e?s.prop("checked",!1):s.is(":checked")||a.clear()}}),a=flatpickr(".js-cas-expiry",{wrap:!0,clickOpens:!0,enableTime:!0,time_24hr:t,allowInput:!0,enableSeconds:!0,onChange:function(t,e,n){(e||i.config.maxDate)&&i.set("maxDate",e?new Date(t):null)}}),s=$(".js-cas-status");s.on("change",function(t){$(this).is(":checked")?i.clear():i.selectedDates.length||a.clear()})},initTabSections:function(){$(".js-cas-tabs").find(".nav-tab").each(function(){var t=this.href.lastIndexOf("#");0<=t&&(t=this.href.substr(t),e.sections.push(t),$(t).hide())})},tabController:function(){this.initTabSections(),this.setCurrentSection(window.location.hash),$("#poststuff").on("click",".js-nav-link",function(t){e.setCurrentSection(this.href)})},findSectionByURL:function(t){t=this.sections.indexOf(t.substring(t.lastIndexOf("#")));return 0<=t?t:null},setCurrentSection:function(t){var e=this.findSectionByURL(t)||0,t=$(".js-cas-tabs").find(".nav-tab");t.eq(e).is(":visible")&&($(this.sections[this.current_section]).hide(),t.eq(this.current_section).removeClass("nav-tab-active"),this.current_section=e,$(this.sections[this.current_section]).show(),t.eq(this.current_section).addClass("nav-tab-active"),$("#_cas_section").val("#top"+this.sections[this.current_section]))},actionOptionHandler:function(){var t=$("#cas-options"),e=t.find(".js-cas-action");t.on("change",".js-cas-handle",function(){var t=$(this),t=e.filter(".js-cas-action-"+t.val());e.not(t).hide().find("input,select").attr("disabled",!0),t.fadeIn("fast").find("input,select").attr("disabled",!1)}),t.find(".js-cas-handle").trigger("change")},suggestVisibility:function(){var e=$(".js-cas-visibility");e.select2({theme:"wpca",placeholder:CASAdmin.allVisibility,minimumInputLength:0,closeOnSelect:!0,allowClear:!1,nextSearchTerm:function(t,e){return e},data:CASAdmin.visibility}).on("select2:selecting",function(t){e.data("forceOpen",!0)}).on("select2:close",function(t){e.data("forceOpen")&&(t.preventDefault(),e.select2("open"),e.data("forceOpen",!1))}),e.data("value")&&e.val(e.data("value").toString().split(",")).trigger("change")},suggestTarget:function(){var e=$(".js-cas-host");e.select2({theme:"wpca",minimumInputLength:0,closeOnSelect:!0,allowClear:!1,width:"250px",nextSearchTerm:function(t,e){return e},data:CASAdmin.target}).on("select2:selecting",function(t){e.data("forceOpen",!0)}).on("select2:close",function(t){e.data("forceOpen")&&(t.preventDefault(),e.select2("open"),e.data("forceOpen",!1))}),e.data("value")&&e.val(e.data("value").toString().split(",")).trigger("change")}};$(document).ready(function(){e.init()})}(jQuery);
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
+ * @copyright 2022 by Joachim Jensen
6
  */
7
  !function($){"use strict";var e={current_section:0,sections:[],init:function(){this.tabController(),this.actionOptionHandler(),this.suggestVisibility(),this.suggestTarget(),this.initSidebarActivation(),$(".js-cas-color-field").wpColorPicker(),$(".js-cas-html").on("change",function(t){var e=$(this);$(e.data("target")).attr("disabled",!e.is(":checked"))}).trigger("change")},initSidebarActivation:function(){flatpickr.l10ns.default.weekdays=CASAdmin.weekdays,flatpickr.l10ns.default.months=CASAdmin.months,flatpickr.l10ns.default.firstDayOfWeek=CASAdmin.weekStart;var t=-1===CASAdmin.timeFormat.toLowerCase().indexOf("a"),i=flatpickr(".js-cas-activation",{wrap:!0,clickOpens:!0,enableTime:!0,time_24hr:t,allowInput:!0,enableSeconds:!0,onChange:function(t,e,n){(e||a.config.minDate)&&a.set("minDate",e?new Date(t):null),e?s.prop("checked",!1):s.is(":checked")||a.clear()}}),a=flatpickr(".js-cas-expiry",{wrap:!0,clickOpens:!0,enableTime:!0,time_24hr:t,allowInput:!0,enableSeconds:!0,onChange:function(t,e,n){(e||i.config.maxDate)&&i.set("maxDate",e?new Date(t):null)}}),s=$(".js-cas-status");s.on("change",function(t){$(this).is(":checked")?i.clear():i.selectedDates.length||a.clear()})},initTabSections:function(){$(".js-cas-tabs").find(".nav-tab").each(function(){var t=this.href.lastIndexOf("#");0<=t&&(t=this.href.substr(t),e.sections.push(t),$(t).hide())})},tabController:function(){this.initTabSections(),this.setCurrentSection(window.location.hash),$("#poststuff").on("click",".js-nav-link",function(t){e.setCurrentSection(this.href)})},findSectionByURL:function(t){t=this.sections.indexOf(t.substring(t.lastIndexOf("#")));return 0<=t?t:null},setCurrentSection:function(t){var e=this.findSectionByURL(t)||0,t=$(".js-cas-tabs").find(".nav-tab");t.eq(e).is(":visible")&&($(this.sections[this.current_section]).hide(),t.eq(this.current_section).removeClass("nav-tab-active"),this.current_section=e,$(this.sections[this.current_section]).show(),t.eq(this.current_section).addClass("nav-tab-active"),$("#_cas_section").val("#top"+this.sections[this.current_section]))},actionOptionHandler:function(){var t=$("#cas-options"),e=t.find(".js-cas-action");t.on("change",".js-cas-handle",function(){var t=$(this),t=e.filter(".js-cas-action-"+t.val());e.not(t).hide().find("input,select").attr("disabled",!0),t.fadeIn("fast").find("input,select").attr("disabled",!1)}),t.find(".js-cas-handle").trigger("change")},suggestVisibility:function(){var e=$(".js-cas-visibility");e.select2({theme:"wpca",placeholder:CASAdmin.allVisibility,minimumInputLength:0,closeOnSelect:!0,allowClear:!1,nextSearchTerm:function(t,e){return e},data:CASAdmin.visibility}).on("select2:selecting",function(t){e.data("forceOpen",!0)}).on("select2:close",function(t){e.data("forceOpen")&&(t.preventDefault(),e.select2("open"),e.data("forceOpen",!1))}),e.data("value")&&e.val(e.data("value").toString().split(",")).trigger("change")},suggestTarget:function(){var e=$(".js-cas-host");e.select2({theme:"wpca",minimumInputLength:0,closeOnSelect:!0,allowClear:!1,width:"250px",nextSearchTerm:function(t,e){return e},data:CASAdmin.target}).on("select2:selecting",function(t){e.data("forceOpen",!0)}).on("select2:close",function(t){e.data("forceOpen")&&(t.preventDefault(),e.select2("open"),e.data("forceOpen",!1))}),e.data("value")&&e.val(e.data("value").toString().split(",")).trigger("change")}};$(document).ready(function(){e.init()})}(jQuery);
assets/js/general.min.js CHANGED
@@ -2,6 +2,6 @@
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
- * @copyright 2021 by Joachim Jensen
6
  */
7
  !function($){"use strict";var t={init:function(){this.toggleSidebarStatus(),CAS.showPopups&&(this.upgradeNoticeHandler(),this.reviewNoticeHandler())},toggleSidebarStatus:function(){$(".sidebar-status").on("change","input.sidebar-status-input",function(t){var a=$(this),e=a.is(":checked");if(a.hasClass("sidebar-status-future")&&!confirm(CAS.enableConfirm))return a.attr("checked",!e),t.preventDefault(),!1;$.post(ajaxurl,{action:"cas_sidebar_status",sidebar_id:a.val(),token:a.attr("data-nonce"),status:e},function(t){t.success?(a.next().attr("title",t.data.title),a.removeClass("sidebar-status-future")):(alert(t.data),a.attr("checked",!e))})})},upgradeNoticeHandler:function(){$(".js-cas-pro-notice.button").attr("disabled",!0),$(".js-cas-pro-notice").on("click",function(t){t.preventDefault(),$(".js-cas-pro-read-more").attr("href",$(this).data("url")),$(".js-cas-pro-popup").trigger("click")})},reviewNoticeHandler:function(){var e=$(".js-cas-notice-review");e.on("click","a, button",function(t){var a=$(this);$.ajax({url:ajaxurl,data:{action:"cas_dismiss_review_notice",dismiss:a.data("cas-rating")?1:0},dataType:"JSON",type:"POST",success:function(t){e.fadeOut(400,function(){e.remove()})},error:function(t,a,e){}})})}};$(document).ready(function(){t.init()})}(jQuery);
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
+ * @copyright 2022 by Joachim Jensen
6
  */
7
  !function($){"use strict";var t={init:function(){this.toggleSidebarStatus(),CAS.showPopups&&(this.upgradeNoticeHandler(),this.reviewNoticeHandler())},toggleSidebarStatus:function(){$(".sidebar-status").on("change","input.sidebar-status-input",function(t){var a=$(this),e=a.is(":checked");if(a.hasClass("sidebar-status-future")&&!confirm(CAS.enableConfirm))return a.attr("checked",!e),t.preventDefault(),!1;$.post(ajaxurl,{action:"cas_sidebar_status",sidebar_id:a.val(),token:a.attr("data-nonce"),status:e},function(t){t.success?(a.next().attr("title",t.data.title),a.removeClass("sidebar-status-future")):(alert(t.data),a.attr("checked",!e))})})},upgradeNoticeHandler:function(){$(".js-cas-pro-notice.button").attr("disabled",!0),$(".js-cas-pro-notice").on("click",function(t){t.preventDefault(),$(".js-cas-pro-read-more").attr("href",$(this).data("url")),$(".js-cas-pro-popup").trigger("click")})},reviewNoticeHandler:function(){var e=$(".js-cas-notice-review");e.on("click","a, button",function(t){var a=$(this);$.ajax({url:ajaxurl,data:{action:"cas_dismiss_review_notice",dismiss:a.data("cas-rating")?1:0},dataType:"JSON",type:"POST",success:function(t){e.fadeOut(400,function(){e.remove()})},error:function(t,a,e){}})})}};$(document).ready(function(){t.init()})}(jQuery);
assets/js/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
assets/js/suggest-sidebars.min.js CHANGED
@@ -2,6 +2,6 @@
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
- * @copyright 2021 by Joachim Jensen
6
  */
7
  !function($){"use strict";var e={init:function(){this.suggestSidebars(),this.toggleSidebarInputs()},toggleSidebarInputs:function(){$(".js-cas-more").click(function(e){e.preventDefault();var t=$(this),e=$(t.data("toggle")),t=t.children(":first");t.hasClass("dashicons-arrow-down-alt2")?(t.addClass("dashicons-arrow-up-alt2").removeClass("dashicons-arrow-down-alt2"),e.slideDown()):(t.addClass("dashicons-arrow-down-alt2").removeClass("dashicons-arrow-up-alt2"),e.slideUp())})},suggestSidebars:function(){$(".js-cas-sidebars").each(function(){$(this).select2({theme:"wpca",minimumInputLength:0,closeOnSelect:!0,allowClear:!1,width:"100%",escapeMarkup:function(e){return e},createTag:function(e){e=$.trim(e.term);return""===e?null:{id:"_"+e.replace(/,/g,"__"),text:e,new:!0}},templateSelection:function(e){return(e.new?"<b>("+CAS.labelNew+")</b> ":"")+e.text},templateResult:function(e){return(e.new?"<b>"+CAS.createNew+":</b> ":"")+e.text},templateNoMatches:function(e){return CAS.notFound}})})}};$(document).ready(function(){e.init()})}(jQuery);
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
+ * @copyright 2022 by Joachim Jensen
6
  */
7
  !function($){"use strict";var e={init:function(){this.suggestSidebars(),this.toggleSidebarInputs()},toggleSidebarInputs:function(){$(".js-cas-more").click(function(e){e.preventDefault();var t=$(this),e=$(t.data("toggle")),t=t.children(":first");t.hasClass("dashicons-arrow-down-alt2")?(t.addClass("dashicons-arrow-up-alt2").removeClass("dashicons-arrow-down-alt2"),e.slideDown()):(t.addClass("dashicons-arrow-down-alt2").removeClass("dashicons-arrow-up-alt2"),e.slideUp())})},suggestSidebars:function(){$(".js-cas-sidebars").each(function(){$(this).select2({theme:"wpca",minimumInputLength:0,closeOnSelect:!0,allowClear:!1,width:"100%",escapeMarkup:function(e){return e},createTag:function(e){e=$.trim(e.term);return""===e?null:{id:"_"+e.replace(/,/g,"__"),text:e,new:!0}},templateSelection:function(e){return(e.new?"<b>("+CAS.labelNew+")</b> ":"")+e.text},templateResult:function(e){return(e.new?"<b>"+CAS.createNew+":</b> ":"")+e.text},templateNoMatches:function(e){return CAS.notFound}})})}};$(document).ready(function(){e.init()})}(jQuery);
assets/js/widgets.min.js CHANGED
@@ -2,6 +2,6 @@
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
- * @copyright 2021 by Joachim Jensen
6
  */
7
  !function($){"use strict";var e={$sidebarContainer:$(".widget-liquid-right"),$widgetContainer:$("#available-widgets"),init:function(){this.openSidebarByURL(),this.addSidebarToolbar(),this.addWidgetSearch(),this.enhancedWidgetManager()},openSidebarByURL:function(){var e,i;!window.location.hash||(i=(e=this.$sidebarContainer.find(".widgets-holder-wrap")).has(window.location.hash)).length&&i.add(e.first()).find(".handlediv,.sidebar-name-arrow").trigger("click")},enhancedWidgetManager:function(){var i,a;$("body").hasClass("cas-widget-manager")&&(this.$widgetContainer.find(".widget").draggable("option","scroll",!1),i=this,(a=$("#widgets-left .inactive-sidebar")).toggle(this.$widgetContainer.hasClass("closed")),this.$widgetContainer.find(".sidebar-name").click(function(e){a.toggle(i.$widgetContainer.hasClass("closed"))}))},addWidgetSearch:function(){var e=$(".widget",this.$widgetContainer).get().reverse();$(".sidebar-description",this.$widgetContainer).prepend('<input type="search" class="js-cas-widget-filter cas-filter" placeholder="'+CASAdmin.filterWidgets+'...">'),this.searchWidgetListener(e)},searchWidgetListener:function(i){var t,s="";this.$widgetContainer.on("input",".js-cas-widget-filter",function(e){var a=$(this).val();a!=s&&(s=a,t&&clearTimeout(t),t=setTimeout(function(){$(i).each(function(e,i){i=$(i);i.find(".widget-title :nth-child(1)").text().search(new RegExp(a,"i"))<0?i.fadeOut():(i.prependTo(i.parent()),i.fadeIn().css("display",""))})},250))})},addSidebarToolbar:function(){var e='<div class="wp-filter cas-filter-sidebar"><a href="admin.php?page=wpcas-edit" class="button button-primary">'+CASAdmin.addNew+'</a><div class="sidebars-toggle"><a href="#" title="'+CASAdmin.collapse+'" class="js-sidebars-toggle" data-toggle="0"><span class="dashicons dashicons-arrow-up-alt2"></span></a><a href="#" title="'+CASAdmin.expand+'" class="js-sidebars-toggle" data-toggle="1"><span class="dashicons dashicons-arrow-down-alt2"></span></a></div><input type="search" class="js-cas-filter cas-filter" placeholder="'+CASAdmin.filterSidebars+'..."></div>';this.$sidebarContainer.prepend(e),this.searchSidebarListener(),this.addSidebarToggle()},addSidebarToggle:function(){var i=$(document),a=this.$sidebarContainer.find(".widgets-holder-wrap");$("body").on("click",".js-sidebars-toggle",function(e){e.preventDefault();e=!!$(this).data("toggle");a.toggleClass("closed",!e),e&&a.children(".widgets-sortables").sortable("refresh"),i.triggerHandler("wp-pin-menu")})},searchSidebarListener:function(){var i,t=this,s="";this.$sidebarContainer.on("input",".js-cas-filter",function(e){var a=$(this).val();a!=s&&(s=a,i&&clearTimeout(i),i=setTimeout(function(){$(".widgets-holder-wrap",t.$sidebarContainer).each(function(e,i){i=$(i);i.find(".sidebar-name :nth-child(2)").text().search(new RegExp(a,"i"))<0?i.fadeOut():i.fadeIn()})},250))})}};$(document).ready(function(){e.init()})}(jQuery);
2
  * @package Content Aware Sidebars
3
  * @author Joachim Jensen <joachim@dev.institute>
4
  * @license GPLv3
5
+ * @copyright 2022 by Joachim Jensen
6
  */
7
  !function($){"use strict";var e={$sidebarContainer:$(".widget-liquid-right"),$widgetContainer:$("#available-widgets"),init:function(){this.openSidebarByURL(),this.addSidebarToolbar(),this.addWidgetSearch(),this.enhancedWidgetManager()},openSidebarByURL:function(){var e,i;!window.location.hash||(i=(e=this.$sidebarContainer.find(".widgets-holder-wrap")).has(window.location.hash)).length&&i.add(e.first()).find(".handlediv,.sidebar-name-arrow").trigger("click")},enhancedWidgetManager:function(){var i,a;$("body").hasClass("cas-widget-manager")&&(this.$widgetContainer.find(".widget").draggable("option","scroll",!1),i=this,(a=$("#widgets-left .inactive-sidebar")).toggle(this.$widgetContainer.hasClass("closed")),this.$widgetContainer.find(".sidebar-name").click(function(e){a.toggle(i.$widgetContainer.hasClass("closed"))}))},addWidgetSearch:function(){var e=$(".widget",this.$widgetContainer).get().reverse();$(".sidebar-description",this.$widgetContainer).prepend('<input type="search" class="js-cas-widget-filter cas-filter" placeholder="'+CASAdmin.filterWidgets+'...">'),this.searchWidgetListener(e)},searchWidgetListener:function(i){var t,s="";this.$widgetContainer.on("input",".js-cas-widget-filter",function(e){var a=$(this).val();a!=s&&(s=a,t&&clearTimeout(t),t=setTimeout(function(){$(i).each(function(e,i){i=$(i);i.find(".widget-title :nth-child(1)").text().search(new RegExp(a,"i"))<0?i.fadeOut():(i.prependTo(i.parent()),i.fadeIn().css("display",""))})},250))})},addSidebarToolbar:function(){var e='<div class="wp-filter cas-filter-sidebar"><a href="admin.php?page=wpcas-edit" class="button button-primary">'+CASAdmin.addNew+'</a><div class="sidebars-toggle"><a href="#" title="'+CASAdmin.collapse+'" class="js-sidebars-toggle" data-toggle="0"><span class="dashicons dashicons-arrow-up-alt2"></span></a><a href="#" title="'+CASAdmin.expand+'" class="js-sidebars-toggle" data-toggle="1"><span class="dashicons dashicons-arrow-down-alt2"></span></a></div><input type="search" class="js-cas-filter cas-filter" placeholder="'+CASAdmin.filterSidebars+'..."></div>';this.$sidebarContainer.prepend(e),this.searchSidebarListener(),this.addSidebarToggle()},addSidebarToggle:function(){var i=$(document),a=this.$sidebarContainer.find(".widgets-holder-wrap");$("body").on("click",".js-sidebars-toggle",function(e){e.preventDefault();e=!!$(this).data("toggle");a.toggleClass("closed",!e),e&&a.children(".widgets-sortables").sortable("refresh"),i.triggerHandler("wp-pin-menu")})},searchSidebarListener:function(){var i,t=this,s="";this.$sidebarContainer.on("input",".js-cas-filter",function(e){var a=$(this).val();a!=s&&(s=a,i&&clearTimeout(i),i=setTimeout(function(){$(".widgets-holder-wrap",t.$sidebarContainer).each(function(e,i){i=$(i);i.find(".sidebar-name :nth-child(2)").text().search(new RegExp(a,"i"))<0?i.fadeOut():i.fadeIn()})},250))})}};$(document).ready(function(){e.init()})}(jQuery);
cas_uninstall.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
changelog.txt CHANGED
@@ -1,3 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 3.12.2 =
2
 
3
  * [fixed] sidebars inserted with shortcode can now be replaced/merged
1
+ = 3.15.2 =
2
+
3
+ * [new] performance improvements
4
+ * [new] publishpress authors compatibility
5
+ * [new] wordpress 5.7 support
6
+ * [fixed] toolbar menu now supports theme areas registered without titles
7
+ * [fixed] toolbar menu now displays nested custom sidebars properly
8
+ * [updated] ui improvements for screen readers
9
+ * [updated] wp-content-aware-engine library
10
+ * [updated] freemius sdk
11
+
12
+ **Pro Plan:**
13
+
14
+ * [fixed] url condition compatible with wordpress installed in subdirectories
15
+ * [fixed] acf condition supports more field types
16
+
17
+ = 3.15.1 =
18
+
19
+ * [fixed] toolbar menu compatibility with php5.6
20
+
21
+ = 3.15 =
22
+
23
+ * [new] toolbar menu to view conditions, theme areas, and sidebars for a given page
24
+ * [new] better compatibility with retired custom sidebars plugin
25
+ * [updated] ui improvements
26
+ * [updated] wp-content-aware-engine library
27
+
28
+ = 3.14.1 =
29
+
30
+ * [fixed] sidebar quick select now displays all eligible sidebars
31
+ * [updated] reinstate widgets screen if disabled by gutenberg plugin without user consent
32
+
33
+ **Pro Plan:**
34
+
35
+ * [fixed] styles would not always be loaded for container widget
36
+
37
+ = 3.14 =
38
+
39
+ * [new] ability to replace or merge with multiple sidebars
40
+ * [new] wordpress 5.6 support
41
+ * [new] minimum wordpress version 4.9
42
+ * [fixed] some custom sidebar styles would not take effect in wp5.6+
43
+ * [updated] wp-content-aware-engine library
44
+
45
+ **Pro Plan:**
46
+
47
+ * [new] time schedule displayed on overview screen
48
+ * [fixed] conditions would not be duplicated with sidebar
49
+ * [updated] improved time schedule ui
50
+
51
+ = 3.13.1 =
52
+
53
+ * [new] identical taxonomy names are now displayed with their post type
54
+ * [fixed] taxonomy and attachment condition suggestions would not display all results
55
+ * [updated] wp-content-aware-engine library
56
+ * [updated] freemius sdk
57
+
58
+ **Pro Plan:**
59
+
60
+ * [new] support for auto-updates
61
+
62
+ = 3.13 =
63
+
64
+ * [new] exception conditions
65
+ * [new] intelligent search by id in post type condition
66
+ * [new] intelligent search by id, email in author condition
67
+ * [new] performance improvements
68
+ * [new] wordpress 5.5 support
69
+ * [updated] wp-content-aware-engine library
70
+ * [updated] freemius sdk
71
+ * [deprecated] negated conditions
72
+ * [deprecated] simple date archive condition
73
+
74
+ **Pro Plan:**
75
+
76
+ * [new] sticky support for storefront theme
77
+ * [fixed] sticky left sidebars in generatepress
78
+
79
  = 3.12.2 =
80
 
81
  * [fixed] sidebars inserted with shortcode can now be replaced/merged
conditions/placeholder.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
content-aware-sidebars.php CHANGED
@@ -1,81 +1,76 @@
1
- <?php
2
- /**
3
- * @package Content Aware Sidebars
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
- /*
9
- Plugin Name: Content Aware Sidebars
10
- Plugin URI: https://dev.institute/wordpress-sidebars/
11
- Description: Unlimited custom sidebars and widget areas for any post, page, category etc.
12
- Version: 3.16.2
13
- Author: Joachim Jensen - DEV Institute
14
- Author URI: https://dev.institute
15
- Requires at least: 5.0
16
- Requires PHP: 5.6
17
- Text Domain: content-aware-sidebars
18
- Domain Path: /lang/
19
- License: GPLv3
20
-
21
- Content Aware Sidebars Plugin
22
- Copyright (C) 2011-2021 Joachim Jensen - jv@intox.dk
23
-
24
- This program is free software: you can redistribute it and/or modify
25
- it under the terms of the GNU General Public License as published by
26
- the Free Software Foundation, either version 3 of the License, or
27
- (at your option) any later version.
28
-
29
- This program is distributed in the hope that it will be useful,
30
- but WITHOUT ANY WARRANTY; without even the implied warranty of
31
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
- GNU General Public License for more details.
33
-
34
- You should have received a copy of the GNU General Public License
35
- along with this program. If not, see <http://www.gnu.org/licenses/>.
36
-
37
- */
38
-
39
- defined('ABSPATH') || exit;
40
-
41
- if (function_exists('cas_fs')) {
42
- cas_fs()->set_basename(true, __FILE__);
43
- return;
44
- }
45
-
46
- if (!class_exists('CAS_App')) {
47
-
48
- // Load dependencies
49
- $cas_dir_path = plugin_dir_path(__FILE__);
50
-
51
- require($cas_dir_path.'lib/wp-content-aware-engine/bootstrap.php');
52
- require($cas_dir_path.'lib/wp-db-updater/wp-db-updater.php');
53
- require($cas_dir_path.'app.php');
54
- require($cas_dir_path.'lib/wp-pointer-tour/wp-pointer-tour.php');
55
- require($cas_dir_path.'admin/admin.php');
56
- require($cas_dir_path.'admin/admin_bar.php');
57
- require($cas_dir_path.'admin/quick_select.php');
58
- require($cas_dir_path.'admin/sidebar-list-table.php');
59
- require($cas_dir_path.'admin/sidebar-overview.php');
60
- require($cas_dir_path.'admin/sidebar-edit.php');
61
- require($cas_dir_path.'admin/screen_widgets.php');
62
- require($cas_dir_path.'admin/settings.php');
63
- require($cas_dir_path.'sidebar.php');
64
- require($cas_dir_path.'freemius.php');
65
- require($cas_dir_path.'admin/db-updates.php');
66
-
67
- // Launch plugin
68
- CAS_App::instance();
69
-
70
- /**
71
- * Template wrapper to display content aware sidebars
72
- *
73
- * @since 3.0
74
- * @param array|string $args
75
- * @return void
76
- */
77
- function ca_display_sidebar($args = [])
78
- {
79
- CAS_App::instance()->manager()->manual_sidebar($args);
80
- }
81
- }
1
+ <?php
2
+ /**
3
+ * @package Content Aware Sidebars
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
+ *
8
+ * Plugin Name: Content Aware Sidebars
9
+ * Plugin URI: https://dev.institute/wordpress-sidebars/
10
+ * Description: Unlimited custom sidebars and widget areas for any post, page, category etc.
11
+ * Version: 3.17
12
+ * Author: Joachim Jensen - DEV Institute
13
+ * Author URI: https://dev.institute
14
+ * Requires at least: 5.0
15
+ * Requires PHP: 5.6
16
+ * Text Domain: content-aware-sidebars
17
+ * Domain Path: /lang/
18
+ * License: GPLv3
19
+ *
20
+ * This program is free software: you can redistribute it and/or modify
21
+ * it under the terms of the GNU General Public License as published by
22
+ * the Free Software Foundation, either version 3 of the License, or
23
+ * (at your option) any later version.
24
+ *
25
+ * This program is distributed in the hope that it will be useful,
26
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
+ * GNU General Public License for more details.
29
+ *
30
+ * You should have received a copy of the GNU General Public License
31
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
32
+ *
33
+ */
34
+
35
+ defined('ABSPATH') || exit;
36
+
37
+ if (function_exists('cas_fs')) {
38
+ cas_fs()->set_basename(true, __FILE__);
39
+ return;
40
+ }
41
+
42
+ if (!class_exists('CAS_App')) {
43
+ // Load dependencies
44
+ $cas_dir_path = plugin_dir_path(__FILE__);
45
+
46
+ require $cas_dir_path . 'lib/wp-content-aware-engine/bootstrap.php';
47
+ require $cas_dir_path . 'lib/wp-db-updater/wp-db-updater.php';
48
+ require $cas_dir_path . 'app.php';
49
+ require $cas_dir_path . 'lib/wp-pointer-tour/wp-pointer-tour.php';
50
+ require $cas_dir_path . 'admin/admin.php';
51
+ require $cas_dir_path . 'admin/admin_bar.php';
52
+ require $cas_dir_path . 'admin/quick_select.php';
53
+ require $cas_dir_path . 'admin/sidebar-list-table.php';
54
+ require $cas_dir_path . 'admin/sidebar-overview.php';
55
+ require $cas_dir_path . 'admin/sidebar-edit.php';
56
+ require $cas_dir_path . 'admin/screen_widgets.php';
57
+ require $cas_dir_path . 'admin/settings.php';
58
+ require $cas_dir_path . 'sidebar.php';
59
+ require $cas_dir_path . 'freemius.php';
60
+ require $cas_dir_path . 'admin/db-updates.php';
61
+
62
+ // Launch plugin
63
+ CAS_App::instance();
64
+
65
+ /**
66
+ * Template wrapper to display content aware sidebars
67
+ *
68
+ * @since 3.0
69
+ * @param array|string $args
70
+ * @return void
71
+ */
72
+ function ca_display_sidebar($args = [])
73
+ {
74
+ CAS_App::instance()->manager()->manual_sidebar($args);
75
+ }
76
+ }
 
 
 
 
 
freemius.php CHANGED
@@ -4,7 +4,7 @@
4
  * @package Content Aware Sidebars
5
  * @author Joachim Jensen <joachim@dev.institute>
6
  * @license GPLv3
7
- * @copyright 2021 by Joachim Jensen
8
  */
9
  defined( 'ABSPATH' ) || exit;
10
  // Create a helper function for easy SDK access.
4
  * @package Content Aware Sidebars
5
  * @author Joachim Jensen <joachim@dev.institute>
6
  * @license GPLv3
7
+ * @copyright 2022 by Joachim Jensen
8
  */
9
  defined( 'ABSPATH' ) || exit;
10
  // Create a helper function for easy SDK access.
index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
lang/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
lib/wp-content-aware-engine/assets/css/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
- /**/
1
+ <?php
2
+ /**/
lib/wp-content-aware-engine/assets/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
- /**/
1
+ <?php
2
+ /**/
lib/wp-content-aware-engine/assets/js/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
- /**/
1
+ <?php
2
+ /**/
lib/wp-content-aware-engine/bootstrap.php CHANGED
@@ -1,92 +1,90 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- * Version of this WPCA
13
- * @var string
14
- */
15
- $this_wpca_version = '9.5a';
16
-
17
- /**
18
- * Class to make sure the latest
19
- * version of WPCA gets loaded
20
- *
21
- * @since 3.0
22
- */
23
- if (!class_exists('WPCALoader')) {
24
- class WPCALoader
25
- {
26
-
27
- /**
28
- * Absolute paths and versions
29
- * @var array
30
- */
31
- private static $_paths = [];
32
-
33
- public function __construct()
34
- {
35
- }
36
-
37
- /**
38
- * Add path to loader
39
- *
40
- * @since 3.0
41
- * @param string $path
42
- * @param string $version
43
- */
44
- public static function add($path, $version)
45
- {
46
- self::$_paths[$path] = $version;
47
- }
48
-
49
- /**
50
- * Load file for newest version
51
- * and setup engine
52
- *
53
- * @since 3.0
54
- * @return void
55
- */
56
- public static function load()
57
- {
58
-
59
- //legacy version present, cannot continue
60
- if (class_exists('WPCACore')) {
61
- return;
62
- }
63
-
64
- uasort(self::$_paths, 'version_compare');
65
- foreach (array_reverse(self::$_paths, true) as $path => $version) {
66
- $file = $path.'core.php';
67
- if (file_exists($file)) {
68
- include($file);
69
- define('WPCA_VERSION', $version);
70
- WPCACore::init();
71
- do_action('wpca/loaded');
72
- break;
73
- }
74
- }
75
- }
76
-
77
- /**
78
- * Get all paths added to loader
79
- * Sorted if called after plugins_loaded
80
- *
81
- * @since 3.0
82
- * @return array
83
- */
84
- public static function debug()
85
- {
86
- return self::$_paths;
87
- }
88
- }
89
- //Hook as early as possible after plugins are loaded
90
- add_action('plugins_loaded', ['WPCALoader','load'], -999999);
91
- }
92
- WPCALoader::add(plugin_dir_path(__FILE__), $this_wpca_version);
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ * Version of this WPCA
13
+ * @var string
14
+ */
15
+ $this_wpca_version = '9.6a';
16
+
17
+ /**
18
+ * Class to make sure the latest
19
+ * version of WPCA gets loaded
20
+ *
21
+ * @since 3.0
22
+ */
23
+ if (!class_exists('WPCALoader')) {
24
+ class WPCALoader
25
+ {
26
+ /**
27
+ * Absolute paths and versions
28
+ * @var array
29
+ */
30
+ private static $_paths = [];
31
+
32
+ public function __construct()
33
+ {
34
+ }
35
+
36
+ /**
37
+ * Add path to loader
38
+ *
39
+ * @since 3.0
40
+ * @param string $path
41
+ * @param string $version
42
+ */
43
+ public static function add($path, $version)
44
+ {
45
+ self::$_paths[$path] = $version;
46
+ }
47
+
48
+ /**
49
+ * Load file for newest version
50
+ * and setup engine
51
+ *
52
+ * @since 3.0
53
+ * @return void
54
+ */
55
+ public static function load()
56
+ {
57
+ //legacy version present, cannot continue
58
+ if (class_exists('WPCACore')) {
59
+ return;
60
+ }
61
+
62
+ uasort(self::$_paths, 'version_compare');
63
+ foreach (array_reverse(self::$_paths, true) as $path => $version) {
64
+ $file = $path . 'core.php';
65
+ if (file_exists($file)) {
66
+ include $file;
67
+ define('WPCA_VERSION', $version);
68
+ WPCACore::init();
69
+ do_action('wpca/loaded');
70
+ break;
71
+ }
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Get all paths added to loader
77
+ * Sorted if called after plugins_loaded
78
+ *
79
+ * @since 3.0
80
+ * @return array
81
+ */
82
+ public static function debug()
83
+ {
84
+ return self::$_paths;
85
+ }
86
+ }
87
+ //Hook as early as possible after plugins are loaded
88
+ add_action('plugins_loaded', ['WPCALoader','load'], -999999);
89
+ }
90
+ WPCALoader::add(plugin_dir_path(__FILE__), $this_wpca_version);
 
 
lib/wp-content-aware-engine/core.php CHANGED
@@ -1,1241 +1,1241 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- if (!class_exists('WPCACore')) {
12
- $domain = explode('/', plugin_basename(__FILE__));
13
- define('WPCA_DOMAIN', $domain[0]);
14
- define('WPCA_PATH', plugin_dir_path(__FILE__));
15
-
16
- /**
17
- * Core for WordPress Content Aware Engine
18
- */
19
- final class WPCACore
20
- {
21
-
22
- /**
23
- * Using class prefix instead of namespace
24
- * for PHP5.2 compatibility
25
- */
26
- const CLASS_PREFIX = 'WPCA';
27
-
28
- /**
29
- * Prefix for data (keys) stored in database
30
- */
31
- const PREFIX = '_ca_';
32
-
33
- /**
34
- * Post Type for condition groups
35
- */
36
- const TYPE_CONDITION_GROUP = 'condition_group';
37
-
38
- /**
39
- * Post Statuses for condition groups
40
- */
41
- /**
42
- * @deprecated
43
- */
44
- const STATUS_NEGATED = 'negated';
45
- /**
46
- * @deprecated
47
- */
48
- const STATUS_PUBLISHED = 'publish';
49
- const STATUS_OR = 'wpca_or';
50
- const STATUS_EXCEPT = 'wpca_except';
51
-
52
- /**
53
- * Exposures for condition groups
54
- */
55
- const EXP_SINGULAR = 0;
56
- const EXP_SINGULAR_ARCHIVE = 1;
57
- const EXP_ARCHIVE = 2;
58
-
59
- /**
60
- * @deprecated 7.0
61
- */
62
- const CAPABILITY = 'edit_theme_options';
63
-
64
- /**
65
- * Name for generated nonces
66
- */
67
- const NONCE = '_ca_nonce';
68
-
69
- const OPTION_CONDITION_TYPE_CACHE = '_ca_condition_type_cache';
70
- const OPTION_POST_TYPE_OPTIONS = '_ca_post_type_options';
71
-
72
- /**
73
- * Post Types that use the engine
74
- * @var WPCAPostTypeManager
75
- */
76
- private static $type_manager;
77
-
78
- /**
79
- * Conditions retrieved from database
80
- * @var array
81
- */
82
- private static $condition_cache = [];
83
-
84
- /**
85
- * Objects retrieved from database
86
- * @var array
87
- */
88
- private static $post_cache = [];
89
-
90
- private static $wp_query_original = [];
91
-
92
- private static $filtered_modules = [];
93
-
94
- /**
95
- * Constructor
96
- */
97
- public static function init()
98
- {
99
- spl_autoload_register([__CLASS__,'_autoload_class_files']);
100
-
101
- if (is_admin()) {
102
- add_action(
103
- 'admin_enqueue_scripts',
104
- [__CLASS__,'add_group_script_styles'],
105
- 9
106
- );
107
- add_action(
108
- 'delete_post',
109
- [__CLASS__,'sync_group_deletion']
110
- );
111
- add_action(
112
- 'trashed_post',
113
- [__CLASS__,'sync_group_trashed']
114
- );
115
- add_action(
116
- 'untrashed_post',
117
- [__CLASS__,'sync_group_untrashed']
118
- );
119
- add_action(
120
- 'wpca/modules/save-data',
121
- [__CLASS__,'save_condition_options'],
122
- 10,
123
- 3
124
- );
125
-
126
- add_action(
127
- 'wp_ajax_wpca/add-rule',
128
- [__CLASS__,'ajax_update_group']
129
- );
130
- }
131
-
132
- add_action(
133
- 'init',
134
- [__CLASS__,'add_group_post_type'],
135
- 99
136
- );
137
-
138
- add_action(
139
- 'init',
140
- [__CLASS__,'schedule_cache_condition_types'],
141
- 99
142
- );
143
-
144
- add_action(
145
- 'wpca/cache_condition_types',
146
- [__CLASS__,'cache_condition_types'],
147
- 999
148
- );
149
- }
150
-
151
- /**
152
- * Get post type manager
153
- *
154
- * @deprecated 4.0
155
- * @since 1.0
156
- * @return WPCAPostTypeManager
157
- */
158
- public static function post_types()
159
- {
160
- return self::types();
161
- }
162
-
163
- /**
164
- * Get type manager
165
- *
166
- * @since 4.0
167
- * @return WPCAPostTypeManager
168
- */
169
- public static function types()
170
- {
171
- if (!isset(self::$type_manager)) {
172
- self::$type_manager = new WPCATypeManager();
173
- }
174
- return self::$type_manager;
175
- }
176
-
177
- /**
178
- * @since 8.0
179
- *
180
- * @return void
181
- */
182
- public static function schedule_cache_condition_types()
183
- {
184
- if (wp_next_scheduled('wpca/cache_condition_types') !== false) {
185
- return;
186
- }
187
-
188
- wp_schedule_event(get_gmt_from_date('today 02:00:00', 'U'), 'daily', 'wpca/cache_condition_types');
189
- }
190
-
191
- /**
192
- * Cache condition types currently in use
193
- *
194
- * @since 8.0
195
- *
196
- * @return void
197
- */
198
- public static function cache_condition_types()
199
- {
200
- $all_modules = [];
201
- $modules_by_type = [];
202
- $cache = [];
203
-
204
- $types = self::types();
205
- foreach ($types as $type => $modules) {
206
- $modules_by_type[$type] = [];
207
- $cache[$type] = [];
208
- foreach ($modules as $module) {
209
- $modules_by_type[$type][$module->get_data_key()] = $module->get_id();
210
- $all_modules[$module->get_data_key()] = $module->get_data_key();
211
- }
212
- }
213
-
214
- if (!$all_modules) {
215
- update_option(self::OPTION_CONDITION_TYPE_CACHE, []);
216
- return;
217
- }
218
-
219
- global $wpdb;
220
-
221
- $query = '
222
- SELECT p.post_type, m.meta_key
223
- FROM '.$wpdb->posts.' p
224
- INNER JOIN '.$wpdb->posts.' c ON c.post_parent = p.ID
225
- INNER JOIN '.$wpdb->postmeta.' m ON m.post_id = c.ID
226
- WHERE p.post_type IN ('.self::sql_prepare_in(array_keys($modules_by_type)).')
227
- AND m.meta_key IN ('.self::sql_prepare_in($all_modules).')
228
- GROUP BY p.post_type, m.meta_key
229
- ';
230
-
231
- $results = (array) $wpdb->get_results($query);
232
-
233
- foreach ($results as $result) {
234
- if (isset($modules_by_type[$result->post_type][$result->meta_key])) {
235
- $cache[$result->post_type][] = $modules_by_type[$result->post_type][$result->meta_key];
236
- }
237
- }
238
-
239
- update_option(self::OPTION_CONDITION_TYPE_CACHE, $cache);
240
- }
241
-
242
- /**
243
- * Register group post type
244
- *
245
- * @since 1.0
246
- * @return void
247
- */
248
- public static function add_group_post_type()
249
- {
250
- //This is just a safety placeholder,
251
- //authorization will be done with parent object's cap
252
- $capability = 'edit_theme_options';
253
- $capabilities = [
254
- 'edit_post' => $capability,
255
- 'read_post' => $capability,
256
- 'delete_post' => $capability,
257
- 'edit_posts' => $capability,
258
- 'delete_posts' => $capability,
259
- 'edit_others_posts' => $capability,
260
- 'publish_posts' => $capability,
261
- 'read_private_posts' => $capability
262
- ];
263
-
264
- register_post_type(self::TYPE_CONDITION_GROUP, [
265
- 'labels' => [
266
- 'name' => __('Condition Groups', WPCA_DOMAIN),
267
- 'singular_name' => __('Condition Group', WPCA_DOMAIN),
268
- ],
269
- 'capabilities' => $capabilities,
270
- 'public' => false,
271
- 'hierarchical' => false,
272
- 'exclude_from_search' => true,
273
- 'publicly_queryable' => false,
274
- 'show_ui' => false,
275
- 'show_in_menu' => false,
276
- 'show_in_nav_menus' => false,
277
- 'show_in_admin_bar' => false,
278
- 'show_in_rest' => false,
279
- 'has_archive' => false,
280
- 'rewrite' => false,
281
- 'query_var' => false,
282
- 'supports' => ['title'],
283
- 'can_export' => false,
284
- 'delete_with_user' => false
285
- ]);
286
-
287
- register_post_status(self::STATUS_NEGATED, [
288
- 'label' => _x('Negated', 'condition status', WPCA_DOMAIN),
289
- 'public' => false,
290
- 'exclude_from_search' => true,
291
- 'show_in_admin_all_list' => false,
292
- 'show_in_admin_status_list' => false,
293
- ]);
294
- register_post_status(self::STATUS_EXCEPT, [
295
- 'label' => _x('Exception', 'condition status', WPCA_DOMAIN),
296
- 'public' => false,
297
- 'exclude_from_search' => true,
298
- 'show_in_admin_all_list' => false,
299
- 'show_in_admin_status_list' => false,
300
- ]);
301
- register_post_status(self::STATUS_OR, [
302
- 'label' => _x('Or', 'condition status', WPCA_DOMAIN),
303
- 'public' => false,
304
- 'exclude_from_search' => true,
305
- 'show_in_admin_all_list' => false,
306
- 'show_in_admin_status_list' => false,
307
- ]);
308
- }
309
-
310
- /**
311
- * Get group IDs by their parent ID
312
- *
313
- * @since 1.0
314
- * @param int $parent_id
315
- * @return array
316
- */
317
- private static function get_group_ids_by_parent($parent_id)
318
- {
319
- if (!self::types()->has(get_post_type($parent_id))) {
320
- return [];
321
- }
322
-
323
- global $wpdb;
324
- return (array)$wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = '%d'", $parent_id));
325
- }
326
-
327
- /**
328
- * Delete groups from database when their parent is deleted
329
- *
330
- * @since 1.0
331
- * @param int $post_id
332
- * @return void
333
- */
334
- public static function sync_group_deletion($post_id)
335
- {
336
- $groups = self::get_group_ids_by_parent($post_id);
337
- if ($groups) {
338
- foreach ($groups as $group_id) {
339
- //Takes care of metadata and terms too
340
- wp_delete_post($group_id, true);
341
- }
342
- }
343
- }
344
-
345
- /**
346
- * Trash groups when their parent is trashed
347
- *
348
- * @since 1.0
349
- * @param int $post_id
350
- * @return void
351
- */
352
- public static function sync_group_trashed($post_id)
353
- {
354
- $groups = self::get_group_ids_by_parent($post_id);
355
- if ($groups) {
356
- foreach ($groups as $group_id) {
357
- wp_trash_post($group_id);
358
- }
359
- }
360
- }
361
-
362
- /**
363
- * Untrash groups when their parent is untrashed
364
- *
365
- * @since 1.0
366
- * @param int $post_id
367
- * @return void
368
- */
369
- public static function sync_group_untrashed($post_id)
370
- {
371
- $groups = self::get_group_ids_by_parent($post_id);
372
- if ($groups) {
373
- foreach ($groups as $group_id) {
374
- wp_untrash_post($group_id);
375
- }
376
- }
377
- }
378
-
379
- /**
380
- * @param string $post_type
381
- * @return array
382
- */
383
- public static function get_conditional_modules($post_type)
384
- {
385
- if (!isset(self::$filtered_modules[$post_type])) {
386
- return [];
387
- }
388
- return self::$filtered_modules[$post_type];
389
- }
390
-
391
- /**
392
- * Get filtered condition groups
393
- *
394
- * @since 2.0
395
- * @return array
396
- */
397
- public static function get_conditions($post_type)
398
- {
399
- global $wpdb, $wp_query, $post;
400
-
401
- if (!self::types()->has($post_type) || (!$wp_query->query && !$post) || is_admin()) {
402
- return [];
403
- }
404
-
405
- // Return cache if present
406
- if (isset(self::$condition_cache[$post_type])) {
407
- return self::$condition_cache[$post_type];
408
- }
409
-
410
- $where = [];
411
- $join = [];
412
-
413
- $cache = [
414
- $post_type
415
- ];
416
-
417
- $modules = self::types()->get($post_type)->get_all();
418
- $modules = self::filter_condition_type_cache($post_type, $modules);
419
-
420
- //avoid combining as long as negated conditions are being deprecated
421
- // foreach (self::types() as $other_type => $other_modules) {
422
- // if ($other_type == $post_type) {
423
- // continue;
424
- // }
425
- // if (self::filter_condition_type_cache($other_type, $other_modules->get_all()) === $modules) {
426
- // $cache[] = $other_type;
427
- // }
428
- // }
429
-
430
- self::fix_wp_query();
431
-
432
- $in_context_by_module_id = [];
433
- foreach ($modules as $module) {
434
- $id = $module->get_id();
435
- $in_context = apply_filters("wpca/module/$id/in-context", $module->in_context());
436
- $in_context_by_module_id[$id] = $in_context;
437
-
438
- if(!$in_context) {
439
- continue;
440
- }
441
-
442
- $data = $module->get_context_data();
443
-
444
- if(empty($data)) {
445
- $in_context_by_module_id[$id] = false;
446
- continue;
447
- }
448
-
449
- if (is_array($data)) {
450
- $name = $module->get_query_name();
451
- $data = "($name.meta_value IS NULL OR $name.meta_value IN (".self::sql_prepare_in($data).'))';
452
- }
453
- $join[$id] = $module->db_join();
454
- $where[$id] = apply_filters("wpca/module/$id/db-where", $data);
455
- self::$filtered_modules[$post_type][] = $module;
456
- }
457
-
458
- $use_negated_conditions = self::get_option($post_type, 'legacy.negated_conditions', false);
459
-
460
- // Check if there are any conditions for current content
461
- $groups_in_context = [];
462
- if (!empty($where)) {
463
- $post_status = [
464
- self::STATUS_PUBLISHED,
465
- self::STATUS_OR,
466
- self::STATUS_EXCEPT
467
- ];
468
-
469
- if ($use_negated_conditions) {
470
- $post_status[] = self::STATUS_NEGATED;
471
- }
472
-
473
- $chunk_size = count($join);
474
- if (defined('WPCA_SQL_JOIN_SIZE') && is_integer(WPCA_SQL_JOIN_SIZE) && WPCA_SQL_JOIN_SIZE > 0) {
475
- $chunk_size = WPCA_SQL_JOIN_SIZE;
476
- } elseif (defined('WPCA_SQL_COMPATIBILITY_MODE') && WPCA_SQL_COMPATIBILITY_MODE === true) {
477
- //Syntax changed in MySQL 5.5 and MariaDB 10.0 (reports as version 5.5)
478
- $wpdb->query('SET'.(version_compare($wpdb->db_version(), '5.5', '>=') ? ' SESSION' : ' OPTION').' SQL_BIG_SELECTS = 1');
479
- }
480
-
481
- $joins = array_chunk($join, $chunk_size);
482
- $joins_max = count($joins) - 1;
483
- $wheres = array_chunk($where, $chunk_size);
484
- $group_ids = [];
485
- $groups_in_context = [];
486
-
487
- $where2 = [];
488
- $where2[] = "p.post_type = '".self::TYPE_CONDITION_GROUP."'";
489
- $where2[] = "p.post_status IN ('".implode("','", $post_status)."')";
490
- $where2[] = 'p.menu_order '.(is_archive() || is_home() ? '>=' : '<=').' 1';
491
-
492
- foreach ($joins as $i => $join) {
493
- if ($i == $joins_max) {
494
- $groups_in_context = $wpdb->get_results(
495
- 'SELECT p.ID, p.post_parent, p.post_status '.
496
- "FROM $wpdb->posts p ".
497
- implode(' ', $join).'
498
- WHERE
499
- '.implode(' AND ', $wheres[$i]).'
500
- AND '.implode(' AND ', $where2).
501
- (!empty($group_ids) ? ' AND p.id IN ('.implode(',', $group_ids).')' : ''),
502
- OBJECT_K
503
- );
504
- break;
505
- }
506
-
507
- $group_ids = array_merge($group_ids, $wpdb->get_col(
508
- 'SELECT p.ID '.
509
- "FROM $wpdb->posts p ".
510
- implode(' ', $join).'
511
- WHERE
512
- '.implode(' AND ', $wheres[$i]).'
513
- AND '.implode(' AND ', $where2)
514
- ));
515
- }
516
- }
517
-
518
- $groups_negated = [];
519
- if ($use_negated_conditions) {
520
- $groups_negated = $wpdb->get_results($wpdb->prepare(
521
- 'SELECT p.ID, p.post_parent '.
522
- "FROM $wpdb->posts p ".
523
- "WHERE p.post_type = '%s' ".
524
- "AND p.post_status = '%s' ",
525
- self::TYPE_CONDITION_GROUP,
526
- self::STATUS_NEGATED
527
- ), OBJECT_K);
528
- }
529
-
530
- if (!empty($groups_in_context) || !empty($groups_negated)) {
531
- //Force update of meta cache to prevent lazy loading
532
- update_meta_cache('post', array_keys($groups_in_context + $groups_negated));
533
- }
534
-
535
- //Exclude types that have unrelated content in same group
536
- foreach ($modules as $module) {
537
- $groups_in_context = $module->filter_excluded_context(
538
- $groups_in_context,
539
- $in_context_by_module_id[$module->get_id()]
540
- );
541
- }
542
-
543
- //exclude exceptions
544
- $excepted = [];
545
- foreach ($groups_in_context as $group_id => $group) {
546
- if ($group->post_status == self::STATUS_EXCEPT) {
547
- $excepted[$group->post_parent] = 1;
548
- }
549
- }
550
-
551
- //condition group => type
552
- $valid = [];
553
- foreach ($groups_in_context as $group) {
554
- $valid[$group->ID] = $group->post_parent;
555
- }
556
-
557
- foreach ($valid as $group_id => $parent_id) {
558
- if (isset($excepted[$parent_id])) {
559
- unset($valid[$group_id]);
560
- }
561
- }
562
-
563
- if ($use_negated_conditions) {
564
- //Filter negated groups
565
- //type => group
566
- $handled_already = array_flip($valid);
567
- foreach ($groups_negated as $group) {
568
- if (isset($valid[$group->ID])) {
569
- unset($valid[$group->ID]);
570
- } else {
571
- $valid[$group->ID] = $group->post_parent;
572
- }
573
- if (isset($handled_already[$group->post_parent])) {
574
- unset($valid[$group->ID]);
575
- }
576
- $handled_already[$group->post_parent] = 1;
577
- }
578
- }
579
-
580
- self::restore_wp_query();
581
-
582
- foreach ($cache as $cache_type) {
583
- self::$condition_cache[$cache_type] = $valid;
584
- }
585
-
586
- return self::$condition_cache[$post_type];
587
- }
588
-
589
- /**
590
- * Get filtered posts from a post type
591
- *
592
- * @since 1.0
593
- * @return array
594
- */
595
- public static function get_posts($post_type)
596
- {
597
- if (isset(self::$post_cache[$post_type])) {
598
- return self::$post_cache[$post_type];
599
- }
600
-
601
- $valid = self::get_conditions($post_type);
602
-
603
- //if cache hasn't been set, method was called too early
604
- if (!isset(self::$condition_cache[$post_type])) {
605
- return false;
606
- }
607
-
608
- self::$post_cache[$post_type] = [];
609
-
610
- $results = [];
611
-
612
- if (!empty($valid)) {
613
- $data = new WP_Query([
614
- 'post__in' => array_values($valid),
615
- 'post_type' => $post_type,
616
- 'post_status' => 'publish',
617
- 'posts_per_page' => -1,
618
- 'ignore_sticky_posts' => true,
619
- 'update_post_term_cache' => false,
620
- 'update_post_meta_cache' => true,
621
- 'suppress_filters' => true,
622
- 'no_found_rows' => true,
623
- 'orderby' => 'none'
624
- ]);
625
-
626
- $results = array_merge($results, $data->posts);
627
- }
628
-
629
- //legacy sorting
630
- uasort($results, function (WP_Post $post_a, WP_Post $post_b) {
631
- //asc
632
- if ($post_a->menu_order != $post_b->menu_order) {
633
- return $post_a->menu_order < $post_b->menu_order ? -1 : 1;
634
- }
635
-
636
- $post_a_handle = get_post_meta($post_a->ID, '_ca_handle', true);
637
- $post_b_handle = get_post_meta($post_b->ID, '_ca_handle', true);
638
-
639
- //desc
640
- if ($post_a_handle != $post_b_handle) {
641
- return $post_a_handle > $post_b_handle ? -1 : 1;
642
- }
643
-
644
- //desc
645
- if ($post_a->post_date != $post_b->post_date) {
646
- return $post_a->post_date > $post_b->post_date ? -1 : 1;
647
- }
648
-
649
- return 0;
650
- });
651
-
652
- $results = array_reduce($results, function ($carry, $post) {
653
- $carry[$post->ID] = (object)[
654
- 'ID' => $post->ID,
655
- 'post_type' => $post->post_type,
656
- 'handle' => get_post_meta($post->ID, '_ca_handle', true),
657
- 'menu_order' => $post->menu_order,
658
- 'post_date' => $post->post_date
659
- ];
660
- return $carry;
661
- }, []);
662
-
663
- self::$post_cache[$post_type] = apply_filters("wpca/posts/{$post_type}", $results);
664
-
665
- return self::$post_cache[$post_type];
666
- }
667
-
668
- public static function render_group_meta_box($post, $screen, $context = 'normal', $priority = 'default')
669
- {
670
- if (!($post instanceof WP_Post) || !self::types()->has($post->post_type)) {
671
- return;
672
- }
673
-
674
- $post_type_obj = get_post_type_object($post->post_type);
675
-
676
- if (!current_user_can($post_type_obj->cap->edit_post, $post->ID)) {
677
- return;
678
- }
679
-
680
- $template = WPCAView::make('condition_options', [
681
- 'post_type' => $post->post_type
682
- ]);
683
- add_action('wpca/group/settings', [$template,'render'], -1, 2);
684
-
685
- $template = WPCAView::make('group_template', [
686
- 'post_type' => $post->post_type
687
- ]);
688
- add_action('admin_footer', [$template,'render']);
689
-
690
- $template = WPCAView::make('condition_template');
691
- add_action('admin_footer', [$template,'render']);
692
-
693
- $view = WPCAView::make('meta_box', [
694
- 'post_type' => $post->post_type,
695
- 'nonce' => wp_nonce_field(self::PREFIX.$post->ID, self::NONCE, true, false),
696
- ]);
697
-
698
- $title = isset($post_type_obj->labels->ca_title) ? $post_type_obj->labels->ca_title : __('Conditional Logic', WPCA_DOMAIN);
699
-
700
- add_meta_box(
701
- 'cas-rules',
702
- $title,
703
- [$view,'render'],
704
- $screen,
705
- $context,
706
- $priority
707
- );
708
- }
709
-
710
- /**
711
- * Insert new condition group for a post type
712
- * Uses current post per default
713
- *
714
- * @since 1.0
715
- * @param WP_Post|int $post
716
- * @return int
717
- */
718
- public static function add_condition_group($post_id = null)
719
- {
720
- $post = get_post($post_id);
721
-
722
- //Make sure to go from auto-draft to draft
723
- if ($post->post_status == 'auto-draft') {
724
- wp_update_post([
725
- 'ID' => $post->ID,
726
- 'post_title' => '',
727
- 'post_status' => 'draft'
728
- ]);
729
- }
730
-
731
- return wp_insert_post([
732
- 'post_status' => self::STATUS_OR,
733
- 'menu_order' => self::EXP_SINGULAR_ARCHIVE,
734
- 'post_type' => self::TYPE_CONDITION_GROUP,
735
- 'post_author' => $post->post_author,
736
- 'post_parent' => $post->ID,
737
- ]);
738
- }
739
-
740
- /**
741
- * Get condition groups for a post type
742
- * Uses current post per default
743
- *
744
- * @since 1.0
745
- * @param WP_Post|int $post_id
746
- * @return array
747
- */
748
- private static function get_condition_groups($post_id = null)
749
- {
750
- $post = get_post($post_id);
751
- $groups = [];
752
-
753
- if ($post) {
754
- $groups = get_posts([
755
- 'posts_per_page' => -1,
756
- 'post_type' => self::TYPE_CONDITION_GROUP,
757
- 'post_parent' => $post->ID,
758
- 'post_status' => [self::STATUS_PUBLISHED,self::STATUS_NEGATED,self::STATUS_EXCEPT, self::STATUS_OR],
759
- 'order' => 'ASC',
760
- 'orderby' => 'post_status'
761
- ]);
762
- }
763
- return $groups;
764
- }
765
-
766
- /**
767
- * AJAX callback to update a condition group
768
- *
769
- * @since 1.0
770
- * @return void
771
- */
772
- public static function ajax_update_group()
773
- {
774
- if (!isset($_POST['current_id']) ||
775
- !check_ajax_referer(self::PREFIX.$_POST['current_id'], 'token', false)) {
776
- wp_send_json_error(__('Unauthorized request', WPCA_DOMAIN), 403);
777
- }
778
-
779
- $parent_id = (int)$_POST['current_id'];
780
- $parent_type = get_post_type_object($_POST['post_type']);
781
-
782
- if (! current_user_can($parent_type->cap->edit_post, $parent_id)) {
783
- wp_send_json_error(__('Unauthorized request', WPCA_DOMAIN), 403);
784
- }
785
-
786
- $response = [
787
- 'message' => __('Conditions updated', WPCA_DOMAIN)
788
- ];
789
-
790
- //Make sure some rules are sent
791
- if (!isset($_POST['conditions'])) {
792
- //Otherwise we delete group
793
- if ($_POST['id'] && wp_delete_post(intval($_POST['id']), true) === false) {
794
- wp_send_json_error(__('Could not delete conditions', WPCA_DOMAIN), 500);
795
- }
796
-
797
- $response['removed'] = true;
798
- wp_send_json($response);
799
- }
800
-
801
- //If ID was not sent at this point, it is a new group
802
- if (!$_POST['id']) {
803
- $post_id = self::add_condition_group($parent_id);
804
- $response['new_post_id'] = $post_id;
805
- } else {
806
- $post_id = (int)$_POST['id'];
807
- }
808
-
809
- wp_update_post([
810
- 'ID' => $post_id,
811
- 'post_status' => self::sanitize_status($_POST['status']),
812
- 'menu_order' => (int)$_POST['exposure']
813
- ]);
814
-
815
- //Prune condition type cache, will rebuild within 24h
816
- update_option(self::OPTION_CONDITION_TYPE_CACHE, []);
817
-
818
- foreach (self::types()->get($parent_type->name)->get_all() as $module) {
819
- //send $_POST here
820
- $module->save_data($post_id);
821
- }
822
-
823
- do_action('wpca/modules/save-data', $post_id, $parent_type->name);
824
-
825
- wp_send_json($response);
826
- }
827
-
828
- /**
829
- * @param string $status
830
- *
831
- * @return string
832
- */
833
- private static function sanitize_status($status)
834
- {
835
- switch ($status) {
836
- case self::STATUS_NEGATED:
837
- return self::STATUS_NEGATED;
838
- case self::STATUS_EXCEPT:
839
- return self::STATUS_EXCEPT;
840
- case self::STATUS_OR:
841
- case self::STATUS_PUBLISHED:
842
- default:
843
- return self::STATUS_OR;
844
- }
845
- }
846
-
847
- /**
848
- * Save registered meta for condition group
849
- *
850
- * @since 3.2
851
- * @param int $group_id
852
- * @return void
853
- */
854
- public static function save_condition_options($group_id, $post_type)
855
- {
856
- $meta_keys = self::get_condition_meta_keys($post_type);
857
- foreach ($meta_keys as $key => $default_value) {
858
- $value = isset($_POST[$key]) ? $_POST[$key] : false;
859
- if ($value) {
860
- update_post_meta($group_id, $key, $value);
861
- } elseif (get_post_meta($group_id, $key, true)) {
862
- delete_post_meta($group_id, $key);
863
- }
864
- }
865
- }
866
-
867
- public static function add_group_script_styles($hook)
868
- {
869
- $current_screen = get_current_screen();
870
-
871
- wp_register_style(
872
- self::PREFIX.'condition-groups',
873
- plugins_url('/assets/css/condition_groups.css', __FILE__),
874
- [],
875
- WPCA_VERSION
876
- );
877
-
878
- if (self::types()->has($current_screen->post_type) && $current_screen->base == 'post') {
879
- self::enqueue_scripts_styles($current_screen->post_type);
880
- }
881
- }
882
-
883
- /**
884
- * Get condition option defaults
885
- *
886
- * @since 3.2
887
- * @param string $post_type
888
- * @return array
889
- */
890
- public static function get_condition_meta_keys($post_type)
891
- {
892
- $group_meta = [
893
- '_ca_autoselect' => 0
894
- ];
895
- return apply_filters('wpca/condition/meta', $group_meta, $post_type);
896
- }
897
-
898
- /**
899
- * Register and enqueue scripts and styles
900
- * for post edit screen
901
- *
902
- * @since 1.0
903
- * @param string $hook
904
- * @return void
905
- */
906
- public static function enqueue_scripts_styles($post_type = '')
907
- {
908
- $post_type = empty($post_type) ? get_post_type() : $post_type;
909
-
910
- $group_meta = self::get_condition_meta_keys($post_type);
911
-
912
- $groups = self::get_condition_groups();
913
- $data = [];
914
- $i = 0;
915
- foreach ($groups as $group) {
916
- $data[$i] = [
917
- 'id' => $group->ID,
918
- 'status' => $group->post_status,
919
- 'exposure' => $group->menu_order,
920
- 'conditions' => []
921
- ];
922
-
923
- foreach (self::types()->get($post_type)->get_all() as $module) {
924
- $data[$i]['conditions'] = $module->get_group_data($data[$i]['conditions'], $group->ID);
925
- }
926
-
927
- foreach ($group_meta as $meta_key => $default_value) {
928
- $value = get_post_meta($group->ID, $meta_key, true);
929
- if ($value === false) {
930
- $value = $default_value;
931
- }
932
- $data[$i][$meta_key] = $value;
933
- }
934
- $i++;
935
- }
936
-
937
- $conditions = [
938
- 'general' => [
939
- 'text' => __('General'),
940
- 'children' => []
941
- ],
942
- 'post_type' => [
943
- 'text' => __('Post Types'),
944
- 'children' => []
945
- ],
946
- 'taxonomy' => [
947
- 'text' => __('Taxonomies'),
948
- 'children' => []
949
- ],
950
- 'plugins' => [
951
- 'text' => __('Plugins'),
952
- 'children' => []
953
- ]
954
- ];
955
-
956
- foreach (self::types()->get($post_type)->get_all() as $module) {
957
- $category = $module->get_category();
958
- if (!isset($conditions[$category])) {
959
- $category = 'general';
960
- }
961
-
962
- //array_values used for backwards compatibility
963
- $conditions[$category]['children'] = array_values($module->list_module($conditions[$category]['children']));
964
- }
965
-
966
- foreach ($conditions as $key => $condition) {
967
- if (empty($condition['children'])) {
968
- unset($conditions[$key]);
969
- }
970
- }
971
-
972
- //Make sure to use packaged version
973
- if (wp_script_is('select2', 'registered')) {
974
- wp_deregister_script('select2');
975
- wp_deregister_style('select2');
976
- }
977
-
978
- $plugins_url = plugins_url('', __FILE__);
979
-
980
- //Add to head to take priority
981
- //if being added under other name
982
- wp_register_script(
983
- 'select2',
984
- $plugins_url . '/assets/js/select2.min.js',
985
- ['jquery'],
986
- '4.0.3',
987
- false
988
- );
989
-
990
- wp_register_script(
991
- 'backbone.trackit',
992
- $plugins_url . '/assets/js/backbone.trackit.min.js',
993
- ['backbone'],
994
- '0.1.0',
995
- true
996
- );
997
-
998
- wp_register_script(
999
- 'backbone.epoxy',
1000
- $plugins_url . '/assets/js/backbone.epoxy.min.js',
1001
- ['backbone'],
1002
- '1.3.3',
1003
- true
1004
- );
1005
-
1006
- wp_register_script(
1007
- self::PREFIX.'condition-groups',
1008
- $plugins_url . '/assets/js/condition_groups.min.js',
1009
- ['jquery','select2','backbone.trackit','backbone.epoxy'],
1010
- WPCA_VERSION,
1011
- true
1012
- );
1013
-
1014
- wp_enqueue_script(self::PREFIX.'condition-groups');
1015
- wp_localize_script(self::PREFIX.'condition-groups', 'WPCA', [
1016
- 'searching' => __('Searching', WPCA_DOMAIN),
1017
- 'noResults' => __('No results found.', WPCA_DOMAIN),
1018
- 'loadingMore' => __('Loading more results', WPCA_DOMAIN),
1019
- 'unsaved' => __('Conditions have unsaved changes. Do you want to continue and discard these changes?', WPCA_DOMAIN),
1020
- 'newGroup' => __('New condition group', WPCA_DOMAIN),
1021
- 'newCondition' => __('Meet ALL of these conditions', WPCA_DOMAIN),
1022
- 'conditions' => array_values($conditions),
1023
- 'groups' => $data,
1024
- 'meta_default' => $group_meta,
1025
- 'post_type' => $post_type,
1026
- 'text_direction' => is_rtl() ? 'rtl' : 'ltr',
1027
- 'condition_not' => __('Not', WPCA_DOMAIN),
1028
- 'condition_or' => __('Or', WPCA_DOMAIN),
1029
- 'condition_except' => __('Except', WPCA_DOMAIN)
1030
- ]);
1031
- wp_enqueue_style(self::PREFIX.'condition-groups');
1032
-
1033
- //@todo remove when ultimate member includes fix
1034
- wp_dequeue_style('um_styles');
1035
-
1036
- //@todo remove when events calendar pro plugin includes fix
1037
- wp_dequeue_script('tribe-select2');
1038
- }
1039
-
1040
- /**
1041
- * Modify wp_query for plugin compatibility
1042
- *
1043
- * @since 5.0
1044
- * @return void
1045
- */
1046
- private static function fix_wp_query()
1047
- {
1048
- $query = [];
1049
-
1050
- //When themes don't declare WooCommerce support,
1051
- //conditionals are not working properly for Shop
1052
- if (defined('WOOCOMMERCE_VERSION') && function_exists('is_shop') && is_shop() && !is_post_type_archive('product')) {
1053
- $query = [
1054
- 'is_archive' => true,
1055
- 'is_post_type_archive' => true,
1056
- 'is_page' => false,
1057
- 'is_singular' => false,
1058
- 'query_vars' => [
1059
- 'post_type' => 'product'
1060
- ]
1061
- ];
1062
- }
1063
-
1064
- self::set_wp_query($query);
1065
- }
1066
-
1067
- /**
1068
- * Restore original wp_query
1069
- *
1070
- * @since 5.0
1071
- * @return void
1072
- */
1073
- private static function restore_wp_query()
1074
- {
1075
- self::set_wp_query(self::$wp_query_original);
1076
- self::$wp_query_original = [];
1077
- }
1078
-
1079
- /**
1080
- * Set properties in wp_query and save original value
1081
- *
1082
- * @since 5.0
1083
- * @param array $query
1084
- */
1085
- private static function set_wp_query($query)
1086
- {
1087
- global $wp_query;
1088
- foreach ($query as $key => $val) {
1089
- $is_array = is_array($val);
1090
-
1091
- if (!isset(self::$wp_query_original[$key])) {
1092
- self::$wp_query_original[$key] = $is_array ? [] : $wp_query->$key;
1093
- }
1094
-
1095
- if ($is_array) {
1096
- foreach ($val as $k1 => $v1) {
1097
- if (!isset(self::$wp_query_original[$key][$k1])) {
1098
- self::$wp_query_original[$key][$k1] = $wp_query->{$key}[$k1];
1099
- }
1100
- $wp_query->{$key}[$k1] = $v1;
1101
- }
1102
- } else {
1103
- $wp_query->$key = $val;
1104
- }
1105
- }
1106
- }
1107
-
1108
- /**
1109
- * Autoload class files
1110
- *
1111
- * @since 1.0
1112
- * @param string $class
1113
- * @return void
1114
- */
1115
- private static function _autoload_class_files($class)
1116
- {
1117
- if (strpos($class, self::CLASS_PREFIX) === 0) {
1118
- $class = str_replace(self::CLASS_PREFIX, '', $class);
1119
- $class = self::str_replace_first('_', '/', $class);
1120
- $class = strtolower($class);
1121
- $file = WPCA_PATH . $class . '.php';
1122
- if (file_exists($file)) {
1123
- include($file);
1124
- }
1125
- }
1126
- }
1127
-
1128
- /**
1129
- * Helper function to replace first
1130
- * occurence of substring
1131
- *
1132
- * @since 1.0
1133
- * @param string $search
1134
- * @param string $replace
1135
- * @param string $subject
1136
- * @return string
1137
- */
1138
- private static function str_replace_first($search, $replace, $subject)
1139
- {
1140
- $pos = strpos($subject, $search);
1141
- if ($pos !== false) {
1142
- $subject = substr_replace($subject, $replace, $pos, strlen($search));
1143
- }
1144
- return $subject;
1145
- }
1146
-
1147
- /**
1148
- * @since 8.0
1149
- * @param array $input
1150
- *
1151
- * @return string
1152
- */
1153
- private static function sql_prepare_in($input)
1154
- {
1155
- $output = array_map(function ($value) {
1156
- return "'" . esc_sql($value) . "'";
1157
- }, $input);
1158
- return implode(',', $output);
1159
- }
1160
-
1161
- /**
1162
- * @since 8.0
1163
- * @param string $type
1164
- * @param array $modules
1165
- *
1166
- * @return array
1167
- */
1168
- private static function filter_condition_type_cache($type, $modules)
1169
- {
1170
- $included_conditions = get_option(self::OPTION_CONDITION_TYPE_CACHE, []);
1171
-
1172
- if (!$included_conditions || !isset($included_conditions[$type])) {
1173
- return $modules;
1174
- }
1175
-
1176
- $included_conditions_lookup = array_flip($included_conditions[$type]);
1177
- $filtered_modules = [];
1178
-
1179
- foreach ($modules as $module) {
1180
- if (isset($included_conditions_lookup[$module->get_id()])) {
1181
- $filtered_modules[] = $module;
1182
- }
1183
- }
1184
-
1185
- return $filtered_modules;
1186
- }
1187
-
1188
- /**
1189
- * @param string $post_type
1190
- * @param string $name
1191
- * @param mixed|null $default_value
1192
- *
1193
- * @return mixed|null
1194
- */
1195
- public static function get_option($post_type, $name, $default_value = null)
1196
- {
1197
- if (!self::types()->has($post_type)) {
1198
- return $default_value;
1199
- }
1200
-
1201
- $value = get_option(self::OPTION_POST_TYPE_OPTIONS, []);
1202
- $levels = explode('.', $post_type.'.'.$name);
1203
-
1204
- foreach ($levels as $option_level) {
1205
- if (!is_array($value) || !isset($value[$option_level])) {
1206
- return $default_value;
1207
- }
1208
- $value = $value[$option_level];
1209
- }
1210
- return $value;
1211
- }
1212
-
1213
- /**
1214
- * @param string $post_type
1215
- * @param string $name
1216
- * @param mixed $value
1217
- *
1218
- * @return bool
1219
- */
1220
- public static function save_option($post_type, $name, $value)
1221
- {
1222
- if (!self::types()->has($post_type)) {
1223
- return false;
1224
- }
1225
-
1226
- $options = get_option(self::OPTION_POST_TYPE_OPTIONS, []);
1227
- $keys = explode('.', $post_type.'.'.$name);
1228
- $array = &$options;
1229
-
1230
- foreach ($keys as $key) {
1231
- if (!isset($array[$key]) || !is_array($array[$key])) {
1232
- $array[$key] = [];
1233
- }
1234
- $array = &$array[$key];
1235
- }
1236
- $array = $value;
1237
-
1238
- return update_option(self::OPTION_POST_TYPE_OPTIONS, $options);
1239
- }
1240
- }
1241
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ if (!class_exists('WPCACore')) {
12
+ $domain = explode('/', plugin_basename(__FILE__));
13
+ define('WPCA_DOMAIN', $domain[0]);
14
+ define('WPCA_PATH', plugin_dir_path(__FILE__));
15
+
16
+ /**
17
+ * Core for WordPress Content Aware Engine
18
+ */
19
+ final class WPCACore
20
+ {
21
+
22
+ /**
23
+ * Using class prefix instead of namespace
24
+ * for PHP5.2 compatibility
25
+ */
26
+ const CLASS_PREFIX = 'WPCA';
27
+
28
+ /**
29
+ * Prefix for data (keys) stored in database
30
+ */
31
+ const PREFIX = '_ca_';
32
+
33
+ /**
34
+ * Post Type for condition groups
35
+ */
36
+ const TYPE_CONDITION_GROUP = 'condition_group';
37
+
38
+ /**
39
+ * Post Statuses for condition groups
40
+ */
41
+ /**
42
+ * @deprecated
43
+ */
44
+ const STATUS_NEGATED = 'negated';
45
+ /**
46
+ * @deprecated
47
+ */
48
+ const STATUS_PUBLISHED = 'publish';
49
+ const STATUS_OR = 'wpca_or';
50
+ const STATUS_EXCEPT = 'wpca_except';
51
+
52
+ /**
53
+ * Exposures for condition groups
54
+ */
55
+ const EXP_SINGULAR = 0;
56
+ const EXP_SINGULAR_ARCHIVE = 1;
57
+ const EXP_ARCHIVE = 2;
58
+
59
+ /**
60
+ * @deprecated 7.0
61
+ */
62
+ const CAPABILITY = 'edit_theme_options';
63
+
64
+ /**
65
+ * Name for generated nonces
66
+ */
67
+ const NONCE = '_ca_nonce';
68
+
69
+ const OPTION_CONDITION_TYPE_CACHE = '_ca_condition_type_cache';
70
+ const OPTION_POST_TYPE_OPTIONS = '_ca_post_type_options';
71
+
72
+ /**
73
+ * Post Types that use the engine
74
+ * @var WPCAPostTypeManager
75
+ */
76
+ private static $type_manager;
77
+
78
+ /**
79
+ * Conditions retrieved from database
80
+ * @var array
81
+ */
82
+ private static $condition_cache = [];
83
+
84
+ /**
85
+ * Objects retrieved from database
86
+ * @var array
87
+ */
88
+ private static $post_cache = [];
89
+
90
+ private static $wp_query_original = [];
91
+
92
+ private static $filtered_modules = [];
93
+
94
+ /**
95
+ * Constructor
96
+ */
97
+ public static function init()
98
+ {
99
+ spl_autoload_register([__CLASS__,'_autoload_class_files']);
100
+
101
+ if (is_admin()) {
102
+ add_action(
103
+ 'admin_enqueue_scripts',
104
+ [__CLASS__,'add_group_script_styles'],
105
+ 9
106
+ );
107
+ add_action(
108
+ 'delete_post',
109
+ [__CLASS__,'sync_group_deletion']
110
+ );
111
+ add_action(
112
+ 'trashed_post',
113
+ [__CLASS__,'sync_group_trashed']
114
+ );
115
+ add_action(
116
+ 'untrashed_post',
117
+ [__CLASS__,'sync_group_untrashed']
118
+ );
119
+ add_action(
120
+ 'wpca/modules/save-data',
121
+ [__CLASS__,'save_condition_options'],
122
+ 10,
123
+ 3
124
+ );
125
+
126
+ add_action(
127
+ 'wp_ajax_wpca/add-rule',
128
+ [__CLASS__,'ajax_update_group']
129
+ );
130
+ }
131
+
132
+ add_action(
133
+ 'init',
134
+ [__CLASS__,'add_group_post_type'],
135
+ 99
136
+ );
137
+
138
+ add_action(
139
+ 'init',
140
+ [__CLASS__,'schedule_cache_condition_types'],
141
+ 99
142
+ );
143
+
144
+ add_action(
145
+ 'wpca/cache_condition_types',
146
+ [__CLASS__,'cache_condition_types'],
147
+ 999
148
+ );
149
+ }
150
+
151
+ /**
152
+ * Get post type manager
153
+ *
154
+ * @deprecated 4.0
155
+ * @since 1.0
156
+ * @return WPCAPostTypeManager
157
+ */
158
+ public static function post_types()
159
+ {
160
+ return self::types();
161
+ }
162
+
163
+ /**
164
+ * Get type manager
165
+ *
166
+ * @since 4.0
167
+ * @return WPCAPostTypeManager
168
+ */
169
+ public static function types()
170
+ {
171
+ if (!isset(self::$type_manager)) {
172
+ self::$type_manager = new WPCATypeManager();
173
+ }
174
+ return self::$type_manager;
175
+ }
176
+
177
+ /**
178
+ * @since 8.0
179
+ *
180
+ * @return void
181
+ */
182
+ public static function schedule_cache_condition_types()
183
+ {
184
+ if (wp_next_scheduled('wpca/cache_condition_types') !== false) {
185
+ return;
186
+ }
187
+
188
+ wp_schedule_event(get_gmt_from_date('today 02:00:00', 'U'), 'daily', 'wpca/cache_condition_types');
189
+ }
190
+
191
+ /**
192
+ * Cache condition types currently in use
193
+ *
194
+ * @since 8.0
195
+ *
196
+ * @return void
197
+ */
198
+ public static function cache_condition_types()
199
+ {
200
+ $all_modules = [];
201
+ $modules_by_type = [];
202
+ $cache = [];
203
+
204
+ $types = self::types();
205
+ foreach ($types as $type => $modules) {
206
+ $modules_by_type[$type] = [];
207
+ $cache[$type] = [];
208
+ foreach ($modules as $module) {
209
+ $modules_by_type[$type][$module->get_data_key()] = $module->get_id();
210
+ $all_modules[$module->get_data_key()] = $module->get_data_key();
211
+ }
212
+ }
213
+
214
+ if (!$all_modules) {
215
+ update_option(self::OPTION_CONDITION_TYPE_CACHE, []);
216
+ return;
217
+ }
218
+
219
+ global $wpdb;
220
+
221
+ $query = '
222
+ SELECT p.post_type, m.meta_key
223
+ FROM '.$wpdb->posts.' p
224
+ INNER JOIN '.$wpdb->posts.' c ON c.post_parent = p.ID
225
+ INNER JOIN '.$wpdb->postmeta.' m ON m.post_id = c.ID
226
+ WHERE p.post_type IN ('.self::sql_prepare_in(array_keys($modules_by_type)).')
227
+ AND m.meta_key IN ('.self::sql_prepare_in($all_modules).')
228
+ GROUP BY p.post_type, m.meta_key
229
+ ';
230
+
231
+ $results = (array) $wpdb->get_results($query);
232
+
233
+ foreach ($results as $result) {
234
+ if (isset($modules_by_type[$result->post_type][$result->meta_key])) {
235
+ $cache[$result->post_type][] = $modules_by_type[$result->post_type][$result->meta_key];
236
+ }
237
+ }
238
+
239
+ update_option(self::OPTION_CONDITION_TYPE_CACHE, $cache);
240
+ }
241
+
242
+ /**
243
+ * Register group post type
244
+ *
245
+ * @since 1.0
246
+ * @return void
247
+ */
248
+ public static function add_group_post_type()
249
+ {
250
+ //This is just a safety placeholder,
251
+ //authorization will be done with parent object's cap
252
+ $capability = 'edit_theme_options';
253
+ $capabilities = [
254
+ 'edit_post' => $capability,
255
+ 'read_post' => $capability,
256
+ 'delete_post' => $capability,
257
+ 'edit_posts' => $capability,
258
+ 'delete_posts' => $capability,
259
+ 'edit_others_posts' => $capability,
260
+ 'publish_posts' => $capability,
261
+ 'read_private_posts' => $capability
262
+ ];
263
+
264
+ register_post_type(self::TYPE_CONDITION_GROUP, [
265
+ 'labels' => [
266
+ 'name' => __('Condition Groups', WPCA_DOMAIN),
267
+ 'singular_name' => __('Condition Group', WPCA_DOMAIN),
268
+ ],
269
+ 'capabilities' => $capabilities,
270
+ 'public' => false,
271
+ 'hierarchical' => false,
272
+ 'exclude_from_search' => true,
273
+ 'publicly_queryable' => false,
274
+ 'show_ui' => false,
275
+ 'show_in_menu' => false,
276
+ 'show_in_nav_menus' => false,
277
+ 'show_in_admin_bar' => false,
278
+ 'show_in_rest' => false,
279
+ 'has_archive' => false,
280
+ 'rewrite' => false,
281
+ 'query_var' => false,
282
+ 'supports' => ['title'],
283
+ 'can_export' => false,
284
+ 'delete_with_user' => false
285
+ ]);
286
+
287
+ register_post_status(self::STATUS_NEGATED, [
288
+ 'label' => _x('Negated', 'condition status', WPCA_DOMAIN),
289
+ 'public' => false,
290
+ 'exclude_from_search' => true,
291
+ 'show_in_admin_all_list' => false,
292
+ 'show_in_admin_status_list' => false,
293
+ ]);
294
+ register_post_status(self::STATUS_EXCEPT, [
295
+ 'label' => _x('Exception', 'condition status', WPCA_DOMAIN),
296
+ 'public' => false,
297
+ 'exclude_from_search' => true,
298
+ 'show_in_admin_all_list' => false,
299
+ 'show_in_admin_status_list' => false,
300
+ ]);
301
+ register_post_status(self::STATUS_OR, [
302
+ 'label' => _x('Or', 'condition status', WPCA_DOMAIN),
303
+ 'public' => false,
304
+ 'exclude_from_search' => true,
305
+ 'show_in_admin_all_list' => false,
306
+ 'show_in_admin_status_list' => false,
307
+ ]);
308
+ }
309
+
310
+ /**
311
+ * Get group IDs by their parent ID
312
+ *
313
+ * @since 1.0
314
+ * @param int $parent_id
315
+ * @return array
316
+ */
317
+ private static function get_group_ids_by_parent($parent_id)
318
+ {
319
+ if (!self::types()->has(get_post_type($parent_id))) {
320
+ return [];
321
+ }
322
+
323
+ global $wpdb;
324
+ return (array)$wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = '%d'", $parent_id));
325
+ }
326
+
327
+ /**
328
+ * Delete groups from database when their parent is deleted
329
+ *
330
+ * @since 1.0
331
+ * @param int $post_id
332
+ * @return void
333
+ */
334
+ public static function sync_group_deletion($post_id)
335
+ {
336
+ $groups = self::get_group_ids_by_parent($post_id);
337
+ if ($groups) {
338
+ foreach ($groups as $group_id) {
339
+ //Takes care of metadata and terms too
340
+ wp_delete_post($group_id, true);
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Trash groups when their parent is trashed
347
+ *
348
+ * @since 1.0
349
+ * @param int $post_id
350
+ * @return void
351
+ */
352
+ public static function sync_group_trashed($post_id)
353
+ {
354
+ $groups = self::get_group_ids_by_parent($post_id);
355
+ if ($groups) {
356
+ foreach ($groups as $group_id) {
357
+ wp_trash_post($group_id);
358
+ }
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Untrash groups when their parent is untrashed
364
+ *
365
+ * @since 1.0
366
+ * @param int $post_id
367
+ * @return void
368
+ */
369
+ public static function sync_group_untrashed($post_id)
370
+ {
371
+ $groups = self::get_group_ids_by_parent($post_id);
372
+ if ($groups) {
373
+ foreach ($groups as $group_id) {
374
+ wp_untrash_post($group_id);
375
+ }
376
+ }
377
+ }
378
+
379
+ /**
380
+ * @param string $post_type
381
+ * @return array
382
+ */
383
+ public static function get_conditional_modules($post_type)
384
+ {
385
+ if (!isset(self::$filtered_modules[$post_type])) {
386
+ return [];
387
+ }
388
+ return self::$filtered_modules[$post_type];
389
+ }
390
+
391
+ /**
392
+ * Get filtered condition groups
393
+ *
394
+ * @since 2.0
395
+ * @return array
396
+ */
397
+ public static function get_conditions($post_type)
398
+ {
399
+ global $wpdb, $wp_query, $post;
400
+
401
+ if (!self::types()->has($post_type) || (!$wp_query->query && !$post) || is_admin()) {
402
+ return [];
403
+ }
404
+
405
+ // Return cache if present
406
+ if (isset(self::$condition_cache[$post_type])) {
407
+ return self::$condition_cache[$post_type];
408
+ }
409
+
410
+ $where = [];
411
+ $join = [];
412
+
413
+ $cache = [
414
+ $post_type
415
+ ];
416
+
417
+ $modules = self::types()->get($post_type)->get_all();
418
+ $modules = self::filter_condition_type_cache($post_type, $modules);
419
+
420
+ //avoid combining as long as negated conditions are being deprecated
421
+ // foreach (self::types() as $other_type => $other_modules) {
422
+ // if ($other_type == $post_type) {
423
+ // continue;
424
+ // }
425
+ // if (self::filter_condition_type_cache($other_type, $other_modules->get_all()) === $modules) {
426
+ // $cache[] = $other_type;
427
+ // }
428
+ // }
429
+
430
+ self::fix_wp_query();
431
+
432
+ $in_context_by_module_id = [];
433
+ foreach ($modules as $module) {
434
+ $id = $module->get_id();
435
+ $in_context = apply_filters("wpca/module/$id/in-context", $module->in_context());
436
+ $in_context_by_module_id[$id] = $in_context;
437
+
438
+ if(!$in_context) {
439
+ continue;
440
+ }
441
+
442
+ $data = $module->get_context_data();
443
+
444
+ if(empty($data)) {
445
+ $in_context_by_module_id[$id] = false;
446
+ continue;
447
+ }
448
+
449
+ if (is_array($data)) {
450
+ $name = $module->get_query_name();
451
+ $data = "($name.meta_value IS NULL OR $name.meta_value IN (".self::sql_prepare_in($data).'))';
452
+ }
453
+ $join[$id] = $module->db_join();
454
+ $where[$id] = apply_filters("wpca/module/$id/db-where", $data);
455
+ self::$filtered_modules[$post_type][] = $module;
456
+ }
457
+
458
+ $use_negated_conditions = self::get_option($post_type, 'legacy.negated_conditions', false);
459
+
460
+ // Check if there are any conditions for current content
461
+ $groups_in_context = [];
462
+ if (!empty($where)) {
463
+ $post_status = [
464
+ self::STATUS_PUBLISHED,
465
+ self::STATUS_OR,
466
+ self::STATUS_EXCEPT
467
+ ];
468
+
469
+ if ($use_negated_conditions) {
470
+ $post_status[] = self::STATUS_NEGATED;
471
+ }
472
+
473
+ $chunk_size = count($join);
474
+ if (defined('WPCA_SQL_JOIN_SIZE') && is_integer(WPCA_SQL_JOIN_SIZE) && WPCA_SQL_JOIN_SIZE > 0) {
475
+ $chunk_size = WPCA_SQL_JOIN_SIZE;
476
+ } elseif (defined('WPCA_SQL_COMPATIBILITY_MODE') && WPCA_SQL_COMPATIBILITY_MODE === true) {
477
+ //Syntax changed in MySQL 5.5 and MariaDB 10.0 (reports as version 5.5)
478
+ $wpdb->query('SET'.(version_compare($wpdb->db_version(), '5.5', '>=') ? ' SESSION' : ' OPTION').' SQL_BIG_SELECTS = 1');
479
+ }
480
+
481
+ $joins = array_chunk($join, $chunk_size);
482
+ $joins_max = count($joins) - 1;
483
+ $wheres = array_chunk($where, $chunk_size);
484
+ $group_ids = [];
485
+ $groups_in_context = [];
486
+
487
+ $where2 = [];
488
+ $where2[] = "p.post_type = '".self::TYPE_CONDITION_GROUP."'";
489
+ $where2[] = "p.post_status IN ('".implode("','", $post_status)."')";
490
+ $where2[] = 'p.menu_order '.(is_archive() || is_home() ? '>=' : '<=').' 1';
491
+
492
+ foreach ($joins as $i => $join) {
493
+ if ($i == $joins_max) {
494
+ $groups_in_context = $wpdb->get_results(
495
+ 'SELECT p.ID, p.post_parent, p.post_status '.
496
+ "FROM $wpdb->posts p ".
497
+ implode(' ', $join).'
498
+ WHERE
499
+ '.implode(' AND ', $wheres[$i]).'
500
+ AND '.implode(' AND ', $where2).
501
+ (!empty($group_ids) ? ' AND p.id IN ('.implode(',', $group_ids).')' : ''),
502
+ OBJECT_K
503
+ );
504
+ break;
505
+ }
506
+
507
+ $group_ids = array_merge($group_ids, $wpdb->get_col(
508
+ 'SELECT p.ID '.
509
+ "FROM $wpdb->posts p ".
510
+ implode(' ', $join).'
511
+ WHERE
512
+ '.implode(' AND ', $wheres[$i]).'
513
+ AND '.implode(' AND ', $where2)
514
+ ));
515
+ }
516
+ }
517
+
518
+ $groups_negated = [];
519
+ if ($use_negated_conditions) {
520
+ $groups_negated = $wpdb->get_results($wpdb->prepare(
521
+ 'SELECT p.ID, p.post_parent '.
522
+ "FROM $wpdb->posts p ".
523
+ "WHERE p.post_type = '%s' ".
524
+ "AND p.post_status = '%s' ",
525
+ self::TYPE_CONDITION_GROUP,
526
+ self::STATUS_NEGATED
527
+ ), OBJECT_K);
528
+ }
529
+
530
+ if (!empty($groups_in_context) || !empty($groups_negated)) {
531
+ //Force update of meta cache to prevent lazy loading
532
+ update_meta_cache('post', array_keys($groups_in_context + $groups_negated));
533
+ }
534
+
535
+ //Exclude types that have unrelated content in same group
536
+ foreach ($modules as $module) {
537
+ $groups_in_context = $module->filter_excluded_context(
538
+ $groups_in_context,
539
+ $in_context_by_module_id[$module->get_id()]
540
+ );
541
+ }
542
+
543
+ //exclude exceptions
544
+ $excepted = [];
545
+ foreach ($groups_in_context as $group_id => $group) {
546
+ if ($group->post_status == self::STATUS_EXCEPT) {
547
+ $excepted[$group->post_parent] = 1;
548
+ }
549
+ }
550
+
551
+ //condition group => type
552
+ $valid = [];
553
+ foreach ($groups_in_context as $group) {
554
+ $valid[$group->ID] = $group->post_parent;
555
+ }
556
+
557
+ foreach ($valid as $group_id => $parent_id) {
558
+ if (isset($excepted[$parent_id])) {
559
+ unset($valid[$group_id]);
560
+ }
561
+ }
562
+
563
+ if ($use_negated_conditions) {
564
+ //Filter negated groups
565
+ //type => group
566
+ $handled_already = array_flip($valid);
567
+ foreach ($groups_negated as $group) {
568
+ if (isset($valid[$group->ID])) {
569
+ unset($valid[$group->ID]);
570
+ } else {
571
+ $valid[$group->ID] = $group->post_parent;
572
+ }
573
+ if (isset($handled_already[$group->post_parent])) {
574
+ unset($valid[$group->ID]);
575
+ }
576
+ $handled_already[$group->post_parent] = 1;
577
+ }
578
+ }
579
+
580
+ self::restore_wp_query();
581
+
582
+ foreach ($cache as $cache_type) {
583
+ self::$condition_cache[$cache_type] = $valid;
584
+ }
585
+
586
+ return self::$condition_cache[$post_type];
587
+ }
588
+
589
+ /**
590
+ * Get filtered posts from a post type
591
+ *
592
+ * @since 1.0
593
+ * @return array
594
+ */
595
+ public static function get_posts($post_type)
596
+ {
597
+ if (isset(self::$post_cache[$post_type])) {
598
+ return self::$post_cache[$post_type];
599
+ }
600
+
601
+ $valid = self::get_conditions($post_type);
602
+
603
+ //if cache hasn't been set, method was called too early
604
+ if (!isset(self::$condition_cache[$post_type])) {
605
+ return false;
606
+ }
607
+
608
+ self::$post_cache[$post_type] = [];
609
+
610
+ $results = [];
611
+
612
+ if (!empty($valid)) {
613
+ $data = new WP_Query([
614
+ 'post__in' => array_values($valid),
615
+ 'post_type' => $post_type,
616
+ 'post_status' => 'publish',
617
+ 'posts_per_page' => -1,
618
+ 'ignore_sticky_posts' => true,
619
+ 'update_post_term_cache' => false,
620
+ 'update_post_meta_cache' => true,
621
+ 'suppress_filters' => true,
622
+ 'no_found_rows' => true,
623
+ 'orderby' => 'none'
624
+ ]);
625
+
626
+ $results = array_merge($results, $data->posts);
627
+ }
628
+
629
+ //legacy sorting
630
+ uasort($results, function (WP_Post $post_a, WP_Post $post_b) {
631
+ //asc
632
+ if ($post_a->menu_order != $post_b->menu_order) {
633
+ return $post_a->menu_order < $post_b->menu_order ? -1 : 1;
634
+ }
635
+
636
+ $post_a_handle = get_post_meta($post_a->ID, '_ca_handle', true);
637
+ $post_b_handle = get_post_meta($post_b->ID, '_ca_handle', true);
638
+
639
+ //desc
640
+ if ($post_a_handle != $post_b_handle) {
641
+ return $post_a_handle > $post_b_handle ? -1 : 1;
642
+ }
643
+
644
+ //desc
645
+ if ($post_a->post_date != $post_b->post_date) {
646
+ return $post_a->post_date > $post_b->post_date ? -1 : 1;
647
+ }
648
+
649
+ return 0;
650
+ });
651
+
652
+ $results = array_reduce($results, function ($carry, $post) {
653
+ $carry[$post->ID] = (object)[
654
+ 'ID' => $post->ID,
655
+ 'post_type' => $post->post_type,
656
+ 'handle' => get_post_meta($post->ID, '_ca_handle', true),
657
+ 'menu_order' => $post->menu_order,
658
+ 'post_date' => $post->post_date
659
+ ];
660
+ return $carry;
661
+ }, []);
662
+
663
+ self::$post_cache[$post_type] = apply_filters("wpca/posts/{$post_type}", $results);
664
+
665
+ return self::$post_cache[$post_type];
666
+ }
667
+
668
+ public static function render_group_meta_box($post, $screen, $context = 'normal', $priority = 'default')
669
+ {
670
+ if (!($post instanceof WP_Post) || !self::types()->has($post->post_type)) {
671
+ return;
672
+ }
673
+
674
+ $post_type_obj = get_post_type_object($post->post_type);
675
+
676
+ if (!current_user_can($post_type_obj->cap->edit_post, $post->ID)) {
677
+ return;
678
+ }
679
+
680
+ $template = WPCAView::make('condition_options', [
681
+ 'post_type' => $post->post_type
682
+ ]);
683
+ add_action('wpca/group/settings', [$template,'render'], -1, 2);
684
+
685
+ $template = WPCAView::make('group_template', [
686
+ 'post_type' => $post->post_type
687
+ ]);
688
+ add_action('admin_footer', [$template,'render']);
689
+
690
+ $template = WPCAView::make('condition_template');
691
+ add_action('admin_footer', [$template,'render']);
692
+
693
+ $view = WPCAView::make('meta_box', [
694
+ 'post_type' => $post->post_type,
695
+ 'nonce' => wp_nonce_field(self::PREFIX.$post->ID, self::NONCE, true, false),
696
+ ]);
697
+
698
+ $title = isset($post_type_obj->labels->ca_title) ? $post_type_obj->labels->ca_title : __('Conditional Logic', WPCA_DOMAIN);
699
+
700
+ add_meta_box(
701
+ 'cas-rules',
702
+ $title,
703
+ [$view,'render'],
704
+ $screen,
705
+ $context,
706
+ $priority
707
+ );
708
+ }
709
+
710
+ /**
711
+ * Insert new condition group for a post type
712
+ * Uses current post per default
713
+ *
714
+ * @since 1.0
715
+ * @param WP_Post|int $post
716
+ * @return int
717
+ */
718
+ public static function add_condition_group($post_id = null)
719
+ {
720
+ $post = get_post($post_id);
721
+
722
+ //Make sure to go from auto-draft to draft
723
+ if ($post->post_status == 'auto-draft') {
724
+ wp_update_post([
725
+ 'ID' => $post->ID,
726
+ 'post_title' => '',
727
+ 'post_status' => 'draft'
728
+ ]);
729
+ }
730
+
731
+ return wp_insert_post([
732
+ 'post_status' => self::STATUS_OR,
733
+ 'menu_order' => self::EXP_SINGULAR_ARCHIVE,
734
+ 'post_type' => self::TYPE_CONDITION_GROUP,
735
+ 'post_author' => $post->post_author,
736
+ 'post_parent' => $post->ID,
737
+ ]);
738
+ }
739
+
740
+ /**
741
+ * Get condition groups for a post type
742
+ * Uses current post per default
743
+ *
744
+ * @since 1.0
745
+ * @param WP_Post|int $post_id
746
+ * @return array
747
+ */
748
+ private static function get_condition_groups($post_id = null)
749
+ {
750
+ $post = get_post($post_id);
751
+ $groups = [];
752
+
753
+ if ($post) {
754
+ $groups = get_posts([
755
+ 'posts_per_page' => -1,
756
+ 'post_type' => self::TYPE_CONDITION_GROUP,
757
+ 'post_parent' => $post->ID,
758
+ 'post_status' => [self::STATUS_PUBLISHED,self::STATUS_NEGATED,self::STATUS_EXCEPT, self::STATUS_OR],
759
+ 'order' => 'ASC',
760
+ 'orderby' => 'post_status'
761
+ ]);
762
+ }
763
+ return $groups;
764
+ }
765
+
766
+ /**
767
+ * AJAX callback to update a condition group
768
+ *
769
+ * @since 1.0
770
+ * @return void
771
+ */
772
+ public static function ajax_update_group()
773
+ {
774
+ if (!isset($_POST['current_id']) ||
775
+ !check_ajax_referer(self::PREFIX.$_POST['current_id'], 'token', false)) {
776
+ wp_send_json_error(__('Unauthorized request', WPCA_DOMAIN), 403);
777
+ }
778
+
779
+ $parent_id = (int)$_POST['current_id'];
780
+ $parent_type = get_post_type_object($_POST['post_type']);
781
+
782
+ if (! current_user_can($parent_type->cap->edit_post, $parent_id)) {
783
+ wp_send_json_error(__('Unauthorized request', WPCA_DOMAIN), 403);
784
+ }
785
+
786
+ $response = [
787
+ 'message' => __('Conditions updated', WPCA_DOMAIN)
788
+ ];
789
+
790
+ //Make sure some rules are sent
791
+ if (!isset($_POST['conditions'])) {
792
+ //Otherwise we delete group
793
+ if ($_POST['id'] && wp_delete_post(intval($_POST['id']), true) === false) {
794
+ wp_send_json_error(__('Could not delete conditions', WPCA_DOMAIN), 500);
795
+ }
796
+
797
+ $response['removed'] = true;
798
+ wp_send_json($response);
799
+ }
800
+
801
+ //If ID was not sent at this point, it is a new group
802
+ if (!$_POST['id']) {
803
+ $post_id = self::add_condition_group($parent_id);
804
+ $response['new_post_id'] = $post_id;
805
+ } else {
806
+ $post_id = (int)$_POST['id'];
807
+ }
808
+
809
+ wp_update_post([
810
+ 'ID' => $post_id,
811
+ 'post_status' => self::sanitize_status($_POST['status']),
812
+ 'menu_order' => (int)$_POST['exposure']
813
+ ]);
814
+
815
+ //Prune condition type cache, will rebuild within 24h
816
+ update_option(self::OPTION_CONDITION_TYPE_CACHE, []);
817
+
818
+ foreach (self::types()->get($parent_type->name)->get_all() as $module) {
819
+ //send $_POST here
820
+ $module->save_data($post_id);
821
+ }
822
+
823
+ do_action('wpca/modules/save-data', $post_id, $parent_type->name);
824
+
825
+ wp_send_json($response);
826
+ }
827
+
828
+ /**
829
+ * @param string $status
830
+ *
831
+ * @return string
832
+ */
833
+ private static function sanitize_status($status)
834
+ {
835
+ switch ($status) {
836
+ case self::STATUS_NEGATED:
837
+ return self::STATUS_NEGATED;
838
+ case self::STATUS_EXCEPT:
839
+ return self::STATUS_EXCEPT;
840
+ case self::STATUS_OR:
841
+ case self::STATUS_PUBLISHED:
842
+ default:
843
+ return self::STATUS_OR;
844
+ }
845
+ }
846
+
847
+ /**
848
+ * Save registered meta for condition group
849
+ *
850
+ * @since 3.2
851
+ * @param int $group_id
852
+ * @return void
853
+ */
854
+ public static function save_condition_options($group_id, $post_type)
855
+ {
856
+ $meta_keys = self::get_condition_meta_keys($post_type);
857
+ foreach ($meta_keys as $key => $default_value) {
858
+ $value = isset($_POST[$key]) ? $_POST[$key] : false;
859
+ if ($value) {
860
+ update_post_meta($group_id, $key, $value);
861
+ } elseif (get_post_meta($group_id, $key, true)) {
862
+ delete_post_meta($group_id, $key);
863
+ }
864
+ }
865
+ }
866
+
867
+ public static function add_group_script_styles($hook)
868
+ {
869
+ $current_screen = get_current_screen();
870
+
871
+ wp_register_style(
872
+ self::PREFIX.'condition-groups',
873
+ plugins_url('/assets/css/condition_groups.css', __FILE__),
874
+ [],
875
+ WPCA_VERSION
876
+ );
877
+
878
+ if (self::types()->has($current_screen->post_type) && $current_screen->base == 'post') {
879
+ self::enqueue_scripts_styles($current_screen->post_type);
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Get condition option defaults
885
+ *
886
+ * @since 3.2
887
+ * @param string $post_type
888
+ * @return array
889
+ */
890
+ public static function get_condition_meta_keys($post_type)
891
+ {
892
+ $group_meta = [
893
+ '_ca_autoselect' => 0
894
+ ];
895
+ return apply_filters('wpca/condition/meta', $group_meta, $post_type);
896
+ }
897
+
898
+ /**
899
+ * Register and enqueue scripts and styles
900
+ * for post edit screen
901
+ *
902
+ * @since 1.0
903
+ * @param string $hook
904
+ * @return void
905
+ */
906
+ public static function enqueue_scripts_styles($post_type = '')
907
+ {
908
+ $post_type = empty($post_type) ? get_post_type() : $post_type;
909
+
910
+ $group_meta = self::get_condition_meta_keys($post_type);
911
+
912
+ $groups = self::get_condition_groups();
913
+ $data = [];
914
+ $i = 0;
915
+ foreach ($groups as $group) {
916
+ $data[$i] = [
917
+ 'id' => $group->ID,
918
+ 'status' => $group->post_status,
919
+ 'exposure' => $group->menu_order,
920
+ 'conditions' => []
921
+ ];
922
+
923
+ foreach (self::types()->get($post_type)->get_all() as $module) {
924
+ $data[$i]['conditions'] = $module->get_group_data($data[$i]['conditions'], $group->ID);
925
+ }
926
+
927
+ foreach ($group_meta as $meta_key => $default_value) {
928
+ $value = get_post_meta($group->ID, $meta_key, true);
929
+ if ($value === false) {
930
+ $value = $default_value;
931
+ }
932
+ $data[$i][$meta_key] = $value;
933
+ }
934
+ $i++;
935
+ }
936
+
937
+ $conditions = [
938
+ 'general' => [
939
+ 'text' => __('General'),
940
+ 'children' => []
941
+ ],
942
+ 'post_type' => [
943
+ 'text' => __('Post Types'),
944
+ 'children' => []
945
+ ],
946
+ 'taxonomy' => [
947
+ 'text' => __('Taxonomies'),
948
+ 'children' => []
949
+ ],
950
+ 'plugins' => [
951
+ 'text' => __('Plugins'),
952
+ 'children' => []
953
+ ]
954
+ ];
955
+
956
+ foreach (self::types()->get($post_type)->get_all() as $module) {
957
+ $category = $module->get_category();
958
+ if (!isset($conditions[$category])) {
959
+ $category = 'general';
960
+ }
961
+
962
+ //array_values used for backwards compatibility
963
+ $conditions[$category]['children'] = array_values($module->list_module($conditions[$category]['children']));
964
+ }
965
+
966
+ foreach ($conditions as $key => $condition) {
967
+ if (empty($condition['children'])) {
968
+ unset($conditions[$key]);
969
+ }
970
+ }
971
+
972
+ //Make sure to use packaged version
973
+ if (wp_script_is('select2', 'registered')) {
974
+ wp_deregister_script('select2');
975
+ wp_deregister_style('select2');
976
+ }
977
+
978
+ $plugins_url = plugins_url('', __FILE__);
979
+
980
+ //Add to head to take priority
981
+ //if being added under other name
982
+ wp_register_script(
983
+ 'select2',
984
+ $plugins_url . '/assets/js/select2.min.js',
985
+ ['jquery'],
986
+ '4.0.3',
987
+ false
988
+ );
989
+
990
+ wp_register_script(
991
+ 'backbone.trackit',
992
+ $plugins_url . '/assets/js/backbone.trackit.min.js',
993
+ ['backbone'],
994
+ '0.1.0',
995
+ true
996
+ );
997
+
998
+ wp_register_script(
999
+ 'backbone.epoxy',
1000
+ $plugins_url . '/assets/js/backbone.epoxy.min.js',
1001
+ ['backbone'],
1002
+ '1.3.3',
1003
+ true
1004
+ );
1005
+
1006
+ wp_register_script(
1007
+ self::PREFIX.'condition-groups',
1008
+ $plugins_url . '/assets/js/condition_groups.min.js',
1009
+ ['jquery','select2','backbone.trackit','backbone.epoxy'],
1010
+ WPCA_VERSION,
1011
+ true
1012
+ );
1013
+
1014
+ wp_enqueue_script(self::PREFIX.'condition-groups');
1015
+ wp_localize_script(self::PREFIX.'condition-groups', 'WPCA', [
1016
+ 'searching' => __('Searching', WPCA_DOMAIN),
1017
+ 'noResults' => __('No results found.', WPCA_DOMAIN),
1018
+ 'loadingMore' => __('Loading more results', WPCA_DOMAIN),
1019
+ 'unsaved' => __('Conditions have unsaved changes. Do you want to continue and discard these changes?', WPCA_DOMAIN),
1020
+ 'newGroup' => __('New condition group', WPCA_DOMAIN),
1021
+ 'newCondition' => __('Meet ALL of these conditions', WPCA_DOMAIN),
1022
+ 'conditions' => array_values($conditions),
1023
+ 'groups' => $data,
1024
+ 'meta_default' => $group_meta,
1025
+ 'post_type' => $post_type,
1026
+ 'text_direction' => is_rtl() ? 'rtl' : 'ltr',
1027
+ 'condition_not' => __('Not', WPCA_DOMAIN),
1028
+ 'condition_or' => __('Or', WPCA_DOMAIN),
1029
+ 'condition_except' => __('Except', WPCA_DOMAIN)
1030
+ ]);
1031
+ wp_enqueue_style(self::PREFIX.'condition-groups');
1032
+
1033
+ //@todo remove when ultimate member includes fix
1034
+ wp_dequeue_style('um_styles');
1035
+
1036
+ //@todo remove when events calendar pro plugin includes fix
1037
+ wp_dequeue_script('tribe-select2');
1038
+ }
1039
+
1040
+ /**
1041
+ * Modify wp_query for plugin compatibility
1042
+ *
1043
+ * @since 5.0
1044
+ * @return void
1045
+ */
1046
+ private static function fix_wp_query()
1047
+ {
1048
+ $query = [];
1049
+
1050
+ //When themes don't declare WooCommerce support,
1051
+ //conditionals are not working properly for Shop
1052
+ if (defined('WOOCOMMERCE_VERSION') && function_exists('is_shop') && is_shop() && !is_post_type_archive('product')) {
1053
+ $query = [
1054
+ 'is_archive' => true,
1055
+ 'is_post_type_archive' => true,
1056
+ 'is_page' => false,
1057
+ 'is_singular' => false,
1058
+ 'query_vars' => [
1059
+ 'post_type' => 'product'
1060
+ ]
1061
+ ];
1062
+ }
1063
+
1064
+ self::set_wp_query($query);
1065
+ }
1066
+
1067
+ /**
1068
+ * Restore original wp_query
1069
+ *
1070
+ * @since 5.0
1071
+ * @return void
1072
+ */
1073
+ private static function restore_wp_query()
1074
+ {
1075
+ self::set_wp_query(self::$wp_query_original);
1076
+ self::$wp_query_original = [];
1077
+ }
1078
+
1079
+ /**
1080
+ * Set properties in wp_query and save original value
1081
+ *
1082
+ * @since 5.0
1083
+ * @param array $query
1084
+ */
1085
+ private static function set_wp_query($query)
1086
+ {
1087
+ global $wp_query;
1088
+ foreach ($query as $key => $val) {
1089
+ $is_array = is_array($val);
1090
+
1091
+ if (!isset(self::$wp_query_original[$key])) {
1092
+ self::$wp_query_original[$key] = $is_array ? [] : $wp_query->$key;
1093
+ }
1094
+
1095
+ if ($is_array) {
1096
+ foreach ($val as $k1 => $v1) {
1097
+ if (!isset(self::$wp_query_original[$key][$k1])) {
1098
+ self::$wp_query_original[$key][$k1] = $wp_query->{$key}[$k1];
1099
+ }
1100
+ $wp_query->{$key}[$k1] = $v1;
1101
+ }
1102
+ } else {
1103
+ $wp_query->$key = $val;
1104
+ }
1105
+ }
1106
+ }
1107
+
1108
+ /**
1109
+ * Autoload class files
1110
+ *
1111
+ * @since 1.0
1112
+ * @param string $class
1113
+ * @return void
1114
+ */
1115
+ private static function _autoload_class_files($class)
1116
+ {
1117
+ if (strpos($class, self::CLASS_PREFIX) === 0) {
1118
+ $class = str_replace(self::CLASS_PREFIX, '', $class);
1119
+ $class = self::str_replace_first('_', '/', $class);
1120
+ $class = strtolower($class);
1121
+ $file = WPCA_PATH . $class . '.php';
1122
+ if (file_exists($file)) {
1123
+ include($file);
1124
+ }
1125
+ }
1126
+ }
1127
+
1128
+ /**
1129
+ * Helper function to replace first
1130
+ * occurence of substring
1131
+ *
1132
+ * @since 1.0
1133
+ * @param string $search
1134
+ * @param string $replace
1135
+ * @param string $subject
1136
+ * @return string
1137
+ */
1138
+ private static function str_replace_first($search, $replace, $subject)
1139
+ {
1140
+ $pos = strpos($subject, $search);
1141
+ if ($pos !== false) {
1142
+ $subject = substr_replace($subject, $replace, $pos, strlen($search));
1143
+ }
1144
+ return $subject;
1145
+ }
1146
+
1147
+ /**
1148
+ * @since 8.0
1149
+ * @param array $input
1150
+ *
1151
+ * @return string
1152
+ */
1153
+ private static function sql_prepare_in($input)
1154
+ {
1155
+ $output = array_map(function ($value) {
1156
+ return "'" . esc_sql($value) . "'";
1157
+ }, $input);
1158
+ return implode(',', $output);
1159
+ }
1160
+
1161
+ /**
1162
+ * @since 8.0
1163
+ * @param string $type
1164
+ * @param array $modules
1165
+ *
1166
+ * @return array
1167
+ */
1168
+ private static function filter_condition_type_cache($type, $modules)
1169
+ {
1170
+ $included_conditions = get_option(self::OPTION_CONDITION_TYPE_CACHE, []);
1171
+
1172
+ if (!$included_conditions || !isset($included_conditions[$type])) {
1173
+ return $modules;
1174
+ }
1175
+
1176
+ $included_conditions_lookup = array_flip($included_conditions[$type]);
1177
+ $filtered_modules = [];
1178
+
1179
+ foreach ($modules as $module) {
1180
+ if (isset($included_conditions_lookup[$module->get_id()])) {
1181
+ $filtered_modules[] = $module;
1182
+ }
1183
+ }
1184
+
1185
+ return $filtered_modules;
1186
+ }
1187
+
1188
+ /**
1189
+ * @param string $post_type
1190
+ * @param string $name
1191
+ * @param mixed|null $default_value
1192
+ *
1193
+ * @return mixed|null
1194
+ */
1195
+ public static function get_option($post_type, $name, $default_value = null)
1196
+ {
1197
+ if (!self::types()->has($post_type)) {
1198
+ return $default_value;
1199
+ }
1200
+
1201
+ $value = get_option(self::OPTION_POST_TYPE_OPTIONS, []);
1202
+ $levels = explode('.', $post_type.'.'.$name);
1203
+
1204
+ foreach ($levels as $option_level) {
1205
+ if (!is_array($value) || !isset($value[$option_level])) {
1206
+ return $default_value;
1207
+ }
1208
+ $value = $value[$option_level];
1209
+ }
1210
+ return $value;
1211
+ }
1212
+
1213
+ /**
1214
+ * @param string $post_type
1215
+ * @param string $name
1216
+ * @param mixed $value
1217
+ *
1218
+ * @return bool
1219
+ */
1220
+ public static function save_option($post_type, $name, $value)
1221
+ {
1222
+ if (!self::types()->has($post_type)) {
1223
+ return false;
1224
+ }
1225
+
1226
+ $options = get_option(self::OPTION_POST_TYPE_OPTIONS, []);
1227
+ $keys = explode('.', $post_type.'.'.$name);
1228
+ $array = &$options;
1229
+
1230
+ foreach ($keys as $key) {
1231
+ if (!isset($array[$key]) || !is_array($array[$key])) {
1232
+ $array[$key] = [];
1233
+ }
1234
+ $array = &$array[$key];
1235
+ }
1236
+ $array = $value;
1237
+
1238
+ return update_option(self::OPTION_POST_TYPE_OPTIONS, $options);
1239
+ }
1240
+ }
1241
+ }
lib/wp-content-aware-engine/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
- /**/
1
+ <?php
2
+ /**/
lib/wp-content-aware-engine/meta.php CHANGED
@@ -1,238 +1,238 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- if (!class_exists('WPCAMeta')) {
12
- /**
13
- * Post Meta
14
- */
15
- class WPCAMeta
16
- {
17
-
18
- /**
19
- * Id
20
- * @var string
21
- */
22
- private $id;
23
-
24
- /**
25
- * Title
26
- * @var string
27
- */
28
- private $title;
29
-
30
- /**
31
- * Description
32
- * @var string
33
- */
34
- private $description;
35
-
36
- /**
37
- * Default value
38
- * @var mixed
39
- */
40
- private $default_value;
41
-
42
- /**
43
- * Input type
44
- * @var string
45
- */
46
- private $input_type;
47
-
48
- /**
49
- * Input list
50
- * @var string
51
- */
52
- private $input_list;
53
-
54
- /**
55
- * Callback to sanitize data before save
56
- * @var func
57
- */
58
- private $sanitizer;
59
-
60
- /**
61
- * Constructor
62
- *
63
- * @since 1.0
64
- */
65
- public function __construct(
66
- $id,
67
- $title,
68
- $default_value = '',
69
- $input_type = 'text',
70
- $input_list = [],
71
- $description = '',
72
- $sanitizer = ''
73
- ) {
74
- $this->id = $id;
75
- $this->title = $title;
76
- $this->default_value = $default_value;
77
- $this->input_type = $input_type;
78
- $this->input_list = $input_list;
79
- $this->description = $description;
80
- $this->sanitizer = $sanitizer;
81
- }
82
-
83
- /**
84
- * Get meta id
85
- *
86
- * @since 1.0
87
- * @return string
88
- */
89
- public function get_id()
90
- {
91
- return $this->id;
92
- }
93
- /**
94
- * Get meta title
95
- *
96
- * @since 1.0
97
- * @return string
98
- */
99
- public function get_title()
100
- {
101
- return $this->title;
102
- }
103
-
104
- /**
105
- * Get meta input type
106
- *
107
- * @since 1.0
108
- * @return string
109
- */
110
- public function get_input_type()
111
- {
112
- return $this->input_type;
113
- }
114
-
115
- /**
116
- * Get meta input list
117
- *
118
- * @since 1.0
119
- * @return array
120
- */
121
- public function get_input_list()
122
- {
123
- return $this->input_list;
124
- }
125
-
126
- /**
127
- * Set meta input list
128
- *
129
- * @since 1.0
130
- * @param array $input_list
131
- */
132
- public function set_input_list($input_list)
133
- {
134
- $this->input_list = $input_list;
135
- }
136
-
137
- /**
138
- * Get this meta data for a post
139
- *
140
- * @since 1.0
141
- * @param int $post_id
142
- * @param boolean $default_fallback
143
- * @param boolean $single
144
- * @return mixed
145
- */
146
- public function get_data($post_id, $default_fallback = false, $single = true)
147
- {
148
- $data = get_post_meta($post_id, WPCACore::PREFIX . $this->id, $single);
149
- if ($data == '' && $default_fallback) {
150
- $data = $this->default_value;
151
- }
152
- return $data;
153
- }
154
-
155
- /**
156
- * Update this meta data for a post
157
- *
158
- * @since 1.0
159
- * @param int $post_id
160
- * @param string $value
161
- * @return void
162
- */
163
- public function update($post_id, $value)
164
- {
165
- if ($this->input_type != 'multi') {
166
- update_post_meta($post_id, WPCACore::PREFIX . $this->id, $value);
167
- } else {
168
- add_post_meta($post_id, WPCACore::PREFIX . $this->id, $value);
169
- }
170
- }
171
-
172
- /**
173
- * Delete this meta data for a post
174
- *
175
- * @since 1.0
176
- * @param int $post_id
177
- * @param string $value
178
- * @return void
179
- */
180
- public function delete($post_id, $value = '')
181
- {
182
- delete_post_meta($post_id, WPCACore::PREFIX . $this->id, $value);
183
- }
184
-
185
- /**
186
- * Save data based on POST
187
- *
188
- * @since 4.2
189
- * @param int $post_id
190
- * @param string $value
191
- * @return void
192
- */
193
- public function save($post_id)
194
- {
195
- $value = isset($_POST[$this->id]) ? $_POST[$this->id] : '';
196
- if ($this->sanitizer && is_callable($this->sanitizer)) {
197
- $value = call_user_func($this->sanitizer, $value);
198
- }
199
- if ($this->input_type != 'multi') {
200
- //value can be 0 and valid
201
- if ($value != '') {
202
- $this->update($post_id, $value);
203
- } elseif ($this->get_data($post_id, false, true) != '') {
204
- $this->delete($post_id);
205
- }
206
- } else {
207
- $old = array_flip($this->get_data($post_id, false, false));
208
- if (is_array($value)) {
209
- foreach ($value as $meta) {
210
- if (isset($old[$meta])) {
211
- unset($old[$meta]);
212
- } else {
213
- $this->update($post_id, $meta);
214
- }
215
- }
216
- }
217
-
218
- foreach ($old as $meta => $v) {
219
- $this->delete($post_id, $meta);
220
- }
221
- }
222
- }
223
-
224
- /**
225
- * Get this meta data for a post
226
- * represented by entry in input list
227
- *
228
- * @since 1.0
229
- * @param int $post_id
230
- * @return mixed
231
- */
232
- public function get_list_data($post_id, $default_fallback = true)
233
- {
234
- $data = $this->get_data($post_id, $default_fallback);
235
- return isset($this->input_list[$data]) ? $this->input_list[$data] : null;
236
- }
237
- }
238
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ if (!class_exists('WPCAMeta')) {
12
+ /**
13
+ * Post Meta
14
+ */
15
+ class WPCAMeta
16
+ {
17
+
18
+ /**
19
+ * Id
20
+ * @var string
21
+ */
22
+ private $id;
23
+
24
+ /**
25
+ * Title
26
+ * @var string
27
+ */
28
+ private $title;
29
+
30
+ /**
31
+ * Description
32
+ * @var string
33
+ */
34
+ private $description;
35
+
36
+ /**
37
+ * Default value
38
+ * @var mixed
39
+ */
40
+ private $default_value;
41
+
42
+ /**
43
+ * Input type
44
+ * @var string
45
+ */
46
+ private $input_type;
47
+
48
+ /**
49
+ * Input list
50
+ * @var string
51
+ */
52
+ private $input_list;
53
+
54
+ /**
55
+ * Callback to sanitize data before save
56
+ * @var func
57
+ */
58
+ private $sanitizer;
59
+
60
+ /**
61
+ * Constructor
62
+ *
63
+ * @since 1.0
64
+ */
65
+ public function __construct(
66
+ $id,
67
+ $title,
68
+ $default_value = '',
69
+ $input_type = 'text',
70
+ $input_list = [],
71
+ $description = '',
72
+ $sanitizer = ''
73
+ ) {
74
+ $this->id = $id;
75
+ $this->title = $title;
76
+ $this->default_value = $default_value;
77
+ $this->input_type = $input_type;
78
+ $this->input_list = $input_list;
79
+ $this->description = $description;
80
+ $this->sanitizer = $sanitizer;
81
+ }
82
+
83
+ /**
84
+ * Get meta id
85
+ *
86
+ * @since 1.0
87
+ * @return string
88
+ */
89
+ public function get_id()
90
+ {
91
+ return $this->id;
92
+ }
93
+ /**
94
+ * Get meta title
95
+ *
96
+ * @since 1.0
97
+ * @return string
98
+ */
99
+ public function get_title()
100
+ {
101
+ return $this->title;
102
+ }
103
+
104
+ /**
105
+ * Get meta input type
106
+ *
107
+ * @since 1.0
108
+ * @return string
109
+ */
110
+ public function get_input_type()
111
+ {
112
+ return $this->input_type;
113
+ }
114
+
115
+ /**
116
+ * Get meta input list
117
+ *
118
+ * @since 1.0
119
+ * @return array
120
+ */
121
+ public function get_input_list()
122
+ {
123
+ return $this->input_list;
124
+ }
125
+
126
+ /**
127
+ * Set meta input list
128
+ *
129
+ * @since 1.0
130
+ * @param array $input_list
131
+ */
132
+ public function set_input_list($input_list)
133
+ {
134
+ $this->input_list = $input_list;
135
+ }
136
+
137
+ /**
138
+ * Get this meta data for a post
139
+ *
140
+ * @since 1.0
141
+ * @param int $post_id
142
+ * @param boolean $default_fallback
143
+ * @param boolean $single
144
+ * @return mixed
145
+ */
146
+ public function get_data($post_id, $default_fallback = false, $single = true)
147
+ {
148
+ $data = get_post_meta($post_id, WPCACore::PREFIX . $this->id, $single);
149
+ if ($data == '' && $default_fallback) {
150
+ $data = $this->default_value;
151
+ }
152
+ return $data;
153
+ }
154
+
155
+ /**
156
+ * Update this meta data for a post
157
+ *
158
+ * @since 1.0
159
+ * @param int $post_id
160
+ * @param string $value
161
+ * @return void
162
+ */
163
+ public function update($post_id, $value)
164
+ {
165
+ if ($this->input_type != 'multi') {
166
+ update_post_meta($post_id, WPCACore::PREFIX . $this->id, $value);
167
+ } else {
168
+ add_post_meta($post_id, WPCACore::PREFIX . $this->id, $value);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Delete this meta data for a post
174
+ *
175
+ * @since 1.0
176
+ * @param int $post_id
177
+ * @param string $value
178
+ * @return void
179
+ */
180
+ public function delete($post_id, $value = '')
181
+ {
182
+ delete_post_meta($post_id, WPCACore::PREFIX . $this->id, $value);
183
+ }
184
+
185
+ /**
186
+ * Save data based on POST
187
+ *
188
+ * @since 4.2
189
+ * @param int $post_id
190
+ * @param string $value
191
+ * @return void
192
+ */
193
+ public function save($post_id)
194
+ {
195
+ $value = isset($_POST[$this->id]) ? $_POST[$this->id] : '';
196
+ if ($this->sanitizer && is_callable($this->sanitizer)) {
197
+ $value = call_user_func($this->sanitizer, $value);
198
+ }
199
+ if ($this->input_type != 'multi') {
200
+ //value can be 0 and valid
201
+ if ($value != '') {
202
+ $this->update($post_id, $value);
203
+ } elseif ($this->get_data($post_id, false, true) != '') {
204
+ $this->delete($post_id);
205
+ }
206
+ } else {
207
+ $old = array_flip($this->get_data($post_id, false, false));
208
+ if (is_array($value)) {
209
+ foreach ($value as $meta) {
210
+ if (isset($old[$meta])) {
211
+ unset($old[$meta]);
212
+ } else {
213
+ $this->update($post_id, $meta);
214
+ }
215
+ }
216
+ }
217
+
218
+ foreach ($old as $meta => $v) {
219
+ $this->delete($post_id, $meta);
220
+ }
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Get this meta data for a post
226
+ * represented by entry in input list
227
+ *
228
+ * @since 1.0
229
+ * @param int $post_id
230
+ * @return mixed
231
+ */
232
+ public function get_list_data($post_id, $default_fallback = true)
233
+ {
234
+ $data = $this->get_data($post_id, $default_fallback);
235
+ return isset($this->input_list[$data]) ? $this->input_list[$data] : null;
236
+ }
237
+ }
238
+ }
lib/wp-content-aware-engine/module/author.php CHANGED
@@ -1,96 +1,96 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- *
13
- * Author Module
14
- *
15
- * Detects if current content is:
16
- * a) post type written by any or specific author
17
- * b) any or specific author archive
18
- *
19
- */
20
- class WPCAModule_author extends WPCAModule_Base
21
- {
22
- public function __construct()
23
- {
24
- parent::__construct('author', __('Authors', WPCA_DOMAIN));
25
- $this->placeholder = __('All Authors', WPCA_DOMAIN);
26
- $this->default_value = $this->id;
27
- $this->query_name = 'ca';
28
- }
29
-
30
- /**
31
- * @inheritDoc
32
- */
33
- public function in_context()
34
- {
35
- return (is_singular() && !is_front_page()) || is_author();
36
- }
37
-
38
- /**
39
- * @inheritDoc
40
- */
41
- public function get_context_data()
42
- {
43
- global $post;
44
- return [
45
- $this->id,
46
- (string)(is_singular() ? $post->post_author : get_query_var('author'))
47
- ];
48
- }
49
-
50
- /**
51
- * @inheritDoc
52
- */
53
- protected function parse_query_args($args)
54
- {
55
- $new_args = [
56
- 'number' => $args['limit'],
57
- 'offset' => ($args['paged'] - 1) * $args['limit'],
58
- 'search' => $args['search'],
59
- 'fields' => ['ID','display_name'],
60
- 'orderby' => 'display_name',
61
- 'order' => 'ASC',
62
- 'include' => $args['include'],
63
- 'count_total' => false,
64
- ];
65
- if ($new_args['search']) {
66
- if (false !== strpos($new_args['search'], '@')) {
67
- $new_args['search_columns'] = [ 'user_email' ];
68
- } elseif (is_numeric($new_args['search'])) {
69
- $new_args['search_columns'] = [ 'user_login', 'ID' ];
70
- } else {
71
- $new_args['search_columns'] = [ 'user_nicename', 'user_login', 'display_name' ];
72
- }
73
- $new_args['search'] = '*'.$new_args['search'].'*';
74
- }
75
- return $new_args;
76
- }
77
-
78
- /**
79
- * @inheritDoc
80
- */
81
- protected function _get_content($args = [])
82
- {
83
- $user_query = new WP_User_Query($args);
84
- $author_list = [];
85
-
86
- if ($user_query->results) {
87
- foreach ($user_query->get_results() as $user) {
88
- $author_list[] = [
89
- 'id' => $user->ID,
90
- 'text' => $user->display_name
91
- ];
92
- }
93
- }
94
- return $author_list;
95
- }
96
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ *
13
+ * Author Module
14
+ *
15
+ * Detects if current content is:
16
+ * a) post type written by any or specific author
17
+ * b) any or specific author archive
18
+ *
19
+ */
20
+ class WPCAModule_author extends WPCAModule_Base
21
+ {
22
+ public function __construct()
23
+ {
24
+ parent::__construct('author', __('Authors', WPCA_DOMAIN));
25
+ $this->placeholder = __('All Authors', WPCA_DOMAIN);
26
+ $this->default_value = $this->id;
27
+ $this->query_name = 'ca';
28
+ }
29
+
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ public function in_context()
34
+ {
35
+ return (is_singular() && !is_front_page()) || is_author();
36
+ }
37
+
38
+ /**
39
+ * @inheritDoc
40
+ */
41
+ public function get_context_data()
42
+ {
43
+ global $post;
44
+ return [
45
+ $this->id,
46
+ (string)(is_singular() ? $post->post_author : get_query_var('author'))
47
+ ];
48
+ }
49
+
50
+ /**
51
+ * @inheritDoc
52
+ */
53
+ protected function parse_query_args($args)
54
+ {
55
+ $new_args = [
56
+ 'number' => $args['limit'],
57
+ 'offset' => ($args['paged'] - 1) * $args['limit'],
58
+ 'search' => $args['search'],
59
+ 'fields' => ['ID','display_name'],
60
+ 'orderby' => 'display_name',
61
+ 'order' => 'ASC',
62
+ 'include' => $args['include'],
63
+ 'count_total' => false,
64
+ ];
65
+ if ($new_args['search']) {
66
+ if (false !== strpos($new_args['search'], '@')) {
67
+ $new_args['search_columns'] = [ 'user_email' ];
68
+ } elseif (is_numeric($new_args['search'])) {
69
+ $new_args['search_columns'] = [ 'user_login', 'ID' ];
70
+ } else {
71
+ $new_args['search_columns'] = [ 'user_nicename', 'user_login', 'display_name' ];
72
+ }
73
+ $new_args['search'] = '*'.$new_args['search'].'*';
74
+ }
75
+ return $new_args;
76
+ }
77
+
78
+ /**
79
+ * @inheritDoc
80
+ */
81
+ protected function _get_content($args = [])
82
+ {
83
+ $user_query = new WP_User_Query($args);
84
+ $author_list = [];
85
+
86
+ if ($user_query->results) {
87
+ foreach ($user_query->get_results() as $user) {
88
+ $author_list[] = [
89
+ 'id' => $user->ID,
90
+ 'text' => $user->display_name
91
+ ];
92
+ }
93
+ }
94
+ return $author_list;
95
+ }
96
+ }
lib/wp-content-aware-engine/module/bbpress.php CHANGED
@@ -1,99 +1,99 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- *
13
- * bbPress Module
14
- * Requires bbPress 2.5+
15
- *
16
- * Detects if current content is:
17
- * a) any or specific bbpress user profile
18
- *
19
- */
20
- class WPCAModule_bbpress extends WPCAModule_author
21
- {
22
- /**
23
- * @var string
24
- */
25
- protected $category = 'plugins';
26
-
27
- public function __construct()
28
- {
29
- parent::__construct();
30
- $this->id = 'bb_profile';
31
- $this->name = __('bbPress User Profiles', WPCA_DOMAIN);
32
- $this->placeholder = __('All Profiles', WPCA_DOMAIN);
33
- $this->default_value = $this->id;
34
- $this->query_name = 'cbb';
35
- }
36
-
37
- /**
38
- * @inheritDoc
39
- */
40
- public function initiate()
41
- {
42
- parent::initiate();
43
- add_filter(
44
- 'wpca/module/post_type/db-where',
45
- [$this,'add_forum_dependency']
46
- );
47
- }
48
-
49
- /**
50
- * @inheritDoc
51
- */
52
- public function can_enable()
53
- {
54
- return function_exists('bbp_get_version')
55
- && function_exists('bbp_is_single_user')
56
- && function_exists('bbp_get_displayed_user_id')
57
- && function_exists('bbp_get_forum_id');
58
- }
59
-
60
- /**
61
- * @inheritDoc
62
- */
63
- public function in_context()
64
- {
65
- return bbp_is_single_user();
66
- }
67
-
68
- /**
69
- * @inheritDoc
70
- */
71
- public function get_context_data()
72
- {
73
- $data = [$this->id];
74
- $data[] = bbp_get_displayed_user_id();
75
- return $data;
76
- }
77
-
78
- /**
79
- * Sidebars to be displayed with forums will also
80
- * be dislpayed with respective topics and replies
81
- *
82
- * @since 1.0
83
- * @param string $where
84
- * @return string
85
- */
86
- public function add_forum_dependency($where)
87
- {
88
- if (is_singular(['topic','reply'])) {
89
- $data = [
90
- get_post_type(),
91
- get_the_ID(),
92
- 'forum'
93
- ];
94
- $data[] = bbp_get_forum_id();
95
- $where = "(cp.meta_value IS NULL OR cp.meta_value IN('".implode("','", $data)."'))";
96
- }
97
- return $where;
98
- }
99
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ *
13
+ * bbPress Module
14
+ * Requires bbPress 2.5+
15
+ *
16
+ * Detects if current content is:
17
+ * a) any or specific bbpress user profile
18
+ *
19
+ */
20
+ class WPCAModule_bbpress extends WPCAModule_author
21
+ {
22
+ /**
23
+ * @var string
24
+ */
25
+ protected $category = 'plugins';
26
+
27
+ public function __construct()
28
+ {
29
+ parent::__construct();
30
+ $this->id = 'bb_profile';
31
+ $this->name = __('bbPress User Profiles', WPCA_DOMAIN);
32
+ $this->placeholder = __('All Profiles', WPCA_DOMAIN);
33
+ $this->default_value = $this->id;
34
+ $this->query_name = 'cbb';
35
+ }
36
+
37
+ /**
38
+ * @inheritDoc
39
+ */
40
+ public function initiate()
41
+ {
42
+ parent::initiate();
43
+ add_filter(
44
+ 'wpca/module/post_type/db-where',
45
+ [$this,'add_forum_dependency']
46
+ );
47
+ }
48
+
49
+ /**
50
+ * @inheritDoc
51
+ */
52
+ public function can_enable()
53
+ {
54
+ return function_exists('bbp_get_version')
55
+ && function_exists('bbp_is_single_user')
56
+ && function_exists('bbp_get_displayed_user_id')
57
+ && function_exists('bbp_get_forum_id');
58
+ }
59
+
60
+ /**
61
+ * @inheritDoc
62
+ */
63
+ public function in_context()
64
+ {
65
+ return bbp_is_single_user();
66
+ }
67
+
68
+ /**
69
+ * @inheritDoc
70
+ */
71
+ public function get_context_data()
72
+ {
73
+ $data = [$this->id];
74
+ $data[] = bbp_get_displayed_user_id();
75
+ return $data;
76
+ }
77
+
78
+ /**
79
+ * Sidebars to be displayed with forums will also
80
+ * be dislpayed with respective topics and replies
81
+ *
82
+ * @since 1.0
83
+ * @param string $where
84
+ * @return string
85
+ */
86
+ public function add_forum_dependency($where)
87
+ {
88
+ if (is_singular(['topic','reply'])) {
89
+ $data = [
90
+ get_post_type(),
91
+ get_the_ID(),
92
+ 'forum'
93
+ ];
94
+ $data[] = bbp_get_forum_id();
95
+ $where = "(cp.meta_value IS NULL OR cp.meta_value IN('".implode("','", $data)."'))";
96
+ }
97
+ return $where;
98
+ }
99
+ }
lib/wp-content-aware-engine/module/bp_member.php CHANGED
@@ -1,154 +1,154 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- *
13
- * BuddyPress Member Page Module
14
- * Requires BuddyPress 2.6+
15
- *
16
- * Detects if current content is:
17
- * a) a specific buddypress member page
18
- *
19
- */
20
- class WPCAModule_bp_member extends WPCAModule_Base
21
- {
22
- /**
23
- * @var string
24
- */
25
- protected $category = 'plugins';
26
-
27
- /**
28
- * Cached search string
29
- * @var string
30
- */
31
- protected $search_string;
32
-
33
- public function __construct()
34
- {
35
- parent::__construct('bp_member', __('BuddyPress Profiles', WPCA_DOMAIN));
36
- $this->default_value = 0;
37
- $this->placeholder = __('All Sections', WPCA_DOMAIN);
38
- $this->query_name = 'cbp';
39
- }
40
-
41
- /**
42
- * @inheritDoc
43
- */
44
- public function can_enable()
45
- {
46
- return defined('BP_VERSION');
47
- }
48
-
49
- /**
50
- * @inheritDoc
51
- */
52
- public function initiate()
53
- {
54
- parent::initiate();
55
- add_filter(
56
- 'wpca/module/static/in-context',
57
- [$this,'static_is_content']
58
- );
59
- }
60
-
61
- /**
62
- * @inheritDoc
63
- */
64
- protected function _get_content($args = [])
65
- {
66
- global $bp;
67
-
68
- if (isset($args['paged']) && $args['paged'] > 1) {
69
- return [];
70
- }
71
-
72
- $content = [];
73
- $is_search = isset($args['search']) && $args['search'];
74
-
75
- if (isset($bp->members->nav)) {
76
- foreach ($bp->members->nav->get_item_nav() as $item) {
77
- $content[$item->slug] = [
78
- 'id' => $item->slug,
79
- 'text' => strip_tags($item->name)
80
- ];
81
- if ($item->children) {
82
- $level = $is_search ? 0 : 1;
83
- foreach ($item->children as $child_item) {
84
- $content[$item->slug.'-'.$child_item->slug] = [
85
- 'text' => strip_tags($child_item->name),
86
- 'id' => $item->slug.'-'.$child_item->slug,
87
- 'level' => $level
88
- ];
89
- }
90
- }
91
- }
92
- }
93
-
94
- if (!empty($args['include'])) {
95
- $content = array_intersect_key($content, array_flip($args['include']));
96
- } elseif ($is_search) {
97
- $this->search_string = $args['search'];
98
- $content = array_filter($content, [$this,'_filter_search']);
99
- }
100
-
101
- return $content;
102
- }
103
-
104
- /**
105
- * Filter content based on search
106
- *
107
- * @since 2.0
108
- * @param string $value
109
- * @return boolean
110
- */
111
- protected function _filter_search($value)
112
- {
113
- return mb_stripos($value['text'], $this->search_string) !== false;
114
- }
115
-
116
- /**
117
- * @inheritDoc
118
- */
119
- public function in_context()
120
- {
121
- global $bp;
122
- return isset($bp->displayed_user->domain) && $bp->displayed_user->domain;
123
- }
124
-
125
- /**
126
- * @inheritDoc
127
- */
128
- public function get_context_data()
129
- {
130
- global $bp;
131
- $data = [$this->default_value];
132
- if (isset($bp->current_component)) {
133
- $data[] = $bp->current_component;
134
- if (isset($bp->current_action)) {
135
- $data[] = $bp->current_component.'-'.$bp->current_action;
136
- }
137
- }
138
- return $data;
139
- }
140
-
141
- /**
142
- * Avoid collision with content of static module
143
- * Somehow buddypress pages pass is_404()
144
- *
145
- * @since 1.0
146
- * @param boolean $content
147
- * @return boolean
148
- */
149
- public function static_is_content($content)
150
- {
151
- //TODO: test if deprecated
152
- return $content && !$this->in_context();
153
- }
154
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ *
13
+ * BuddyPress Member Page Module
14
+ * Requires BuddyPress 2.6+
15
+ *
16
+ * Detects if current content is:
17
+ * a) a specific buddypress member page
18
+ *
19
+ */
20
+ class WPCAModule_bp_member extends WPCAModule_Base
21
+ {
22
+ /**
23
+ * @var string
24
+ */
25
+ protected $category = 'plugins';
26
+
27
+ /**
28
+ * Cached search string
29
+ * @var string
30
+ */
31
+ protected $search_string;
32
+
33
+ public function __construct()
34
+ {
35
+ parent::__construct('bp_member', __('BuddyPress Profiles', WPCA_DOMAIN));
36
+ $this->default_value = 0;
37
+ $this->placeholder = __('All Sections', WPCA_DOMAIN);
38
+ $this->query_name = 'cbp';
39
+ }
40
+
41
+ /**
42
+ * @inheritDoc
43
+ */
44
+ public function can_enable()
45
+ {
46
+ return defined('BP_VERSION');
47
+ }
48
+
49
+ /**
50
+ * @inheritDoc
51
+ */
52
+ public function initiate()
53
+ {
54
+ parent::initiate();
55
+ add_filter(
56
+ 'wpca/module/static/in-context',
57
+ [$this,'static_is_content']
58
+ );
59
+ }
60
+
61
+ /**
62
+ * @inheritDoc
63
+ */
64
+ protected function _get_content($args = [])
65
+ {
66
+ global $bp;
67
+
68
+ if (isset($args['paged']) && $args['paged'] > 1) {
69
+ return [];
70
+ }
71
+
72
+ $content = [];
73
+ $is_search = isset($args['search']) && $args['search'];
74
+
75
+ if (isset($bp->members->nav)) {
76
+ foreach ($bp->members->nav->get_item_nav() as $item) {
77
+ $content[$item->slug] = [
78
+ 'id' => $item->slug,
79
+ 'text' => strip_tags($item->name)
80
+ ];
81
+ if ($item->children) {
82
+ $level = $is_search ? 0 : 1;
83
+ foreach ($item->children as $child_item) {
84
+ $content[$item->slug.'-'.$child_item->slug] = [
85
+ 'text' => strip_tags($child_item->name),
86
+ 'id' => $item->slug.'-'.$child_item->slug,
87
+ 'level' => $level
88
+ ];
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ if (!empty($args['include'])) {
95
+ $content = array_intersect_key($content, array_flip($args['include']));
96
+ } elseif ($is_search) {
97
+ $this->search_string = $args['search'];
98
+ $content = array_filter($content, [$this,'_filter_search']);
99
+ }
100
+
101
+ return $content;
102
+ }
103
+
104
+ /**
105
+ * Filter content based on search
106
+ *
107
+ * @since 2.0
108
+ * @param string $value
109
+ * @return boolean
110
+ */
111
+ protected function _filter_search($value)
112
+ {
113
+ return mb_stripos($value['text'], $this->search_string) !== false;
114
+ }
115
+
116
+ /**
117
+ * @inheritDoc
118
+ */
119
+ public function in_context()
120
+ {
121
+ global $bp;
122
+ return isset($bp->displayed_user->domain) && $bp->displayed_user->domain;
123
+ }
124
+
125
+ /**
126
+ * @inheritDoc
127
+ */
128
+ public function get_context_data()
129
+ {
130
+ global $bp;
131
+ $data = [$this->default_value];
132
+ if (isset($bp->current_component)) {
133
+ $data[] = $bp->current_component;
134
+ if (isset($bp->current_action)) {
135
+ $data[] = $bp->current_component.'-'.$bp->current_action;
136
+ }
137
+ }
138
+ return $data;
139
+ }
140
+
141
+ /**
142
+ * Avoid collision with content of static module
143
+ * Somehow buddypress pages pass is_404()
144
+ *
145
+ * @since 1.0
146
+ * @param boolean $content
147
+ * @return boolean
148
+ */
149
+ public function static_is_content($content)
150
+ {
151
+ //TODO: test if deprecated
152
+ return $content && !$this->in_context();
153
+ }
154
+ }
lib/wp-content-aware-engine/module/date.php CHANGED
@@ -1,77 +1,77 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- * Date Module
13
- *
14
- * @deprecated 9.1
15
- */
16
- class WPCAModule_date extends WPCAModule_Base
17
- {
18
-
19
- /**
20
- * Constructor
21
- */
22
- public function __construct()
23
- {
24
- parent::__construct(
25
- 'date',
26
- __('Dates', WPCA_DOMAIN)
27
- );
28
- $this->placeholder = __('Date Archives', WPCA_DOMAIN);
29
- $this->default_value = '0000-00-00';
30
- if (get_class() === 'WPCAModule_date') {
31
- $this->name .= ' (Legacy)';
32
- }
33
- //$this->query_name = 'cd';
34
- }
35
-
36
- /**
37
- * @inheritDoc
38
- */
39
- public function in_context()
40
- {
41
- return is_date();
42
- }
43
-
44
- /**
45
- * Get data from context
46
- *
47
- * @global object $wpdb
48
- * @since 1.0
49
- * @return array
50
- */
51
- public function get_context_data()
52
- {
53
- global $wpdb;
54
-
55
- $name = $this->get_query_name();
56
-
57
- return $wpdb->prepare(
58
- "($name.meta_value IS NULL OR '%s' = $name.meta_value)",
59
- '0000-00-00'
60
- );
61
- }
62
-
63
- /**
64
- * Get content
65
- *
66
- * @since 1.0
67
- * @return array
68
- */
69
- protected function _get_content($args = [])
70
- {
71
- $data = [];
72
- if ($args['include']) {
73
- $data = array_intersect_key($data, array_flip($args['include']));
74
- }
75
- return $data;
76
- }
77
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ * Date Module
13
+ *
14
+ * @deprecated 9.1
15
+ */
16
+ class WPCAModule_date extends WPCAModule_Base
17
+ {
18
+
19
+ /**
20
+ * Constructor
21
+ */
22
+ public function __construct()
23
+ {
24
+ parent::__construct(
25
+ 'date',
26
+ __('Dates', WPCA_DOMAIN)
27
+ );
28
+ $this->placeholder = __('Date Archives', WPCA_DOMAIN);
29
+ $this->default_value = '0000-00-00';
30
+ if (get_class() === 'WPCAModule_date') {
31
+ $this->name .= ' (Legacy)';
32
+ }
33
+ //$this->query_name = 'cd';
34
+ }
35
+
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ public function in_context()
40
+ {
41
+ return is_date();
42
+ }
43
+
44
+ /**
45
+ * Get data from context
46
+ *
47
+ * @global object $wpdb
48
+ * @since 1.0
49
+ * @return array
50
+ */
51
+ public function get_context_data()
52
+ {
53
+ global $wpdb;
54
+
55
+ $name = $this->get_query_name();
56
+
57
+ return $wpdb->prepare(
58
+ "($name.meta_value IS NULL OR '%s' = $name.meta_value)",
59
+ '0000-00-00'
60
+ );
61
+ }
62
+
63
+ /**
64
+ * Get content
65
+ *
66
+ * @since 1.0
67
+ * @return array
68
+ */
69
+ protected function _get_content($args = [])
70
+ {
71
+ $data = [];
72
+ if ($args['include']) {
73
+ $data = array_intersect_key($data, array_flip($args['include']));
74
+ }
75
+ return $data;
76
+ }
77
+ }
lib/wp-content-aware-engine/module/polylang.php CHANGED
@@ -1,111 +1,111 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- *
13
- * Polylang Module
14
- * Requires version 1.7+
15
- *
16
- * Detects if current content is:
17
- * a) in specific language
18
- *
19
- */
20
- class WPCAModule_polylang extends WPCAModule_Base
21
- {
22
-
23
- /**
24
- * @var string
25
- */
26
- protected $category = 'plugins';
27
-
28
- /**
29
- * Constructor
30
- */
31
- public function __construct()
32
- {
33
- parent::__construct('language', __('Languages', WPCA_DOMAIN));
34
- $this->query_name = 'cl';
35
- }
36
-
37
- /**
38
- * @inheritDoc
39
- */
40
- public function initiate()
41
- {
42
- parent::initiate();
43
- add_filter(
44
- 'pll_get_post_types',
45
- [$this,'remove_sidebar_multilingual']
46
- );
47
- }
48
-
49
- /**
50
- * @inheritDoc
51
- */
52
- public function can_enable()
53
- {
54
- return defined('POLYLANG_VERSION')
55
- && function_exists('pll_current_language');
56
- }
57
-
58
- /**
59
- * @inheritDoc
60
- */
61
- public function in_context()
62
- {
63
- return true;
64
- }
65
-
66
- /**
67
- * @inheritDoc
68
- */
69
- public function get_context_data()
70
- {
71
- $data = [$this->id];
72
- $data[] = pll_current_language();
73
- return $data;
74
- }
75
-
76
- /**
77
- * @inheritDoc
78
- */
79
- protected function _get_content($args = [])
80
- {
81
- global $polylang;
82
-
83
- $langs = [];
84
-
85
- if (isset($polylang->model) && method_exists($polylang->model, 'get_languages_list')) {
86
- foreach ($polylang->model->get_languages_list(['fields' => false]) as $lng) {
87
- $langs[$lng->slug] = $lng->name;
88
- }
89
- }
90
-
91
- if ($args['include']) {
92
- $langs = array_intersect_key($langs, array_flip($args['include']));
93
- }
94
- return $langs;
95
- }
96
-
97
- /**
98
- * Remove sidebars from multilingual list
99
- *
100
- * @since 1.0
101
- * @param array $post_types
102
- * @return array
103
- */
104
- public function remove_sidebar_multilingual($post_types)
105
- {
106
- foreach (WPCACore::types() as $post_type => $module) {
107
- unset($post_types[$post_type]);
108
- }
109
- return $post_types;
110
- }
111
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ *
13
+ * Polylang Module
14
+ * Requires version 1.7+
15
+ *
16
+ * Detects if current content is:
17
+ * a) in specific language
18
+ *
19
+ */
20
+ class WPCAModule_polylang extends WPCAModule_Base
21
+ {
22
+
23
+ /**
24
+ * @var string
25
+ */
26
+ protected $category = 'plugins';
27
+
28
+ /**
29
+ * Constructor
30
+ */
31
+ public function __construct()
32
+ {
33
+ parent::__construct('language', __('Languages', WPCA_DOMAIN));
34
+ $this->query_name = 'cl';
35
+ }
36
+
37
+ /**
38
+ * @inheritDoc
39
+ */
40
+ public function initiate()
41
+ {
42
+ parent::initiate();
43
+ add_filter(
44
+ 'pll_get_post_types',
45
+ [$this,'remove_sidebar_multilingual']
46
+ );
47
+ }
48
+
49
+ /**
50
+ * @inheritDoc
51
+ */
52
+ public function can_enable()
53
+ {
54
+ return defined('POLYLANG_VERSION')
55
+ && function_exists('pll_current_language');
56
+ }
57
+
58
+ /**
59
+ * @inheritDoc
60
+ */
61
+ public function in_context()
62
+ {
63
+ return true;
64
+ }
65
+
66
+ /**
67
+ * @inheritDoc
68
+ */
69
+ public function get_context_data()
70
+ {
71
+ $data = [$this->id];
72
+ $data[] = pll_current_language();
73
+ return $data;
74
+ }
75
+
76
+ /**
77
+ * @inheritDoc
78
+ */
79
+ protected function _get_content($args = [])
80
+ {
81
+ global $polylang;
82
+
83
+ $langs = [];
84
+
85
+ if (isset($polylang->model) && method_exists($polylang->model, 'get_languages_list')) {
86
+ foreach ($polylang->model->get_languages_list(['fields' => false]) as $lng) {
87
+ $langs[$lng->slug] = $lng->name;
88
+ }
89
+ }
90
+
91
+ if ($args['include']) {
92
+ $langs = array_intersect_key($langs, array_flip($args['include']));
93
+ }
94
+ return $langs;
95
+ }
96
+
97
+ /**
98
+ * Remove sidebars from multilingual list
99
+ *
100
+ * @since 1.0
101
+ * @param array $post_types
102
+ * @return array
103
+ */
104
+ public function remove_sidebar_multilingual($post_types)
105
+ {
106
+ foreach (WPCACore::types() as $post_type => $module) {
107
+ unset($post_types[$post_type]);
108
+ }
109
+ return $post_types;
110
+ }
111
+ }
lib/wp-content-aware-engine/module/post_type.php CHANGED
@@ -1,527 +1,527 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
-
12
- /**
13
- *
14
- * Post Type Module
15
- *
16
- * Detects if current content is:
17
- * a) specific post type or specific post
18
- * b) specific post type archive or home
19
- *
20
- */
21
- class WPCAModule_post_type extends WPCAModule_Base
22
- {
23
- /**
24
- * @var string
25
- */
26
- protected $category = 'post_type';
27
-
28
- /**
29
- * Registered public post types
30
- *
31
- * @var array
32
- */
33
- private $_post_types;
34
-
35
- /**
36
- * Conditions to inherit from post ancestors
37
- * @var array
38
- */
39
- private $_post_ancestor_conditions;
40
-
41
- public function __construct()
42
- {
43
- parent::__construct('post_type', __('Post Types', WPCA_DOMAIN));
44
- $this->query_name = 'cp';
45
- }
46
-
47
- /**
48
- * @inheritDoc
49
- */
50
- public function initiate()
51
- {
52
- parent::initiate();
53
-
54
- add_action(
55
- 'transition_post_status',
56
- [$this,'post_ancestry_check'],
57
- 10,
58
- 3
59
- );
60
-
61
- if (is_admin()) {
62
- foreach ($this->post_types() as $post_type) {
63
- add_action(
64
- 'wp_ajax_wpca/module/'.$this->id.'-'.$post_type,
65
- [$this,'ajax_print_content']
66
- );
67
- }
68
- }
69
- }
70
-
71
- /**
72
- * @inheritDoc
73
- */
74
- protected function _get_content($args = [])
75
- {
76
- $walk_tree = false;
77
- $start = ($args['paged'] - 1) * $args['posts_per_page'];
78
- $end = $start + $args['posts_per_page'];
79
-
80
- //WordPress searches in title and content by default
81
- //We want to search in title and slug
82
- if (!empty($args['search'])) {
83
- $exclude_query = '';
84
- if (!empty($args['post__not_in'])) {
85
- $exclude_query = ' AND ID NOT IN ('.implode(',', $args['post__not_in']).')';
86
- }
87
-
88
- $columns = [
89
- ['post_title', 'LIKE', '%'.$args['search'].'%'],
90
- ['post_name', 'LIKE', '%'.$args['search'].'%'],
91
- ];
92
-
93
- if (is_numeric($args['search'])) {
94
- $columns[] = ['ID', '=', $args['search']];
95
- }
96
-
97
- $where = [];
98
- $values = [];
99
- foreach ($columns as $column_value) {
100
- list($column, $operator, $value) = $column_value;
101
- $prepared_value = is_numeric($value) ? '%d' : '%s';
102
- $where[] = "{$column} {$operator} '{$prepared_value}'";
103
- $values[] = $value;
104
- }
105
-
106
- //Using unprepared (safe) exclude because WP is not good at parsing arrays
107
- global $wpdb;
108
- $posts = $wpdb->get_results($wpdb->prepare(
109
- "
110
- SELECT ID, post_title, post_type, post_parent, post_status, post_password
111
- FROM {$wpdb->posts}
112
- WHERE (".implode(' OR ', $where).")
113
- AND post_status IN('".implode("','", $args['post_status'])."')
114
- AND post_type = '%s'
115
- $exclude_query
116
- ORDER BY post_title ASC
117
- LIMIT %d,%d
118
- ",
119
- array_merge($values, [
120
- $args['post_type'],
121
- $start,
122
- $args['posts_per_page']
123
- ])
124
- ));
125
- } else {
126
- if (is_post_type_hierarchical($args['post_type']) && !isset($args['post__in'])) {
127
- $args['posts_per_page'] = -1;
128
- $args['paged'] = 0;
129
- $args['orderby'] = 'menu_order title';
130
-
131
- $walk_tree = true;
132
- }
133
- $query = new WP_Query($args);
134
- $posts = $query->posts;
135
- }
136
-
137
- $retval = [];
138
-
139
- if ($walk_tree) {
140
- $pages_sorted = [];
141
- foreach ($posts as $post) {
142
- $pages_sorted[$post->post_parent][] = $post;
143
- }
144
- $i = 0;
145
- $this->_walk_tree($pages_sorted, $pages_sorted[0], $i, $start, $end, 0, $retval);
146
- } else {
147
- foreach ($posts as $post) {
148
- $retval[$post->ID] = $this->post_title($post);
149
- }
150
- }
151
-
152
- return $retval;
153
- }
154
-
155
- /**
156
- * Get hierarchical content with level param
157
- *
158
- * @since 3.7.2
159
- * @param array $all_pages
160
- * @param array $pages
161
- * @param int $i
162
- * @param int $start
163
- * @param int $end
164
- * @param int $level
165
- * @param array &$retval
166
- * @return void
167
- */
168
- protected function _walk_tree($all_pages, $pages, &$i, $start, $end, $level, &$retval)
169
- {
170
- foreach ($pages as $page) {
171
- if ($i >= $end) {
172
- break;
173
- }
174
-
175
- if ($i >= $start) {
176
- $retval[] = [
177
- 'id' => $page->ID,
178
- 'text' => $this->post_title($page),
179
- 'level' => $level
180
- ];
181
- }
182
-
183
- $i++;
184
-
185
- if (isset($all_pages[$page->ID])) {
186
- $this->_walk_tree($all_pages, $all_pages[$page->ID], $i, $start, $end, $level + 1, $retval);
187
- }
188
- }
189
- }
190
-
191
- /**
192
- * Get registered public post types
193
- *
194
- * @since 4.0
195
- * @return array
196
- */
197
- public function post_types()
198
- {
199
- if (!$this->_post_types) {
200
- // List public post types
201
- foreach (get_post_types(['public' => true], 'names') as $post_type) {
202
- $this->_post_types[$post_type] = $post_type;
203
- }
204
- }
205
- return $this->_post_types;
206
- }
207
-
208
- /**
209
- * @inheritDoc
210
- */
211
- public function get_group_data($group_data, $post_id)
212
- {
213
- $ids = get_post_custom_values(WPCACore::PREFIX . $this->id, $post_id);
214
- if ($ids) {
215
- $lookup = array_flip((array)$ids);
216
- foreach ($this->post_types() as $post_type) {
217
- $post_type_obj = get_post_type_object($post_type);
218
- $data = $this->get_content([
219
- 'include' => $ids,
220
- 'post_type' => $post_type
221
- ]);
222
-
223
- if ($data || isset($lookup[$post_type])) {
224
- $placeholder = $post_type_obj->labels->all_items;
225
- switch ($post_type) {
226
- case 'post':
227
- $placeholder .= ' / '.__('Blog Page', WPCA_DOMAIN);
228
- break;
229
- case 'product':
230
- $placeholder .= ' / '.__('Shop Page', WPCA_DOMAIN);
231
- break;
232
- default:
233
- if ($post_type_obj->has_archive) {
234
- $placeholder .= ' / '.sprintf(__('%s Archives', WPCA_DOMAIN), $post_type_obj->labels->singular_name);
235
- }
236
- break;
237
- }
238
-
239
- $group_data[$this->id.'-'.$post_type] = [
240
- 'label' => $post_type_obj->label,
241
- 'placeholder' => $placeholder,
242
- 'default_value' => $post_type
243
- ];
244
-
245
- if ($data) {
246
- $group_data[$this->id.'-'.$post_type]['data'] = $data;
247
- }
248
- }
249
- }
250
- }
251
- return $group_data;
252
- }
253
-
254
- /**
255
- * @inheritDoc
256
- */
257
- public function in_context()
258
- {
259
- return ((is_singular() || is_home()) && !is_front_page()) || is_post_type_archive();
260
- }
261
-
262
- /**
263
- * @inheritDoc
264
- */
265
- public function get_context_data()
266
- {
267
- if (is_singular()) {
268
- return [
269
- get_post_type(),
270
- get_queried_object_id()
271
- ];
272
- }
273
-
274
- // Home has post as default post type
275
- $post_type = get_query_var('post_type');
276
- if (is_array($post_type)) {
277
- $post_type = reset($post_type);
278
- } elseif (!$post_type) {
279
- $post_type = 'post';
280
- }
281
-
282
- return [
283
- $post_type
284
- ];
285
- }
286
-
287
- /**
288
- * @inheritDoc
289
- */
290
- protected function parse_query_args($args)
291
- {
292
- if (isset($args['item_object'])) {
293
- preg_match('/post_type-(.+)$/i', $args['item_object'], $matches);
294
- $post_type_name = isset($matches[1]) ? $matches[1] : '___';
295
- } else {
296
- $post_type_name = isset($args['post_type']) ? $args['post_type'] : 'category';
297
- }
298
-
299
- $exclude = [];
300
- if ($post_type_name == 'page' && 'page' == get_option('show_on_front')) {
301
- $exclude[] = intval(get_option('page_on_front'));
302
- $exclude[] = intval(get_option('page_for_posts'));
303
- }
304
-
305
- $post_status = ['publish','private','future','draft'];
306
- if ($post_type_name == 'attachment') {
307
- $post_status = ['inherit'];
308
- }
309
-
310
- $new_args = [
311
- 'post__not_in' => $exclude,
312
- 'post_type' => $post_type_name,
313
- 'post_status' => $post_status,
314
- 'orderby' => 'title',
315
- 'order' => 'ASC',
316
- 'paged' => $args['paged'],
317
- 'posts_per_page' => $args['limit'],
318
- 'search' => $args['search'],
319
- 'ignore_sticky_posts' => true,
320
- 'update_post_term_cache' => false,
321
- 'suppress_filters' => true,
322
- 'no_found_rows' => true,
323
- ];
324
-
325
- //future proof in case this is considered a bug https://core.trac.wordpress.org/ticket/28099
326
- if (!empty($args['include'])) {
327
- $new_args['post__in'] = $args['include'];
328
- }
329
-
330
- return $new_args;
331
- }
332
-
333
- /**
334
- * @inheritDoc
335
- */
336
- public function list_module($list)
337
- {
338
- foreach ($this->post_types() as $post_type) {
339
- $post_type_obj = get_post_type_object($post_type);
340
-
341
- $name = $post_type_obj->label;
342
- $placeholder = $post_type_obj->labels->all_items;
343
-
344
- switch ($post_type) {
345
- case 'post':
346
- $name .= ' / '.__('Blog', WPCA_DOMAIN);
347
- $placeholder .= ' / '.__('Blog Page', WPCA_DOMAIN);
348
- break;
349
- case 'product':
350
- $name .= ' / '.__('Shop', WPCA_DOMAIN);
351
- $placeholder .= ' / '.__('Shop Page', WPCA_DOMAIN);
352
- break;
353
- default:
354
- if ($post_type_obj->has_archive) {
355
- $placeholder .= ' / '.sprintf(__('%s Archives', WPCA_DOMAIN), $post_type_obj->labels->singular_name);
356
- }
357
- break;
358
- }
359
-
360
- $list[] = [
361
- 'id' => $this->id.'-'.$post_type,
362
- 'text' => $name,
363
- 'placeholder' => $placeholder,
364
- 'default_value' => $post_type
365
- ];
366
- }
367
- return $list;
368
- }
369
-
370
- /**
371
- * Get post title and state
372
- *
373
- * @since 3.7
374
- * @param WP_Post $post
375
- * @return string
376
- */
377
- public function post_title($post)
378
- {
379
- $post_states = [];
380
-
381
- if (!empty($post->post_password)) {
382
- $post_states['protected'] = __('Password protected');
383
- }
384
-
385
- if (is_sticky($post->ID)) {
386
- $post_states['sticky'] = __('Sticky');
387
- }
388
-
389
- switch ($post->post_status) {
390
- case 'private':
391
- $post_states['private'] = __('Private');
392
- break;
393
- case 'draft':
394
- $post_states['draft'] = __('Draft');
395
- break;
396
- case 'pending':
397
- /* translators: post state */
398
- $post_states['pending'] = _x('Pending', 'post state');
399
- break;
400
- case 'scheduled':
401
- $post_states['scheduled'] = __('Scheduled');
402
- break;
403
- default:
404
- break;
405
- }
406
-
407
- $post_title = $post->post_title ? $post->post_title : __('(no title)');
408
- $post_states = apply_filters('display_post_states', $post_states, $post);
409
-
410
- return $post_title . ' ' . ($post_states ? ' ('.implode(', ', $post_states).')' : '');
411
- }
412
-
413
- /**
414
- * @inheritDoc
415
- */
416
- public function save_data($post_id)
417
- {
418
- $meta_key = WPCACore::PREFIX . $this->id;
419
- $old = array_flip(get_post_meta($post_id, $meta_key, false));
420
- $new = [];
421
-
422
- foreach ($this->post_types() as $post_type) {
423
- $id = $this->id.'-'.$post_type;
424
- if (isset($_POST['conditions'][$id])) {
425
- $new = array_merge($new, $_POST['conditions'][$id]);
426
- }
427
- }
428
-
429
- if ($new) {
430
- //$new = array_unique($new);
431
- // Skip existing data or insert new data
432
- foreach ($new as $new_single) {
433
- if (isset($old[$new_single])) {
434
- unset($old[$new_single]);
435
- } else {
436
- add_post_meta($post_id, $meta_key, $new_single);
437
- }
438
- }
439
- // Remove existing data that have not been skipped
440
- foreach ($old as $old_key => $old_value) {
441
- delete_post_meta($post_id, $meta_key, $old_key);
442
- }
443
- } elseif (!empty($old)) {
444
- // Remove any old values when $new is empty
445
- delete_post_meta($post_id, $meta_key);
446
- }
447
- }
448
-
449
- /**
450
- * Check if post ancestors have sidebar conditions
451
- *
452
- * @since 1.0
453
- * @param string $new_status
454
- * @param string $old_status
455
- * @param WP_Post $post
456
- * @return void
457
- */
458
- public function post_ancestry_check($new_status, $old_status, $post)
459
- {
460
- if (!WPCACore::types()->has($post->post_type) && $post->post_type != WPCACore::TYPE_CONDITION_GROUP && $post->post_parent) {
461
- $status = [
462
- 'publish' => 1,
463
- 'private' => 1,
464
- 'future' => 1
465
- ];
466
-
467
- // Only new posts are relevant
468
- if (!isset($status[$old_status]) && isset($status[$new_status])) {
469
- $post_type = get_post_type_object($post->post_type);
470
- if ($post_type->hierarchical && $post_type->public) {
471
-
472
-
473
- // Get sidebars with post ancestor wanting to auto-select post
474
- $query = new WP_Query([
475
- 'post_type' => WPCACore::TYPE_CONDITION_GROUP,
476
- 'post_status' => [WPCACore::STATUS_OR,WPCACore::STATUS_EXCEPT,WPCACore::STATUS_PUBLISHED],
477
- 'meta_query' => [
478
- 'relation' => 'AND',
479
- [
480
- 'key' => WPCACore::PREFIX . 'autoselect',
481
- 'value' => 1,
482
- 'compare' => '='
483
- ],
484
- [
485
- 'key' => WPCACore::PREFIX . $this->id,
486
- 'value' => get_post_ancestors($post),
487
- 'type' => 'numeric',
488
- 'compare' => 'IN'
489
- ]
490
- ]
491
- ]);
492
-
493
- if ($query && $query->found_posts) {
494
-
495
- //Add conditions after Quick Select
496
- //otherwise they will be removed there
497
- $this->_post_ancestor_conditions = $query->posts;
498
- add_action(
499
- 'save_post_'.$post->post_type,
500
- [$this,'post_ancestry_add'],
501
- 99,
502
- 2
503
- );
504
- do_action('wpca/modules/auto-select/'.$this->category, $query->posts, $post);
505
- }
506
- }
507
- }
508
- }
509
- }
510
-
511
- /**
512
- * Add sidebar conditions from post ancestors
513
- *
514
- * @since 3.1.1
515
- * @param int $post_id
516
- * @param WP_Post $post
517
- * @return void
518
- */
519
- public function post_ancestry_add($post_id, $post)
520
- {
521
- if ($this->_post_ancestor_conditions) {
522
- foreach ($this->_post_ancestor_conditions as $condition) {
523
- add_post_meta($condition->ID, WPCACore::PREFIX.$this->id, $post_id);
524
- }
525
- }
526
- }
527
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+
12
+ /**
13
+ *
14
+ * Post Type Module
15
+ *
16
+ * Detects if current content is:
17
+ * a) specific post type or specific post
18
+ * b) specific post type archive or home
19
+ *
20
+ */
21
+ class WPCAModule_post_type extends WPCAModule_Base
22
+ {
23
+ /**
24
+ * @var string
25
+ */
26
+ protected $category = 'post_type';
27
+
28
+ /**
29
+ * Registered public post types
30
+ *
31
+ * @var array
32
+ */
33
+ private $_post_types;
34
+
35
+ /**
36
+ * Conditions to inherit from post ancestors
37
+ * @var array
38
+ */
39
+ private $_post_ancestor_conditions;
40
+
41
+ public function __construct()
42
+ {
43
+ parent::__construct('post_type', __('Post Types', WPCA_DOMAIN));
44
+ $this->query_name = 'cp';
45
+ }
46
+
47
+ /**
48
+ * @inheritDoc
49
+ */
50
+ public function initiate()
51
+ {
52
+ parent::initiate();
53
+
54
+ add_action(
55
+ 'transition_post_status',
56
+ [$this,'post_ancestry_check'],
57
+ 10,
58
+ 3
59
+ );
60
+
61
+ if (is_admin()) {
62
+ foreach ($this->post_types() as $post_type) {
63
+ add_action(
64
+ 'wp_ajax_wpca/module/'.$this->id.'-'.$post_type,
65
+ [$this,'ajax_print_content']
66
+ );
67
+ }
68
+ }
69
+ }
70
+
71
+ /**
72
+ * @inheritDoc
73
+ */
74
+ protected function _get_content($args = [])
75
+ {
76
+ $walk_tree = false;
77
+ $start = ($args['paged'] - 1) * $args['posts_per_page'];
78
+ $end = $start + $args['posts_per_page'];
79
+
80
+ //WordPress searches in title and content by default
81
+ //We want to search in title and slug
82
+ if (!empty($args['search'])) {
83
+ $exclude_query = '';
84
+ if (!empty($args['post__not_in'])) {
85
+ $exclude_query = ' AND ID NOT IN ('.implode(',', $args['post__not_in']).')';
86
+ }
87
+
88
+ $columns = [
89
+ ['post_title', 'LIKE', '%'.$args['search'].'%'],
90
+ ['post_name', 'LIKE', '%'.$args['search'].'%'],
91
+ ];
92
+
93
+ if (is_numeric($args['search'])) {
94
+ $columns[] = ['ID', '=', $args['search']];
95
+ }
96
+
97
+ $where = [];
98
+ $values = [];
99
+ foreach ($columns as $column_value) {
100
+ list($column, $operator, $value) = $column_value;
101
+ $prepared_value = is_numeric($value) ? '%d' : '%s';
102
+ $where[] = "{$column} {$operator} '{$prepared_value}'";
103
+ $values[] = $value;
104
+ }
105
+
106
+ //Using unprepared (safe) exclude because WP is not good at parsing arrays
107
+ global $wpdb;
108
+ $posts = $wpdb->get_results($wpdb->prepare(
109
+ "
110
+ SELECT ID, post_title, post_type, post_parent, post_status, post_password
111
+ FROM {$wpdb->posts}
112
+ WHERE (".implode(' OR ', $where).")
113
+ AND post_status IN('".implode("','", $args['post_status'])."')
114
+ AND post_type = '%s'
115
+ $exclude_query
116
+ ORDER BY post_title ASC
117
+ LIMIT %d,%d
118
+ ",
119
+ array_merge($values, [
120
+ $args['post_type'],
121
+ $start,
122
+ $args['posts_per_page']
123
+ ])
124
+ ));
125
+ } else {
126
+ if (is_post_type_hierarchical($args['post_type']) && !isset($args['post__in'])) {
127
+ $args['posts_per_page'] = -1;
128
+ $args['paged'] = 0;
129
+ $args['orderby'] = 'menu_order title';
130
+
131
+ $walk_tree = true;
132
+ }
133
+ $query = new WP_Query($args);
134
+ $posts = $query->posts;
135
+ }
136
+
137
+ $retval = [];
138
+
139
+ if ($walk_tree) {
140
+ $pages_sorted = [];
141
+ foreach ($posts as $post) {
142
+ $pages_sorted[$post->post_parent][] = $post;
143
+ }
144
+ $i = 0;
145
+ $this->_walk_tree($pages_sorted, $pages_sorted[0], $i, $start, $end, 0, $retval);
146
+ } else {
147
+ foreach ($posts as $post) {
148
+ $retval[$post->ID] = $this->post_title($post);
149
+ }
150
+ }
151
+
152
+ return $retval;
153
+ }
154
+
155
+ /**
156
+ * Get hierarchical content with level param
157
+ *
158
+ * @since 3.7.2
159
+ * @param array $all_pages
160
+ * @param array $pages
161
+ * @param int $i
162
+ * @param int $start
163
+ * @param int $end
164
+ * @param int $level
165
+ * @param array &$retval
166
+ * @return void
167
+ */
168
+ protected function _walk_tree($all_pages, $pages, &$i, $start, $end, $level, &$retval)
169
+ {
170
+ foreach ($pages as $page) {
171
+ if ($i >= $end) {
172
+ break;
173
+ }
174
+
175
+ if ($i >= $start) {
176
+ $retval[] = [
177
+ 'id' => $page->ID,
178
+ 'text' => $this->post_title($page),
179
+ 'level' => $level
180
+ ];
181
+ }
182
+
183
+ $i++;
184
+
185
+ if (isset($all_pages[$page->ID])) {
186
+ $this->_walk_tree($all_pages, $all_pages[$page->ID], $i, $start, $end, $level + 1, $retval);
187
+ }
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Get registered public post types
193
+ *
194
+ * @since 4.0
195
+ * @return array
196
+ */
197
+ public function post_types()
198
+ {
199
+ if (!$this->_post_types) {
200
+ // List public post types
201
+ foreach (get_post_types(['public' => true], 'names') as $post_type) {
202
+ $this->_post_types[$post_type] = $post_type;
203
+ }
204
+ }
205
+ return $this->_post_types;
206
+ }
207
+
208
+ /**
209
+ * @inheritDoc
210
+ */
211
+ public function get_group_data($group_data, $post_id)
212
+ {
213
+ $ids = get_post_custom_values(WPCACore::PREFIX . $this->id, $post_id);
214
+ if ($ids) {
215
+ $lookup = array_flip((array)$ids);
216
+ foreach ($this->post_types() as $post_type) {
217
+ $post_type_obj = get_post_type_object($post_type);
218
+ $data = $this->get_content([
219
+ 'include' => $ids,
220
+ 'post_type' => $post_type
221
+ ]);
222
+
223
+ if ($data || isset($lookup[$post_type])) {
224
+ $placeholder = $post_type_obj->labels->all_items;
225
+ switch ($post_type) {
226
+ case 'post':
227
+ $placeholder .= ' / '.__('Blog Page', WPCA_DOMAIN);
228
+ break;
229
+ case 'product':
230
+ $placeholder .= ' / '.__('Shop Page', WPCA_DOMAIN);
231
+ break;
232
+ default:
233
+ if ($post_type_obj->has_archive) {
234
+ $placeholder .= ' / '.sprintf(__('%s Archives', WPCA_DOMAIN), $post_type_obj->labels->singular_name);
235
+ }
236
+ break;
237
+ }
238
+
239
+ $group_data[$this->id.'-'.$post_type] = [
240
+ 'label' => $post_type_obj->label,
241
+ 'placeholder' => $placeholder,
242
+ 'default_value' => $post_type
243
+ ];
244
+
245
+ if ($data) {
246
+ $group_data[$this->id.'-'.$post_type]['data'] = $data;
247
+ }
248
+ }
249
+ }
250
+ }
251
+ return $group_data;
252
+ }
253
+
254
+ /**
255
+ * @inheritDoc
256
+ */
257
+ public function in_context()
258
+ {
259
+ return ((is_singular() || is_home()) && !is_front_page()) || is_post_type_archive();
260
+ }
261
+
262
+ /**
263
+ * @inheritDoc
264
+ */
265
+ public function get_context_data()
266
+ {
267
+ if (is_singular()) {
268
+ return [
269
+ get_post_type(),
270
+ get_queried_object_id()
271
+ ];
272
+ }
273
+
274
+ // Home has post as default post type
275
+ $post_type = get_query_var('post_type');
276
+ if (is_array($post_type)) {
277
+ $post_type = reset($post_type);
278
+ } elseif (!$post_type) {
279
+ $post_type = 'post';
280
+ }
281
+
282
+ return [
283
+ $post_type
284
+ ];
285
+ }
286
+
287
+ /**
288
+ * @inheritDoc
289
+ */
290
+ protected function parse_query_args($args)
291
+ {
292
+ if (isset($args['item_object'])) {
293
+ preg_match('/post_type-(.+)$/i', $args['item_object'], $matches);
294
+ $post_type_name = isset($matches[1]) ? $matches[1] : '___';
295
+ } else {
296
+ $post_type_name = isset($args['post_type']) ? $args['post_type'] : 'category';
297
+ }
298
+
299
+ $exclude = [];
300
+ if ($post_type_name == 'page' && 'page' == get_option('show_on_front')) {
301
+ $exclude[] = intval(get_option('page_on_front'));
302
+ $exclude[] = intval(get_option('page_for_posts'));
303
+ }
304
+
305
+ $post_status = ['publish','private','future','draft'];
306
+ if ($post_type_name == 'attachment') {
307
+ $post_status = ['inherit'];
308
+ }
309
+
310
+ $new_args = [
311
+ 'post__not_in' => $exclude,
312
+ 'post_type' => $post_type_name,
313
+ 'post_status' => $post_status,
314
+ 'orderby' => 'title',
315
+ 'order' => 'ASC',
316
+ 'paged' => $args['paged'],
317
+ 'posts_per_page' => $args['limit'],
318
+ 'search' => $args['search'],
319
+ 'ignore_sticky_posts' => true,
320
+ 'update_post_term_cache' => false,
321
+ 'suppress_filters' => true,
322
+ 'no_found_rows' => true,
323
+ ];
324
+
325
+ //future proof in case this is considered a bug https://core.trac.wordpress.org/ticket/28099
326
+ if (!empty($args['include'])) {
327
+ $new_args['post__in'] = $args['include'];
328
+ }
329
+
330
+ return $new_args;
331
+ }
332
+
333
+ /**
334
+ * @inheritDoc
335
+ */
336
+ public function list_module($list)
337
+ {
338
+ foreach ($this->post_types() as $post_type) {
339
+ $post_type_obj = get_post_type_object($post_type);
340
+
341
+ $name = $post_type_obj->label;
342
+ $placeholder = $post_type_obj->labels->all_items;
343
+
344
+ switch ($post_type) {
345
+ case 'post':
346
+ $name .= ' / '.__('Blog', WPCA_DOMAIN);
347
+ $placeholder .= ' / '.__('Blog Page', WPCA_DOMAIN);
348
+ break;
349
+ case 'product':
350
+ $name .= ' / '.__('Shop', WPCA_DOMAIN);
351
+ $placeholder .= ' / '.__('Shop Page', WPCA_DOMAIN);
352
+ break;
353
+ default:
354
+ if ($post_type_obj->has_archive) {
355
+ $placeholder .= ' / '.sprintf(__('%s Archives', WPCA_DOMAIN), $post_type_obj->labels->singular_name);
356
+ }
357
+ break;
358
+ }
359
+
360
+ $list[] = [
361
+ 'id' => $this->id.'-'.$post_type,
362
+ 'text' => $name,
363
+ 'placeholder' => $placeholder,
364
+ 'default_value' => $post_type
365
+ ];
366
+ }
367
+ return $list;
368
+ }
369
+
370
+ /**
371
+ * Get post title and state
372
+ *
373
+ * @since 3.7
374
+ * @param WP_Post $post
375
+ * @return string
376
+ */
377
+ public function post_title($post)
378
+ {
379
+ $post_states = [];
380
+
381
+ if (!empty($post->post_password)) {
382
+ $post_states['protected'] = __('Password protected');
383
+ }
384
+
385
+ if (is_sticky($post->ID)) {
386
+ $post_states['sticky'] = __('Sticky');
387
+ }
388
+
389
+ switch ($post->post_status) {
390
+ case 'private':
391
+ $post_states['private'] = __('Private');
392
+ break;
393
+ case 'draft':
394
+ $post_states['draft'] = __('Draft');
395
+ break;
396
+ case 'pending':
397
+ /* translators: post state */
398
+ $post_states['pending'] = _x('Pending', 'post state');
399
+ break;
400
+ case 'scheduled':
401
+ $post_states['scheduled'] = __('Scheduled');
402
+ break;
403
+ default:
404
+ break;
405
+ }
406
+
407
+ $post_title = $post->post_title ? $post->post_title : __('(no title)');
408
+ $post_states = apply_filters('display_post_states', $post_states, $post);
409
+
410
+ return $post_title . ' ' . ($post_states ? ' ('.implode(', ', $post_states).')' : '');
411
+ }
412
+
413
+ /**
414
+ * @inheritDoc
415
+ */
416
+ public function save_data($post_id)
417
+ {
418
+ $meta_key = WPCACore::PREFIX . $this->id;
419
+ $old = array_flip(get_post_meta($post_id, $meta_key, false));
420
+ $new = [];
421
+
422
+ foreach ($this->post_types() as $post_type) {
423
+ $id = $this->id.'-'.$post_type;
424
+ if (isset($_POST['conditions'][$id])) {
425
+ $new = array_merge($new, $_POST['conditions'][$id]);
426
+ }
427
+ }
428
+
429
+ if ($new) {
430
+ //$new = array_unique($new);
431
+ // Skip existing data or insert new data
432
+ foreach ($new as $new_single) {
433
+ if (isset($old[$new_single])) {
434
+ unset($old[$new_single]);
435
+ } else {
436
+ add_post_meta($post_id, $meta_key, $new_single);
437
+ }
438
+ }
439
+ // Remove existing data that have not been skipped
440
+ foreach ($old as $old_key => $old_value) {
441
+ delete_post_meta($post_id, $meta_key, $old_key);
442
+ }
443
+ } elseif (!empty($old)) {
444
+ // Remove any old values when $new is empty
445
+ delete_post_meta($post_id, $meta_key);
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Check if post ancestors have sidebar conditions
451
+ *
452
+ * @since 1.0
453
+ * @param string $new_status
454
+ * @param string $old_status
455
+ * @param WP_Post $post
456
+ * @return void
457
+ */
458
+ public function post_ancestry_check($new_status, $old_status, $post)
459
+ {
460
+ if (!WPCACore::types()->has($post->post_type) && $post->post_type != WPCACore::TYPE_CONDITION_GROUP && $post->post_parent) {
461
+ $status = [
462
+ 'publish' => 1,
463
+ 'private' => 1,
464
+ 'future' => 1
465
+ ];
466
+
467
+ // Only new posts are relevant
468
+ if (!isset($status[$old_status]) && isset($status[$new_status])) {
469
+ $post_type = get_post_type_object($post->post_type);
470
+ if ($post_type->hierarchical && $post_type->public) {
471
+
472
+
473
+ // Get sidebars with post ancestor wanting to auto-select post
474
+ $query = new WP_Query([
475
+ 'post_type' => WPCACore::TYPE_CONDITION_GROUP,
476
+ 'post_status' => [WPCACore::STATUS_OR,WPCACore::STATUS_EXCEPT,WPCACore::STATUS_PUBLISHED],
477
+ 'meta_query' => [
478
+ 'relation' => 'AND',
479
+ [
480
+ 'key' => WPCACore::PREFIX . 'autoselect',
481
+ 'value' => 1,
482
+ 'compare' => '='
483
+ ],
484
+ [
485
+ 'key' => WPCACore::PREFIX . $this->id,
486
+ 'value' => get_post_ancestors($post),
487
+ 'type' => 'numeric',
488
+ 'compare' => 'IN'
489
+ ]
490
+ ]
491
+ ]);
492
+
493
+ if ($query && $query->found_posts) {
494
+
495
+ //Add conditions after Quick Select
496
+ //otherwise they will be removed there
497
+ $this->_post_ancestor_conditions = $query->posts;
498
+ add_action(
499
+ 'save_post_'.$post->post_type,
500
+ [$this,'post_ancestry_add'],
501
+ 99,
502
+ 2
503
+ );
504
+ do_action('wpca/modules/auto-select/'.$this->category, $query->posts, $post);
505
+ }
506
+ }
507
+ }
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Add sidebar conditions from post ancestors
513
+ *
514
+ * @since 3.1.1
515
+ * @param int $post_id
516
+ * @param WP_Post $post
517
+ * @return void
518
+ */
519
+ public function post_ancestry_add($post_id, $post)
520
+ {
521
+ if ($this->_post_ancestor_conditions) {
522
+ foreach ($this->_post_ancestor_conditions as $condition) {
523
+ add_post_meta($condition->ID, WPCACore::PREFIX.$this->id, $post_id);
524
+ }
525
+ }
526
+ }
527
+ }
lib/wp-content-aware-engine/module/static.php CHANGED
@@ -1,92 +1,92 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- *
13
- * Static Pages Module
14
- *
15
- * Detects if current content is:
16
- * a) front page
17
- * b) search results
18
- * c) 404 page
19
- *
20
- */
21
- class WPCAModule_static extends WPCAModule_Base
22
- {
23
-
24
- /**
25
- * Cached search string
26
- * @var string
27
- */
28
- protected $search_string;
29
-
30
- public function __construct()
31
- {
32
- parent::__construct('static', __('Special Pages', WPCA_DOMAIN));
33
- $this->query_name = 'cs';
34
- }
35
-
36
- /**
37
- * @inheritDoc
38
- */
39
- protected function _get_content($args = [])
40
- {
41
- $static = [
42
- 'front-page' => __('Front Page', WPCA_DOMAIN),
43
- 'search' => __('Search Results', WPCA_DOMAIN),
44
- '404' => __('404 Page', WPCA_DOMAIN)
45
- ];
46
-
47
- if ($args['include']) {
48
- $static = array_intersect_key($static, array_flip($args['include']));
49
- } elseif ($args['search']) {
50
- $this->search_string = $args['search'];
51
- $static = array_filter($static, [$this,'_filter_search']);
52
- }
53
- return $static;
54
- }
55
-
56
- /**
57
- * Filter content based on search
58
- *
59
- * @since 2.0
60
- * @param string $value
61
- * @return boolean
62
- */
63
- protected function _filter_search($value)
64
- {
65
- return mb_stripos($value, $this->search_string) !== false;
66
- }
67
-
68
- /**
69
- * @inheritDoc
70
- */
71
- public function in_context()
72
- {
73
- return is_front_page() || is_search() || is_404();
74
- }
75
-
76
- /**
77
- * @inheritDoc
78
- */
79
- public function get_context_data()
80
- {
81
- if (is_front_page()) {
82
- $val = 'front-page';
83
- } elseif (is_search()) {
84
- $val = 'search';
85
- } else {
86
- $val = '404';
87
- }
88
- return [
89
- $val
90
- ];
91
- }
92
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ *
13
+ * Static Pages Module
14
+ *
15
+ * Detects if current content is:
16
+ * a) front page
17
+ * b) search results
18
+ * c) 404 page
19
+ *
20
+ */
21
+ class WPCAModule_static extends WPCAModule_Base
22
+ {
23
+
24
+ /**
25
+ * Cached search string
26
+ * @var string
27
+ */
28
+ protected $search_string;
29
+
30
+ public function __construct()
31
+ {
32
+ parent::__construct('static', __('Special Pages', WPCA_DOMAIN));
33
+ $this->query_name = 'cs';
34
+ }
35
+
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ protected function _get_content($args = [])
40
+ {
41
+ $static = [
42
+ 'front-page' => __('Front Page', WPCA_DOMAIN),
43
+ 'search' => __('Search Results', WPCA_DOMAIN),
44
+ '404' => __('404 Page', WPCA_DOMAIN)
45
+ ];
46
+
47
+ if ($args['include']) {
48
+ $static = array_intersect_key($static, array_flip($args['include']));
49
+ } elseif ($args['search']) {
50
+ $this->search_string = $args['search'];
51
+ $static = array_filter($static, [$this,'_filter_search']);
52
+ }
53
+ return $static;
54
+ }
55
+
56
+ /**
57
+ * Filter content based on search
58
+ *
59
+ * @since 2.0
60
+ * @param string $value
61
+ * @return boolean
62
+ */
63
+ protected function _filter_search($value)
64
+ {
65
+ return mb_stripos($value, $this->search_string) !== false;
66
+ }
67
+
68
+ /**
69
+ * @inheritDoc
70
+ */
71
+ public function in_context()
72
+ {
73
+ return is_front_page() || is_search() || is_404();
74
+ }
75
+
76
+ /**
77
+ * @inheritDoc
78
+ */
79
+ public function get_context_data()
80
+ {
81
+ if (is_front_page()) {
82
+ $val = 'front-page';
83
+ } elseif (is_search()) {
84
+ $val = 'search';
85
+ } else {
86
+ $val = '404';
87
+ }
88
+ return [
89
+ $val
90
+ ];
91
+ }
92
+ }
lib/wp-content-aware-engine/module/weglot.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ *
13
+ * WeGlot Module
14
+ *
15
+ * Detects if current content is:
16
+ * a) in specific language
17
+ *
18
+ */
19
+ class WPCAModule_weglot extends WPCAModule_Base
20
+ {
21
+ /**
22
+ * @var string
23
+ */
24
+ protected $category = 'plugins';
25
+
26
+ public function __construct()
27
+ {
28
+ parent::__construct('language', __('Languages', WPCA_DOMAIN));
29
+ $this->query_name = 'cl';
30
+ }
31
+
32
+ /**
33
+ * @inheritDoc
34
+ */
35
+ public function in_context()
36
+ {
37
+ return true;
38
+ }
39
+
40
+ /**
41
+ * @inheritDoc
42
+ */
43
+ public function can_enable()
44
+ {
45
+ return defined('WEGLOT_VERSION')
46
+ && function_exists('weglot_get_current_language')
47
+ && function_exists('weglot_get_original_language')
48
+ && function_exists('weglot_get_destination_languages')
49
+ && function_exists('weglot_get_languages_available');
50
+ }
51
+
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ public function get_context_data()
56
+ {
57
+ $data = [$this->id];
58
+ $current_language = weglot_get_current_language();
59
+ if ($current_language) {
60
+ $data[] = $current_language;
61
+ }
62
+ return $data;
63
+ }
64
+
65
+ /**
66
+ * @inheritDoc
67
+ */
68
+ protected function _get_content($args = [])
69
+ {
70
+ $langs = [];
71
+ $codes = [
72
+ weglot_get_original_language() => 1
73
+ ];
74
+ foreach (weglot_get_destination_languages() as $language) {
75
+ if (isset($language['language_to'])) {
76
+ $codes[$language['language_to']] = 1;
77
+ }
78
+ }
79
+
80
+ foreach (weglot_get_languages_available() as $language) {
81
+ if (isset($codes[$language->getInternalCode()])) {
82
+ $langs[$language->getInternalCode()] = $language->getEnglishName();
83
+ }
84
+ }
85
+
86
+ if ($args['include']) {
87
+ $langs = array_intersect_key($langs, array_flip($args['include']));
88
+ }
89
+ return $langs;
90
+ }
91
+ }
lib/wp-content-aware-engine/objectmanager.php CHANGED
@@ -1,145 +1,145 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- if (!class_exists('WPCAObjectManager')) {
12
- /**
13
- * Manage a list of objects nicely
14
- */
15
- class WPCAObjectManager implements IteratorAggregate
16
- {
17
-
18
- /**
19
- * List of objects
20
- *
21
- * @var array
22
- */
23
- private $objects = [];
24
-
25
- /**
26
- * Constructor
27
- *
28
- * @since 1.0
29
- */
30
- public function __construct()
31
- {
32
- }
33
-
34
- /**
35
- * Add object to the manager if key is
36
- * not already added
37
- *
38
- * @since 1.0
39
- * @param mixed $object
40
- * @param string $name
41
- * @return WPCAObjectManager
42
- */
43
- public function add($object, $name)
44
- {
45
- if (!$this->has($name)) {
46
- $this->set($object, $name);
47
- }
48
- return $this;
49
- }
50
-
51
- /**
52
- * Remove object with key from manager
53
- *
54
- * @since 1.0
55
- * @param string $name
56
- * @return void
57
- */
58
- public function remove($name)
59
- {
60
- unset($this->objects[$name]);
61
- }
62
-
63
- /**
64
- * Check if manager has key
65
- *
66
- * @since 1.0
67
- * @param string $name
68
- * @return boolean
69
- */
70
- public function has($name)
71
- {
72
- return isset($this->objects[$name]);
73
- }
74
-
75
- /**
76
- * Get object with key
77
- * Returns null if not found
78
- *
79
- * @since 1.0
80
- * @param string $name
81
- * @return mixed|null
82
- */
83
- public function get($name)
84
- {
85
- return $this->has($name) ? $this->objects[$name] : null;
86
- }
87
-
88
- /**
89
- * Add object to manager regardless if
90
- * key exists already
91
- *
92
- * @since 1.0
93
- * @param mixed $object
94
- * @param string $name
95
- */
96
- public function set($object, $name)
97
- {
98
- $this->objects[$name] = $object;
99
- }
100
-
101
- /**
102
- * Get all objects in manager
103
- *
104
- * @since 1.0
105
- * @return array
106
- */
107
- public function get_all()
108
- {
109
- return $this->objects;
110
- }
111
-
112
- /**
113
- * Set all objects in manager
114
- *
115
- * @since 1.0
116
- * @param array $objects
117
- */
118
- public function set_all($objects)
119
- {
120
- $this->objects = (array)$objects;
121
- }
122
-
123
- /**
124
- * Count objects
125
- *
126
- * @since 1.0
127
- * @return int
128
- */
129
- public function count()
130
- {
131
- return count($this->objects);
132
- }
133
-
134
- /**
135
- * Make objects traversable
136
- *
137
- * @since 4.2
138
- * @return ArrayIterator
139
- */
140
- public function getIterator()
141
- {
142
- return new ArrayIterator($this->objects);
143
- }
144
- }
145
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ if (!class_exists('WPCAObjectManager')) {
12
+ /**
13
+ * Manage a list of objects nicely
14
+ */
15
+ class WPCAObjectManager implements IteratorAggregate
16
+ {
17
+
18
+ /**
19
+ * List of objects
20
+ *
21
+ * @var array
22
+ */
23
+ private $objects = [];
24
+
25
+ /**
26
+ * Constructor
27
+ *
28
+ * @since 1.0
29
+ */
30
+ public function __construct()
31
+ {
32
+ }
33
+
34
+ /**
35
+ * Add object to the manager if key is
36
+ * not already added
37
+ *
38
+ * @since 1.0
39
+ * @param mixed $object
40
+ * @param string $name
41
+ * @return WPCAObjectManager
42
+ */
43
+ public function add($object, $name)
44
+ {
45
+ if (!$this->has($name)) {
46
+ $this->set($object, $name);
47
+ }
48
+ return $this;
49
+ }
50
+
51
+ /**
52
+ * Remove object with key from manager
53
+ *
54
+ * @since 1.0
55
+ * @param string $name
56
+ * @return void
57
+ */
58
+ public function remove($name)
59
+ {
60
+ unset($this->objects[$name]);
61
+ }
62
+
63
+ /**
64
+ * Check if manager has key
65
+ *
66
+ * @since 1.0
67
+ * @param string $name
68
+ * @return boolean
69
+ */
70
+ public function has($name)
71
+ {
72
+ return isset($this->objects[$name]);
73
+ }
74
+
75
+ /**
76
+ * Get object with key
77
+ * Returns null if not found
78
+ *
79
+ * @since 1.0
80
+ * @param string $name
81
+ * @return mixed|null
82
+ */
83
+ public function get($name)
84
+ {
85
+ return $this->has($name) ? $this->objects[$name] : null;
86
+ }
87
+
88
+ /**
89
+ * Add object to manager regardless if
90
+ * key exists already
91
+ *
92
+ * @since 1.0
93
+ * @param mixed $object
94
+ * @param string $name
95
+ */
96
+ public function set($object, $name)
97
+ {
98
+ $this->objects[$name] = $object;
99
+ }
100
+
101
+ /**
102
+ * Get all objects in manager
103
+ *
104
+ * @since 1.0
105
+ * @return array
106
+ */
107
+ public function get_all()
108
+ {
109
+ return $this->objects;
110
+ }
111
+
112
+ /**
113
+ * Set all objects in manager
114
+ *
115
+ * @since 1.0
116
+ * @param array $objects
117
+ */
118
+ public function set_all($objects)
119
+ {
120
+ $this->objects = (array)$objects;
121
+ }
122
+
123
+ /**
124
+ * Count objects
125
+ *
126
+ * @since 1.0
127
+ * @return int
128
+ */
129
+ public function count()
130
+ {
131
+ return count($this->objects);
132
+ }
133
+
134
+ /**
135
+ * Make objects traversable
136
+ *
137
+ * @since 4.2
138
+ * @return ArrayIterator
139
+ */
140
+ public function getIterator()
141
+ {
142
+ return new ArrayIterator($this->objects);
143
+ }
144
+ }
145
+ }
lib/wp-content-aware-engine/typemanager.php CHANGED
@@ -8,14 +8,12 @@
8
 
9
  defined('ABSPATH') || exit;
10
 
11
-
12
  if (!class_exists('WPCATypeManager')) {
13
  /**
14
  * Manage module objects
15
  */
16
  final class WPCATypeManager extends WPCAObjectManager
17
  {
18
-
19
  /**
20
  * Constructor
21
  */
@@ -65,11 +63,12 @@ if (!class_exists('WPCATypeManager')) {
65
  'qtranslate',
66
  'translatepress',
67
  'transposh',
 
68
  'wpml'
69
  ];
70
 
71
  foreach ($modules as $name) {
72
- $class_name = WPCACore::CLASS_PREFIX.'Module_'.$name;
73
 
74
  if (!class_exists($class_name)) {
75
  continue;
8
 
9
  defined('ABSPATH') || exit;
10
 
 
11
  if (!class_exists('WPCATypeManager')) {
12
  /**
13
  * Manage module objects
14
  */
15
  final class WPCATypeManager extends WPCAObjectManager
16
  {
 
17
  /**
18
  * Constructor
19
  */
63
  'qtranslate',
64
  'translatepress',
65
  'transposh',
66
+ 'weglot',
67
  'wpml'
68
  ];
69
 
70
  foreach ($modules as $name) {
71
+ $class_name = WPCACore::CLASS_PREFIX . 'Module_' . $name;
72
 
73
  if (!class_exists($class_name)) {
74
  continue;
lib/wp-content-aware-engine/view.php CHANGED
@@ -1,124 +1,124 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
-
9
- defined('ABSPATH') || exit;
10
-
11
- /**
12
- * View Class
13
- */
14
- class WPCAView
15
- {
16
-
17
- /**
18
- * Path to view template
19
- *
20
- * @var string
21
- */
22
- private $_path;
23
-
24
- /**
25
- * Parameters for view template
26
- *
27
- * @var array
28
- */
29
- private $_params;
30
-
31
- /**
32
- * Template content
33
- *
34
- * @var string
35
- */
36
- private $_content;
37
-
38
- /**
39
- * Constructor
40
- *
41
- * @since 1.0
42
- * @param string $path
43
- * @param array $params
44
- */
45
- private function __construct($path, $params = [])
46
- {
47
- $this->_path = $path;
48
- $this->_params = $params;
49
- }
50
-
51
- /**
52
- * Create instance of view
53
- *
54
- * @since 1.0
55
- * @param string $name
56
- * @param array $params
57
- * @return WPCAView
58
- */
59
- public static function make($name, $params = [])
60
- {
61
- return new self($name, $params);
62
- }
63
-
64
- /**
65
- * Add possibility to set params dynamically
66
- *
67
- * @since 1.0
68
- * @param string $method
69
- * @param array $args
70
- * @return mixed
71
- */
72
- public function __call($method, $args)
73
- {
74
- if (substr($method, 0, 3) == 'set' && count($args) == 1) {
75
- $this->_params[strtolower(substr($method, 2))] = $args[0];
76
- return $this;
77
- }
78
- return call_user_func_array($method, $args);
79
- }
80
-
81
- /**
82
- * Get path to file
83
- *
84
- * @since 1.0
85
- * @return string
86
- */
87
- private function resolve_path()
88
- {
89
- if (stripos(strrev($this->_path), 'php.') === 0) {
90
- return $this->_path;
91
- }
92
- return WPCA_PATH.'view/'.str_replace('.', '/', $this->_path).'.php';
93
- }
94
-
95
- /**
96
- * Get content
97
- *
98
- * @since 1.0
99
- * @return string
100
- */
101
- private function get_content()
102
- {
103
- if (!$this->_content) {
104
- ob_start();
105
- if ($this->_params) {
106
- extract($this->_params);
107
- }
108
- require($this->resolve_path());
109
- $this->_content = ob_get_clean();
110
- }
111
- return $this->_content;
112
- }
113
-
114
- /**
115
- * Render content
116
- *
117
- * @since 1.0
118
- * @return void
119
- */
120
- public function render()
121
- {
122
- echo $this->get_content();
123
- }
124
- }
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+
9
+ defined('ABSPATH') || exit;
10
+
11
+ /**
12
+ * View Class
13
+ */
14
+ class WPCAView
15
+ {
16
+
17
+ /**
18
+ * Path to view template
19
+ *
20
+ * @var string
21
+ */
22
+ private $_path;
23
+
24
+ /**
25
+ * Parameters for view template
26
+ *
27
+ * @var array
28
+ */
29
+ private $_params;
30
+
31
+ /**
32
+ * Template content
33
+ *
34
+ * @var string
35
+ */
36
+ private $_content;
37
+
38
+ /**
39
+ * Constructor
40
+ *
41
+ * @since 1.0
42
+ * @param string $path
43
+ * @param array $params
44
+ */
45
+ private function __construct($path, $params = [])
46
+ {
47
+ $this->_path = $path;
48
+ $this->_params = $params;
49
+ }
50
+
51
+ /**
52
+ * Create instance of view
53
+ *
54
+ * @since 1.0
55
+ * @param string $name
56
+ * @param array $params
57
+ * @return WPCAView
58
+ */
59
+ public static function make($name, $params = [])
60
+ {
61
+ return new self($name, $params);
62
+ }
63
+
64
+ /**
65
+ * Add possibility to set params dynamically
66
+ *
67
+ * @since 1.0
68
+ * @param string $method
69
+ * @param array $args
70
+ * @return mixed
71
+ */
72
+ public function __call($method, $args)
73
+ {
74
+ if (substr($method, 0, 3) == 'set' && count($args) == 1) {
75
+ $this->_params[strtolower(substr($method, 2))] = $args[0];
76
+ return $this;
77
+ }
78
+ return call_user_func_array($method, $args);
79
+ }
80
+
81
+ /**
82
+ * Get path to file
83
+ *
84
+ * @since 1.0
85
+ * @return string
86
+ */
87
+ private function resolve_path()
88
+ {
89
+ if (stripos(strrev($this->_path), 'php.') === 0) {
90
+ return $this->_path;
91
+ }
92
+ return WPCA_PATH.'view/'.str_replace('.', '/', $this->_path).'.php';
93
+ }
94
+
95
+ /**
96
+ * Get content
97
+ *
98
+ * @since 1.0
99
+ * @return string
100
+ */
101
+ private function get_content()
102
+ {
103
+ if (!$this->_content) {
104
+ ob_start();
105
+ if ($this->_params) {
106
+ extract($this->_params);
107
+ }
108
+ require($this->resolve_path());
109
+ $this->_content = ob_get_clean();
110
+ }
111
+ return $this->_content;
112
+ }
113
+
114
+ /**
115
+ * Render content
116
+ *
117
+ * @since 1.0
118
+ * @return void
119
+ */
120
+ public function render()
121
+ {
122
+ echo $this->get_content();
123
+ }
124
+ }
lib/wp-content-aware-engine/view/condition_options.php CHANGED
@@ -1,42 +1,42 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
- ?>
9
  <li>
10
  <label><?php _e('Page Types', WPCA_DOMAIN); ?></label>
11
  <div class="wpca-pull-right">
12
  <select data-vm="value:exposure">
13
- <option value="0"><?php _e('Single Pages', WPCA_DOMAIN); ?>
14
  </option>
15
- <option value="2"><?php _e('Archive Pages', WPCA_DOMAIN); ?>
16
  </option>
17
- <option value="1"><?php _e('All', WPCA_DOMAIN); ?>
18
  </option>
19
  </select>
20
  </div>
21
  </li>
22
- <?php if (WPCACore::get_option($post_type, 'legacy.negated_conditions', false)) : ?>
23
  <li>
24
  <label class="cae-toggle">
25
  <input data-vm="checked:statusNegated" type="checkbox" />
26
- <div class="cae-toggle-bar wpca-pull-right"></div><?php _e('Negate conditions', WPCA_DOMAIN); ?>
27
  (Legacy)
28
  </label>
29
  </li>
30
- <?php endif; ?>
31
  <li>
32
  <label class="cae-toggle">
33
  <input data-vm="checked:statusExcept" type="checkbox" />
34
- <div class="cae-toggle-bar wpca-pull-right"></div><?php _e('Exception', WPCA_DOMAIN); ?>
35
  </label>
36
  </li>
37
  <li>
38
  <label class="cae-toggle">
39
  <input data-vm="checked:binary(_ca_autoselect)" type="checkbox" />
40
- <div class="cae-toggle-bar wpca-pull-right"></div><?php _e('Auto-select new children of selected items', WPCA_DOMAIN); ?>
41
  </label>
42
  </li>
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+ ?>
9
  <li>
10
  <label><?php _e('Page Types', WPCA_DOMAIN); ?></label>
11
  <div class="wpca-pull-right">
12
  <select data-vm="value:exposure">
13
+ <option value="0"><?php _e('Single Pages', WPCA_DOMAIN); ?>
14
  </option>
15
+ <option value="2"><?php _e('Archive Pages', WPCA_DOMAIN); ?>
16
  </option>
17
+ <option value="1"><?php _e('All', WPCA_DOMAIN); ?>
18
  </option>
19
  </select>
20
  </div>
21
  </li>
22
+ <?php if (WPCACore::get_option($post_type, 'legacy.negated_conditions', false)) : ?>
23
  <li>
24
  <label class="cae-toggle">
25
  <input data-vm="checked:statusNegated" type="checkbox" />
26
+ <div class="cae-toggle-bar wpca-pull-right"></div><?php _e('Negate conditions', WPCA_DOMAIN); ?>
27
  (Legacy)
28
  </label>
29
  </li>
30
+ <?php endif; ?>
31
  <li>
32
  <label class="cae-toggle">
33
  <input data-vm="checked:statusExcept" type="checkbox" />
34
+ <div class="cae-toggle-bar wpca-pull-right"></div><?php _e('Exception', WPCA_DOMAIN); ?>
35
  </label>
36
  </li>
37
  <li>
38
  <label class="cae-toggle">
39
  <input data-vm="checked:binary(_ca_autoselect)" type="checkbox" />
40
+ <div class="cae-toggle-bar wpca-pull-right"></div><?php _e('Auto-select new children of selected items', WPCA_DOMAIN); ?>
41
  </label>
42
  </li>
lib/wp-content-aware-engine/view/condition_template.php CHANGED
@@ -1,11 +1,11 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
- ?>
9
  <script type="text/template" id="wpca-template-condition">
10
  <div class="cas-group-sep"><span><?php _e('And', WPCA_DOMAIN); ?></span></div>
11
  <div class='cas-group-label'>
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+ ?>
9
  <script type="text/template" id="wpca-template-condition">
10
  <div class="cas-group-sep"><span><?php _e('And', WPCA_DOMAIN); ?></span></div>
11
  <div class='cas-group-label'>
lib/wp-content-aware-engine/view/group_template.php CHANGED
@@ -1,11 +1,11 @@
1
- <?php
2
- /**
3
- * @package wp-content-aware-engine
4
- * @author Joachim Jensen <joachim@dev.institute>
5
- * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
- */
8
- ?>
9
  <script type="text/template" id="wpca-template-group">
10
  <div class="cas-group-sep" data-vm="classes:{'wpca-group-negate':any(statusExcept,statusNegated)}">
11
  <span data-vm="text:statusLabel"></span>
@@ -20,12 +20,12 @@
20
  <div class="alignright">
21
  <span class="spinner"></span>
22
  <button class="js-wpca-save-group button button-small hide-if-js" type="button"><?php _e('Save Changes', WPCA_DOMAIN); ?></button>
23
- <?php do_action('wpca/group/actions', $post_type); ?>
24
  <button type="button" class="button button-small js-wpca-options"><span class="dashicons dashicons-admin-generic"></span> <?php _e('Settings', WPCA_DOMAIN) ?></button>
25
  </div>
26
  </div>
27
  <ul class="cas-group-options hide-if-js">
28
- <?php do_action('wpca/group/settings', $post_type); ?>
29
  </ul>
30
  <div class="cas-group-cell">
31
  <div class="cas-content" data-vm="collection:$collection"></div>
1
+ <?php
2
+ /**
3
+ * @package wp-content-aware-engine
4
+ * @author Joachim Jensen <joachim@dev.institute>
5
+ * @license GPLv3
6
+ * @copyright 2021 by Joachim Jensen
7
+ */
8
+ ?>
9
  <script type="text/template" id="wpca-template-group">
10
  <div class="cas-group-sep" data-vm="classes:{'wpca-group-negate':any(statusExcept,statusNegated)}">
11
  <span data-vm="text:statusLabel"></span>
20
  <div class="alignright">
21
  <span class="spinner"></span>
22
  <button class="js-wpca-save-group button button-small hide-if-js" type="button"><?php _e('Save Changes', WPCA_DOMAIN); ?></button>
23
+ <?php do_action('wpca/group/actions', $post_type); ?>
24
  <button type="button" class="button button-small js-wpca-options"><span class="dashicons dashicons-admin-generic"></span> <?php _e('Settings', WPCA_DOMAIN) ?></button>
25
  </div>
26
  </div>
27
  <ul class="cas-group-options hide-if-js">
28
+ <?php do_action('wpca/group/settings', $post_type); ?>
29
  </ul>
30
  <div class="cas-group-cell">
31
  <div class="cas-content" data-vm="collection:$collection"></div>
lib/wp-content-aware-engine/view/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
- /**/
1
+ <?php
2
+ /**/
lib/wp-pointer-tour/assets/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
lib/wp-pointer-tour/assets/js/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
lib/wp-pointer-tour/index.php CHANGED
@@ -1,2 +1,2 @@
1
- <?php
2
  /**/
1
+ <?php
2
  /**/
readme.txt CHANGED
@@ -1,11 +1,11 @@
1
  === Lightweight Widget Area Plugin - Content Aware Sidebars ===
2
  Contributors: intoxstudio, devinstitute, freemius
3
  Donate link: #
4
- Tags: custom sidebars, sidebar, hide sidebar, display widgets, widget, bbpress, buddypress, sidebar manager
5
  Requires at least: 5.0
6
  Requires PHP: 5.6
7
- Tested up to: 5.8
8
- Stable tag: 3.16.2
9
  License: GPLv3
10
 
11
  Display new sidebars on any post, page, category etc. Works with Classic Widgets, Block Widgets, and all themes!
@@ -32,7 +32,7 @@ If your website is big or in growth, CAS is the ideal solution for you.
32
  * Front Page, Search Results, 404 Not Found Page
33
  * bbPress Profiles, Forums & Topics
34
  * BuddyPress Profile Sections
35
- * Languages (WPML, Polylang, qTranslate X, TranslatePress, Transposh)
36
  * Pods Pages
37
 
38
  > **You can even combine conditions in any way you like! E.g. target all posts in a select category and written by a specific author.**
@@ -68,6 +68,7 @@ When adding new widgets to sidebars, **Live Search will find widgets instantly**
68
  * [TranslatePress](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
69
  * [Transposh Translation Filter](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
70
  * [WooCommerce](https://dev.institute/wordpress-sidebars/woocommerce/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
 
71
  * [WPML](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
72
 
73
  ###Customize Your Widget Areas Your Way
@@ -86,6 +87,7 @@ Make any sidebar or widget area sticky without hurting site performance. No jQue
86
  Display a widget area after a specific number or percentage of paragraphs in your content
87
  * **Even More Display Conditions**
88
  * Advanced Custom Fields data
 
89
  * URLS + wildcards
90
  * Referrer URLs
91
  * Date Archives & Content by publish date
@@ -184,6 +186,18 @@ Of course! Check out the links below:
184
 
185
  ####Highlights
186
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  = 3.16.2 =
188
 
189
  * [fixed] compatibility improvements
@@ -210,82 +224,4 @@ Of course! Check out the links below:
210
  * [new] option to display container widget only if conditions are met
211
  * [new] sticky support for ajax powered themes such as woodmart
212
 
213
- = 3.15.2 =
214
-
215
- * [new] performance improvements
216
- * [new] publishpress authors compatibility
217
- * [new] wordpress 5.7 support
218
- * [fixed] toolbar menu now supports theme areas registered without titles
219
- * [fixed] toolbar menu now displays nested custom sidebars properly
220
- * [updated] ui improvements for screen readers
221
- * [updated] wp-content-aware-engine library
222
- * [updated] freemius sdk
223
-
224
- **Pro Plan:**
225
-
226
- * [fixed] url condition compatible with wordpress installed in subdirectories
227
- * [fixed] acf condition supports more field types
228
-
229
- = 3.15.1 =
230
-
231
- * [fixed] toolbar menu compatibility with php5.6
232
-
233
- = 3.15 =
234
-
235
- * [new] toolbar menu to view conditions, theme areas, and sidebars for a given page
236
- * [new] better compatibility with retired custom sidebars plugin
237
- * [updated] ui improvements
238
- * [updated] wp-content-aware-engine library
239
-
240
- = 3.14.1 =
241
-
242
- * [fixed] sidebar quick select now displays all eligible sidebars
243
- * [updated] reinstate widgets screen if disabled by gutenberg plugin without user consent
244
-
245
- **Pro Plan:**
246
-
247
- * [fixed] styles would not always be loaded for container widget
248
-
249
- = 3.14 =
250
-
251
- * [new] ability to replace or merge with multiple sidebars
252
- * [new] wordpress 5.6 support
253
- * [new] minimum wordpress version 4.9
254
- * [fixed] some custom sidebar styles would not take effect in wp5.6+
255
- * [updated] wp-content-aware-engine library
256
-
257
- **Pro Plan:**
258
-
259
- * [new] time schedule displayed on overview screen
260
- * [fixed] conditions would not be duplicated with sidebar
261
- * [updated] improved time schedule ui
262
-
263
- = 3.13.1 =
264
-
265
- * [new] identical taxonomy names are now displayed with their post type
266
- * [fixed] taxonomy and attachment condition suggestions would not display all results
267
- * [updated] wp-content-aware-engine library
268
- * [updated] freemius sdk
269
-
270
- **Pro Plan:**
271
-
272
- * [new] support for auto-updates
273
-
274
- = 3.13 =
275
-
276
- * [new] exception conditions
277
- * [new] intelligent search by id in post type condition
278
- * [new] intelligent search by id, email in author condition
279
- * [new] performance improvements
280
- * [new] wordpress 5.5 support
281
- * [updated] wp-content-aware-engine library
282
- * [updated] freemius sdk
283
- * [deprecated] negated conditions
284
- * [deprecated] simple date archive condition
285
-
286
- **Pro Plan:**
287
-
288
- * [new] sticky support for storefront theme
289
- * [fixed] sticky left sidebars in generatepress
290
-
291
  See changelog.txt for previous changes.
1
  === Lightweight Widget Area Plugin - Content Aware Sidebars ===
2
  Contributors: intoxstudio, devinstitute, freemius
3
  Donate link: #
4
+ Tags: custom sidebars, sidebar, classic widgets, widget, bbpress, buddypress, sidebar manager
5
  Requires at least: 5.0
6
  Requires PHP: 5.6
7
+ Tested up to: 5.9
8
+ Stable tag: 3.17
9
  License: GPLv3
10
 
11
  Display new sidebars on any post, page, category etc. Works with Classic Widgets, Block Widgets, and all themes!
32
  * Front Page, Search Results, 404 Not Found Page
33
  * bbPress Profiles, Forums & Topics
34
  * BuddyPress Profile Sections
35
+ * Languages (Polylang, qTranslate X, TranslatePress, Transposh, Weglot, WPML)
36
  * Pods Pages
37
 
38
  > **You can even combine conditions in any way you like! E.g. target all posts in a select category and written by a specific author.**
68
  * [TranslatePress](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
69
  * [Transposh Translation Filter](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
70
  * [WooCommerce](https://dev.institute/wordpress-sidebars/woocommerce/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
71
+ * [Weglot](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
72
  * [WPML](https://dev.institute/wordpress-sidebars/multilingual-plugins/?utm_source=readme&utm_medium=referral&utm_content=integration&utm_campaign=cas)
73
 
74
  ###Customize Your Widget Areas Your Way
87
  Display a widget area after a specific number or percentage of paragraphs in your content
88
  * **Even More Display Conditions**
89
  * Advanced Custom Fields data
90
+ * Meta Box data
91
  * URLS + wildcards
92
  * Referrer URLs
93
  * Date Archives & Content by publish date
186
 
187
  ####Highlights
188
 
189
+ = 3.17 =
190
+
191
+ * [new] weglot display condition
192
+ * [new] wordpress 5.9 support
193
+
194
+ **Pro Plan:**
195
+
196
+ * [new] meta box display condition
197
+ * [new] infuse action now uses sidebar order option as hook priority
198
+ * [new] option to disable all widgets at once in widget cleaner
199
+ * [fixed] pagination in buddypress groups condition
200
+
201
  = 3.16.2 =
202
 
203
  * [fixed] compatibility improvements
224
  * [new] option to display container widget only if conditions are met
225
  * [new] sticky support for ajax powered themes such as woodmart
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  See changelog.txt for previous changes.
sidebar.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  defined('ABSPATH') || exit;
view/meta_box_action.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  CAS_Sidebar_Edit::form_field('handle');
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  CAS_Sidebar_Edit::form_field('handle');
view/meta_box_advanced.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  if (!EMPTY_TRASH_DAYS) {
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  if (!EMPTY_TRASH_DAYS) {
view/meta_box_design.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  $url = 'https://dev.institute/wordpress-sidebars/pricing/?utm_source=plugin&utm_medium=popup&utm_content=design&utm_campaign=cas';
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  $url = 'https://dev.institute/wordpress-sidebars/pricing/?utm_source=plugin&utm_medium=popup&utm_content=design&utm_campaign=cas';
view/meta_box_html.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  $data = CAS_App::instance()->manager()->metadata()->get('html')->get_data($post->ID, true);
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  $data = CAS_App::instance()->manager()->metadata()->get('html')->get_data($post->ID, true);
view/meta_box_schedule.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  global $wp_locale;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  global $wp_locale;
view/meta_box_status.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  $activate_date = $post->post_status == CAS_App::STATUS_SCHEDULED ? $post->post_date : '';
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  $activate_date = $post->post_status == CAS_App::STATUS_SCHEDULED ? $post->post_date : '';
view/meta_box_submit.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  $cas_fs = cas_fs();
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  $cas_fs = cas_fs();
view/meta_box_support.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  $locale = get_locale();
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  $locale = get_locale();
view/notice_review.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
  ?>
9
  <div class="notice notice-success updated js-cas-notice-review is-dismissible">
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
  ?>
9
  <div class="notice notice-success updated js-cas-notice-review is-dismissible">
view/sidebars_quick_select.php CHANGED
@@ -3,7 +3,7 @@
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
- * @copyright 2021 by Joachim Jensen
7
  */
8
 
9
  $i = 0;
3
  * @package Content Aware Sidebars
4
  * @author Joachim Jensen <joachim@dev.institute>
5
  * @license GPLv3
6
+ * @copyright 2022 by Joachim Jensen
7
  */
8
 
9
  $i = 0;