PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / trunk
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms vtrunk
3.53.0 3.52.0 3.51.0 3.50.0 3.45.0 3.38.0 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.40.0 3.40.1 3.41.0 3.42.0 3.43.0 3.44.0 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 All 177 releases
simple-tags / inc / class.admin.php

class.admin.php in Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms trunk, at inc/class.admin.php

1,573 lines 69.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // phpcs:disable Squiz.PHP.CommentedOutCode.Found,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Legacy TaxoPress file: keep behavior unchanged while documenting existing PHPCS exceptions.
4
5 // Include modules
6 require_once(TAXOPRESS_ABSPATH . '/modules/taxopress-ai/taxopress-ai.php');
7
8 class SimpleTags_Admin
9 {
10 // CPT and Taxonomy support
11 public static $post_type = 'post';
12 public static $post_type_name = '';
13 public static $taxonomy = '';
14 public static $taxo_name = '';
15 public static $admin_url = '';
16 public static $enabled_menus = [];
17
18 public const MENU_SLUG = 'st_options';
19
20 /**
21 * Initialize Admin
22 *
23 * @return void
24 * @author WebFactory Ltd
25 */
26 public function __construct()
27 {
28 // DB Upgrade ?
29 self::upgrade();
30
31 // Which taxo ?
32 self::register_taxonomy();
33
34 // Plugin installer
35 add_action('admin_init', array(__CLASS__, 'plugin_installer_upgrade_code'));
36
37 // Redirect on plugin activation
38 add_action('admin_init', array(__CLASS__, 'redirect_on_activate'));
39
40 // Admin menu
41 add_action('admin_menu', array(__CLASS__, 'admin_menu'));
42
43 //Admin footer credit
44 add_action('in_admin_footer', array(__CLASS__, 'taxopress_admin_footer'));
45
46 // Load JavaScript and CSS
47 add_action('admin_enqueue_scripts', array(__CLASS__, 'admin_enqueue_scripts'));
48
49 add_action('admin_enqueue_scripts', [$this, 'maybe_enqueue_frontend_assets_in_admin']);
50
51 add_action('admin_head', array($this, 'taxopress_hide_other_plugin_notices'));
52
53 add_action('wp_ajax_taxopress_search_posts', [$this, 'taxopress_search_posts_ajax']);
54
55 //ui class is used accross many pages. So, it should be here
56 require STAGS_DIR . '/inc/class.admin.taxonomies.ui.php';
57
58 $dashboard_screen = (isset($_GET['page']) && $_GET['page'] === 'st_dashboard') ? true : false;
59
60 //dashboard
61 require STAGS_DIR . '/inc/dashboard.php';
62 SimpleTags_Dashboard::get_instance();
63 self::$enabled_menus['st_dashboard'] = esc_html__('Dashboard', 'simple-tags');
64 if (1 === (int) SimpleTags_Plugin::get_option_value('active_taxonomies')) {
65 self::$enabled_menus['st_taxonomies'] = esc_html__('Taxonomies', 'simple-tags');
66 }
67
68 //hidden-terms
69 if (1 === (int) SimpleTags_Plugin::get_option_value('enable_hidden_terms')) {
70 require STAGS_DIR . '/inc/hidden-terms.php';
71 SimpleTags_Hidden_Terms::get_instance();
72 }
73
74 //terms
75 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_st_terms')) {
76 require STAGS_DIR . '/inc/terms-table.php';
77 require STAGS_DIR . '/inc/terms.php';
78 SimpleTags_Terms::get_instance();
79 self::$enabled_menus['st_terms'] = esc_html__('Terms', 'simple-tags');
80 }
81
82 //posts
83 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_st_posts')) {
84 require STAGS_DIR . '/inc/posts-table.php';
85 require STAGS_DIR . '/inc/posts.php';
86 SimpleTags_Posts::get_instance();
87 self::$enabled_menus['st_posts'] = esc_html__('Posts', 'simple-tags');
88 }
89
90 //tag clouds/ terms display
91 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_terms_display')) {
92 require_once STAGS_DIR . '/inc/tag-clouds-action.php';
93 require STAGS_DIR . '/inc/tag-clouds-table.php';
94 require STAGS_DIR . '/inc/tag-clouds.php';
95 SimpleTags_Tag_Clouds::get_instance();
96 }
97
98 //post tags
99 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_post_tags')) {
100 require_once STAGS_DIR . '/inc/post-tags-action.php';
101 require STAGS_DIR . '/inc/post-tags-table.php';
102 require STAGS_DIR . '/inc/post-tags.php';
103 SimpleTags_Post_Tags::get_instance();
104 }
105
106 //Related Posts
107 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_related_posts_new')) {
108 require_once STAGS_DIR . '/inc/related-posts-action.php';
109 require STAGS_DIR . '/inc/related-posts-table.php';
110 require STAGS_DIR . '/inc/related-posts.php';
111 SimpleTags_Related_Post::get_instance();
112 }
113
114 //Auto Links
115 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_auto_links')) {
116 require STAGS_DIR . '/inc/autolinks-table.php';
117 require STAGS_DIR . '/inc/autolinks.php';
118 SimpleTags_Autolink::get_instance();
119 }
120
121 //Auto Terms
122 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_auto_terms')) {
123 require STAGS_DIR . '/inc/autoterms-table.php';
124 require STAGS_DIR . '/inc/autoterms-logs-table.php';
125 require STAGS_DIR . '/inc/autoterms.php';
126 require STAGS_DIR . '/inc/autoterms_content.php';
127 require STAGS_DIR . '/inc/schedule.php';
128 require STAGS_DIR . '/inc/schedule-logs-table.php';
129 SimpleTags_Autoterms::get_instance();
130 SimpleTags_Autoterms_Content::get_instance();
131 SimpleTags_Autoterms_Schedule::get_instance();
132 self::$enabled_menus['st_autoterms'] = esc_html__('Auto Terms', 'simple-tags');
133 }
134
135 TaxoPress_AI_Module::get_instance();
136
137 //click terms option
138 require STAGS_DIR . '/inc/class.admin.clickterms.php';
139 new SimpleTags_Admin_ClickTags();
140
141 require STAGS_DIR . '/inc/class.admin.autocomplete.php';
142 new SimpleTags_Admin_Autocomplete();
143
144 // Mass edit terms
145 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_mass_edit')) {
146 require STAGS_DIR . '/inc/class.admin.mass.php';
147 new SimpleTags_Admin_Mass();
148 }
149
150 // Manage terms
151 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_manage')) {
152 require STAGS_DIR . '/inc/class-tag-table.php';
153 require STAGS_DIR . '/inc/class.admin.manage.php';
154 SimpleTags_Admin_Manage::get_instance();
155 }
156
157 require STAGS_DIR . '/inc/class.admin.post.php';
158 new SimpleTags_Admin_Post_Settings();
159
160 //taxonomies
161 if ($dashboard_screen || 1 === (int) SimpleTags_Plugin::get_option_value('active_taxonomies')) {
162 require_once STAGS_DIR . '/inc/taxonomies-action.php';
163 require STAGS_DIR . '/inc/class-taxonomies-table.php';
164 require STAGS_DIR . '/inc/taxonomies.php';
165 SimpleTags_Admin_Taxonomies::get_instance();
166 }
167
168 do_action('taxopress_admin_class_after_includes');
169
170 // Ajax action, JS Helper and admin action
171 add_action('wp_ajax_simpletags', array(__CLASS__, 'ajax_check'));
172 // Save dashboard feature
173 add_action('wp_ajax_save_taxopress_dashboard_feature_by_ajax', [__CLASS__, 'saveDashboardFeature']);
174 // Plugin action links
175 add_filter('plugin_action_links_' . plugin_basename(TAXOPRESS_FILE), [__CLASS__, 'plugin_settings_link']);
176 }
177
178 public function taxopress_hide_other_plugin_notices()
179 {
180 global $pagenow;
181
182 $taxopress_pages = taxopress_admin_pages();
183
184 if (isset($_GET['page']) && in_array($_GET['page'], $taxopress_pages)) {
185 echo '<style>
186 .notice:not(.taxopress-notice) {
187 display: none !important;
188 }
189 </style>';
190 }
191 }
192
193 /**
194 * Plugin action links
195 */
196 public static function plugin_settings_link($links)
197 {
198
199 foreach (self::$enabled_menus as $menu_slug => $menu_title) {
200 $links[] = '<a href="' . admin_url('admin.php?page=' . $menu_slug) . '">' . $menu_title . '</a>';
201 }
202
203 return $links;
204 }
205
206 /**
207 * Ajax for saving a feature from dashboard page
208 *
209 * Copied from PublishPress Blocks
210 *
211 * @return boolean,void Return false if failure, echo json on success
212 */
213 public static function saveDashboardFeature()
214 {
215 if (!current_user_can('admin_simple_tags')) {
216 wp_send_json(__('No permission!', 'simple-tags'), 403);
217 return false;
218 }
219
220 if (
221 !wp_verify_nonce(
222 sanitize_key(wp_unslash($_POST['nonce'])),
223 'st-admin-js'
224 )
225 ) {
226 wp_send_json(__('Invalid nonce token!', 'simple-tags'), 400);
227 return false;
228 }
229
230 if (empty($_POST['feature'])) {
231 wp_send_json(__('Error: wrong data', 'simple-tags'), 400);
232 return false;
233 }
234
235 $feature = sanitize_text_field(wp_unslash($_POST['feature']));
236 $new_state = sanitize_text_field(wp_unslash($_POST['new_state']));
237
238 SimpleTags_Plugin::set_option_value($feature, $new_state);
239
240 wp_send_json(true, 200);
241 }
242
243 /**
244 * Ajax Dispatcher
245 */
246 public static function ajax_check()
247 {
248 if (isset($_GET['stags_action']) && 'maybe_create_tag' === $_GET['stags_action'] && isset($_GET['tag'])) {
249 if (!check_ajax_referer('st-admin-js', 'nonce', false)) {
250 wp_send_json_error(['message' => __('Security check failed.', 'simple-tags')], 403);
251 }
252
253 $taxonomy = get_taxonomy('post_tag');
254 if (!$taxonomy || empty($taxonomy->cap->manage_terms) || !current_user_can($taxonomy->cap->manage_terms)) {
255 wp_send_json_error(['message' => __('Permission denied.', 'simple-tags')], 403);
256 }
257
258 self::maybe_create_tag(sanitize_text_field(wp_unslash($_GET['tag'])));
259 }
260 }
261
262 /**
263 * Maybe create a tag, and return the term_id
264 *
265 * @param string $tag_name
266 */
267 public static function maybe_create_tag($tag_name = '')
268 {
269 $term_id = 0;
270 //restore & in tag post
271 $tag_name = sanitize_text_field(str_replace("simpletagand", "&", $tag_name));
272 $result_term = term_exists($tag_name, 'post_tag', 0);
273 if (empty($result_term)) {
274 $result_term = wp_insert_term(
275 $tag_name,
276 'post_tag'
277 );
278
279 if (!is_wp_error($result_term)) {
280 $term_id = (int) $result_term['term_id'];
281 }
282 } else {
283 $term_id = (int) $result_term['term_id'];
284 }
285
286 wp_send_json_success(['term_id' => $term_id]);
287 }
288
289 /**
290 * Ajax for search posts
291 *
292 * @return void
293 */
294 public static function taxopress_search_posts_ajax()
295 {
296 if (!check_ajax_referer('st-admin-js', 'nonce', false)) {
297 wp_send_json_error(['message' => __('Security check failed.', 'simple-tags')]);
298 }
299
300 if (!current_user_can('simple_tags')) {
301 wp_send_json_error(['message' => __('Permission denied.', 'simple-tags')]);
302 }
303
304 $search = isset($_GET['search']) ? sanitize_text_field(wp_unslash($_GET['search'])) : '';
305 $paged = max(1, intval($_GET['page'] ?? 1));
306 $post_type = 'post';
307
308
309 $query = new WP_Query([
310 'post_type' => $post_type,
311 'post_status' => 'publish',
312 'posts_per_page' => 10,
313 'paged' => $paged,
314 'orderby' => 'date',
315 'order' => 'DESC',
316 'fields' => 'ids'
317 ]);
318
319 $results = [];
320 foreach ($query->posts as $post_id) {
321 $results[] = [
322 'id' => $post_id,
323 'text' => get_the_title($post_id)
324 ];
325 }
326
327 wp_send_json([
328 'results' => $results,
329 'more' => $paged < $query->max_num_pages
330 ]);
331 }
332
333 /**
334 * Test if current URL is not a DEV environnement
335 *
336 * Copy from monsterinsights_is_dev_url(), thanks !
337 *
338 * @param string $url
339 *
340 * @return bool
341 */
342 private static function is_dev_url($url = '')
343 {
344 $is_local_url = false;
345
346 // Trim it up
347 $url = strtolower(trim($url));
348 // Need to get the host...so let's add the scheme so we can use parse_url
349 if (false === strpos($url, 'http://') && false === strpos($url, 'https://')) {
350 $url = 'http://' . $url;
351 }
352
353 $url_parts = wp_parse_url($url);
354 $host = !empty($url_parts['host']) ? $url_parts['host'] : false;
355 if (!empty($url) && !empty($host)) {
356 if (false !== ip2long($host)) {
357 if (!filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
358 $is_local_url = true;
359 }
360 } elseif ('localhost' === $host) {
361 $is_local_url = true;
362 }
363
364 $tlds_to_check = array('.local', ':8888', ':8080', ':8081', '.invalid', '.example', '.test');
365 foreach ($tlds_to_check as $tld) {
366 if (false !== strpos($host, $tld)) {
367 $is_local_url = true;
368 break;
369 }
370 }
371
372 if (substr_count($host, '.') > 1) {
373 $subdomains_to_check = array('dev.', '*.staging.', 'beta.', 'test.');
374 foreach ($subdomains_to_check as $subdomain) {
375 $subdomain = str_replace('.', '(.)', $subdomain);
376 $subdomain = str_replace(array('*', '(.)'), '(.*)', $subdomain);
377 if (preg_match('/^(' . $subdomain . ')/', $host)) {
378 $is_local_url = true;
379 break;
380 }
381 }
382 }
383 }
384
385 return $is_local_url;
386 }
387
388 /**
389 * Init taxonomy class variable, load this action after all actions on init !
390 * Make a public static function for call it from children class...
391 *
392 * @return void
393 * @author WebFactory Ltd
394 */
395 public static function register_taxonomy()
396 {
397 add_action('init', array(__CLASS__, 'init'), 99999999);
398 }
399
400 /**
401 * Put in var class the current taxonomy choose by the user
402 *
403 * @return void
404 * @author WebFactory Ltd
405 */
406 public static function init()
407 {
408 self::$taxo_name = esc_html__('Post tags', 'simple-tags');
409 self::$post_type_name = esc_html__('Posts', 'simple-tags');
410
411 // Custom CPT ?
412 if (isset($_GET['cpt']) && !empty($_GET['cpt']) && post_type_exists(sanitize_text_field(wp_unslash($_GET['cpt'])))) {
413 $cpt = get_post_type_object(sanitize_text_field(wp_unslash($_GET['cpt'])));
414 self::$post_type = $cpt->name;
415 self::$post_type_name = $cpt->labels->name;
416 }
417
418 // Get compatible taxo for current post type
419 $compatible_taxonomies = get_object_taxonomies(self::$post_type);
420
421 // Custom taxo ?
422 if (isset($_GET['taxo']) && !empty($_GET['taxo']) && taxonomy_exists(sanitize_text_field(wp_unslash($_GET['taxo'])))) {
423 $taxo = get_taxonomy(sanitize_text_field(wp_unslash($_GET['taxo'])));
424
425 // Taxo is compatible ?
426 if (in_array($taxo->name, $compatible_taxonomies)) {
427 self::$taxonomy = $taxo->name;
428 self::$taxo_name = $taxo->labels->name;
429 } else {
430 unset($taxo);
431 }
432 }
433
434 // Default taxo from CPT...
435 if (!isset($taxo) && is_array($compatible_taxonomies) && !empty($compatible_taxonomies)) {
436 // Take post_tag before category
437 if (in_array('post_tag', $compatible_taxonomies, true)) {
438 $taxo = get_taxonomy('post_tag');
439 } else {
440 $taxo = get_taxonomy(current($compatible_taxonomies));
441 }
442
443 self::$taxonomy = $taxo->name;
444 self::$taxo_name = $taxo->labels->name;
445
446 // TODO: Redirect for help user that see the URL...
447 } elseif (!isset($taxo)) {
448 // TODO: We can't wp_die on init as it affect all pages
449 //wp_die(esc_html__('This custom post type not have taxonomies.', 'simple-tags'));
450 }
451
452 // Free memory
453 unset($cpt, $taxo);
454 }
455
456 /**
457 * Build HTML form for allow user to change taxonomy for the current page.
458 *
459 * @param string $page_value
460 *
461 * @return void
462 * @author Olatechpro
463 */
464 public static function boxSelectorTaxonomy($page_value = '')
465 {
466 echo '<div class="box-selector-taxonomy">' . PHP_EOL;
467
468 echo '<div class="change-taxo">' . PHP_EOL;
469 echo '<form action="" method="get">' . PHP_EOL;
470 if (!empty($page_value)) {
471 echo '<input type="hidden" name="page" value="' . esc_attr($page_value) . '" />' . PHP_EOL;
472 }
473 $taxonomies = [];
474 echo '<select name="cpt" id="cpt-select" class="st-cpt-select">' . PHP_EOL;
475 foreach (get_post_types(array('show_ui' => true), 'objects') as $post_type) {
476 $taxonomies_children = get_object_taxonomies($post_type->name);
477 if (empty($taxonomies_children)) {
478 continue;
479 }
480 $taxonomies[$post_type->name] = $taxonomies_children;
481 echo '<option ' . selected($post_type->name, self::$post_type, false) . ' value="' . esc_attr($post_type->name) . '">' . esc_html($post_type->labels->name) . '</option>' . PHP_EOL;
482 }
483 echo '</select>' . PHP_EOL;
484
485 echo '<select name="taxo" id="taxonomy-select" class="st-taxonomy-select">' . PHP_EOL;
486 foreach ($taxonomies as $parent_post => $taxonomy) {
487 if (count($taxonomy) > 0) {
488 foreach ($taxonomy as $tax_name) {
489 $taxonomy = get_taxonomy($tax_name);
490 if (false === (bool) $taxonomy->show_ui) {
491 continue;
492 }
493
494 if (self::$post_type == $parent_post) {
495 $class = "";
496 } else {
497 $class = "st-hide-content";
498 }
499
500 echo '<option ' . selected($tax_name, self::$taxonomy, false) . ' value="' . esc_attr($tax_name) . '" data-post="' . esc_attr($parent_post) . '" class="' . esc_attr($class) . '">' . esc_html($taxonomy->labels->name) . '</option>' . PHP_EOL;
501 }
502 }
503 }
504 echo '</select>' . PHP_EOL;
505
506 echo '<input type="submit" class="button" id="submit-change-taxo" value="' . esc_attr__('Change selection', 'simple-tags') . '" />' . PHP_EOL;
507 echo '</form>' . PHP_EOL;
508 echo '</div>' . PHP_EOL;
509 echo '</div>' . PHP_EOL;
510 }
511
512 public static function tabSelectorTaxonomy($tab_slug = '', $page_slug = '')
513 {
514 $current_taxo = isset($_GET["{$tab_slug}_taxo"]) ? sanitize_text_field(wp_unslash($_GET["{$tab_slug}_taxo"])) : get_option("{$tab_slug}_taxo", '');
515 $current_cpt = isset($_GET["{$tab_slug}_cpt"]) ? sanitize_text_field(wp_unslash($_GET["{$tab_slug}_cpt"])) : get_option("{$tab_slug}_cpt", '');
516
517 // Fallbacks if not yet set
518 if (empty($current_cpt)) {
519 foreach (get_post_types(['show_ui' => true], 'objects') as $pt) {
520 if (!empty(get_object_taxonomies($pt->name))) {
521 $current_cpt = $pt->name;
522 break;
523 }
524 }
525 }
526 if (empty($current_taxo) && $current_cpt) {
527 $possible_taxos = get_object_taxonomies($current_cpt);
528 if (!empty($possible_taxos)) {
529 $current_taxo = $possible_taxos[0];
530 }
531 }
532
533 // Save for use elsewhere
534 self::$post_type = $current_cpt;
535 self::$taxonomy = $current_taxo;
536
537 // Update $post_type_name dynamically
538 if ($current_cpt) {
539 $post_type_object = get_post_type_object($current_cpt);
540 if ($post_type_object) {
541 self::$post_type_name = $post_type_object->labels->name;
542 }
543 }
544
545 // Save to DB for persistence
546 update_option("{$tab_slug}_taxo", $current_taxo);
547 update_option("{$tab_slug}_cpt", $current_cpt);
548
549 // Build list of post types and taxonomies (only CPTs with taxonomies)
550 $taxonomies = [];
551 echo '<div class="box-selector-taxonomy tab-taxo-filter tab-taxo-filter-' . esc_attr($tab_slug) . '">' . PHP_EOL;
552 echo '<div class="change-taxo">' . PHP_EOL;
553
554 echo '<form action="' . esc_url(admin_url('admin.php')) . '" method="get">' . PHP_EOL;
555 $page = !empty($page_slug) ? $page_slug : (isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : 'st_manage');
556 echo '<input type="hidden" name="page" value="' . esc_attr($page) . '" />' . PHP_EOL;
557 echo '<input type="hidden" name="page" value="st_manage" />' . PHP_EOL;
558
559 if (!empty($tab_slug)) {
560 echo '<input type="hidden" name="tab" value="' . esc_attr($tab_slug) . '" />' . PHP_EOL;
561 }
562
563 // CPT dropdown
564 echo '<select name="' . esc_attr($tab_slug) . '_cpt" class="st-cpt-select st-cpt-select-' . esc_attr($tab_slug) . '">' . PHP_EOL;
565 foreach (get_post_types(['show_ui' => true], 'objects') as $post_type) {
566 $taxonomies_children = get_object_taxonomies($post_type->name);
567 if (empty($taxonomies_children)) {
568 continue;
569 }
570 $taxonomies[$post_type->name] = $taxonomies_children;
571 echo '<option ' . selected($post_type->name, $current_cpt, false) . ' value="' . esc_attr($post_type->name) . '">' . esc_html($post_type->labels->name) . '</option>' . PHP_EOL;
572 }
573 echo '</select>' . PHP_EOL;
574
575 // Taxonomy dropdown
576 echo '<select name="' . esc_attr($tab_slug) . '_taxo" class="st-taxonomy-select st-taxonomy-select-' . esc_attr($tab_slug) . '">' . PHP_EOL;
577 foreach ($taxonomies as $parent_post => $taxonomy_list) {
578 foreach ($taxonomy_list as $tax_name) {
579 $taxonomy = get_taxonomy($tax_name);
580 if (false === (bool) $taxonomy->show_ui) {
581 continue;
582 }
583 $class = ($parent_post === $current_cpt) ? '' : 'st-hide-content';
584
585 echo '<option ' . selected($tax_name, $current_taxo, false) .
586 ' value="' . esc_attr($tax_name) . '"' .
587 ' data-post="' . esc_attr($parent_post) . '"' .
588 ' class="' . esc_attr($class) . '">' .
589 esc_html($taxonomy->labels->name) .
590 '</option>' . PHP_EOL;
591 }
592 }
593 echo '</select>' . PHP_EOL;
594
595 echo '<input type="submit" class="button" value="' . esc_attr__('Change selection', 'simple-tags') . '" />' . PHP_EOL;
596 echo '</form>' . PHP_EOL;
597 echo '</div>' . PHP_EOL;
598 echo '</div>' . PHP_EOL;
599 }
600
601 public function maybe_enqueue_frontend_assets_in_admin()
602 {
603
604 $screen = get_current_screen();
605 if (!$screen) {
606 return;
607 }
608
609 if (strpos($screen->id, 'taxopress_page_') === false) {
610 return;
611 }
612
613 $is_edit_mode = isset($_GET['action']) && in_array($_GET['action'], ['edit'], true);
614 if (!$is_edit_mode) {
615 return;
616 }
617
618 $current_page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
619
620 // List of pages that need preview functionality
621 $preview_pages = [
622 'st_terms_display',
623 'st_related_posts',
624 'st_post_tags',
625 ];
626
627 if (!in_array($current_page, $preview_pages, true)) {
628 return;
629 }
630
631 if ((int) SimpleTags_Plugin::get_option_value('disable_admin_frontend_scripts') === 1) {
632 return;
633 }
634
635 if (! apply_filters('taxopress_load_admin_frontend_scripts', true)) {
636 return;
637 }
638
639 // Register and enqueue assets
640 wp_register_script('taxopress-frontend-js', STAGS_URL . '/assets/frontend/js/frontend.js', array('jquery'), STAGS_VERSION);
641 wp_register_style('taxopress-frontend-css', STAGS_URL . '/assets/frontend/css/frontend.css', array(), STAGS_VERSION, 'all');
642
643 // Enqueue the assets
644 wp_enqueue_script('taxopress-frontend-js');
645 wp_enqueue_style('taxopress-frontend-css');
646 }
647 /**
648 * Init somes JS and CSS need for TaxoPress.
649 *
650 * @return void
651 * @author WebFactory Ltd
652 */
653 public static function admin_enqueue_scripts()
654 {
655 global $pagenow;
656
657 $select_2_page = false;
658 if ((isset($_GET['page']) && in_array($_GET['page'], ['st_posts', 'st_terms', 'st_autolinks', 'st_autoterms', 'st_autoterms_schedule', 'st_terms_display', 'st_related_posts', 'st_post_tags', 'st_mass_terms'])) || in_array($pagenow, ['post.php', 'edit.php', 'post-new.php'])) {
659 $select_2_page = true;
660 }
661
662 do_action('taxopress_admin_class_before_assets_register');
663
664 //color picker style
665 wp_enqueue_style('wp-color-picker');
666
667 // Helper TaxoPress
668 wp_register_script('st-helper-add-tags', STAGS_URL . '/assets/js/helper-add-tags.js', array('jquery'), STAGS_VERSION);
669 wp_localize_script('st-helper-add-tags', 'stHelperAddTagsL10n', [
670 'nonce' => wp_create_nonce('st-admin-js'),
671 ]);
672 wp_register_script('st-helper-options', STAGS_URL . '/assets/js/helper-options.js', array('jquery', 'wp-color-picker'), STAGS_VERSION);
673
674 // Register CSS
675 wp_register_style('st-admin', STAGS_URL . '/assets/css/admin.css', array(), STAGS_VERSION, 'all');
676 wp_register_style('st-admin-global', STAGS_URL . '/assets/css/admin-global.css', array(), STAGS_VERSION, 'all');
677
678 // Register tooltip
679 wp_register_script(
680 'taxopress-admin-tooltip',
681 STAGS_URL . '/assets/lib/tooltip/js/tooltip.min.js',
682 ['jquery'],
683 STAGS_VERSION
684 );
685
686 wp_register_style(
687 'taxopress-admin-tooltip',
688 STAGS_URL . '/assets/lib/tooltip/css/tooltip.min.css',
689 [],
690 STAGS_VERSION
691 );
692
693 //enqueue tooltip
694 wp_enqueue_script('taxopress-admin-tooltip');
695 wp_enqueue_style('taxopress-admin-tooltip');
696
697 // Register Select 2
698 wp_register_script(
699 'taxopress-admin-select2',
700 STAGS_URL . '/assets/lib/select2/js/select2.full.min.js',
701 ['jquery'],
702 STAGS_VERSION
703 );
704
705 wp_register_style(
706 'taxopress-admin-select2',
707 STAGS_URL . '/assets/lib/select2/css/select2.min.css',
708 [],
709 STAGS_VERSION
710 );
711
712 if ($select_2_page) {
713 wp_enqueue_script('taxopress-admin-select2');
714 wp_enqueue_style('taxopress-admin-select2');
715 }
716
717 //Register and enqueue admin js
718 $script_dependencies = ['jquery'];
719 if ($select_2_page) {
720 $script_dependencies[] = 'taxopress-admin-select2';
721 $script_dependencies[] = 'wp-util';
722 }
723
724 $taxopress_pages = taxopress_admin_pages();
725
726 if (isset($_GET['page']) && in_array($_GET['page'], $taxopress_pages)) {
727 wp_enqueue_media();
728 }
729
730 wp_register_script('st-admin-js', STAGS_URL . '/assets/js/admin.js', $script_dependencies, STAGS_VERSION);
731 wp_enqueue_script('st-admin-js');
732 //localize script
733 wp_localize_script('st-admin-js', 'st_admin_localize', [
734 'ajaxurl' => admin_url('admin-ajax.php'),
735 'select_valid' => esc_html__('Please select a valid', 'simple-tags'),
736 'check_nonce' => wp_create_nonce('st-admin-js'),
737 'select_default_label' => esc_html__('Select Default Post Thumb', 'simple-tags'),
738 'use_media_label' => esc_html__('Use this media', 'simple-tags'),
739 'existing_content_admin_label' => esc_html__('Edit the current setting.', 'simple-tags'),
740 'request_error' => esc_html__('The request could not be completed. Please try again.', 'simple-tags'),
741 'autoterm_admin_url' => admin_url('admin.php?page=st_autoterms'),
742 'no_terms_message' => esc_html__('No terms will be deleted', 'simple-tags'),
743 'terms_count_message' => esc_html__(' terms will be deleted.', 'simple-tags'),
744 'checking_terms_message' => esc_html__('Checking terms...', 'simple-tags'),
745 'terms_error' => esc_html__('An error occurred while checking terms.', 'simple-tags'),
746 'post_required' => esc_html__('Select a post to see a preview.', 'simple-tags'),
747 'save_settings' => esc_html__('Auto Term ID missing. Kindly save the auto term before using this feature.', 'simple-tags'),
748 'delete_label' => esc_html__('Delete', 'simple-tags'),
749 'ai_nonce' => wp_create_nonce('taxopress-ai-ajax-nonce'),
750 'post_title' => '%post_title%',
751 'post_permalink' => '%post_permalink%',
752 'post_date' => '%post_date%',
753 'post_thumb_url' => '%post_thumb_url%',
754 'post_category' => '%post_category%',
755 'post_size' => '%post_size%',
756 'post_color' => '%post_color%',
757 'merge_cancelled' => esc_html__('Merge has been cancelled.', 'simple-tags'),
758 'cancel_label' => esc_html__('Cancel', 'simple-tags'),
759 'paused_label' => esc_html__('Pause.', 'simple-tags'),
760 'continue_label' => esc_html__('Continue', 'simple-tags'),
761 'merge_in_progress' => esc_html__('Merging terms. Please wait...', 'simple-tags'),
762 'merge_attached_data' => esc_html__('Merging %1$s terms attached to %2$s posts. Please wait...', 'simple-tags'),
763 'merge_large_data' => esc_html__('Large dataset detected, terms will be merged in batches of 20!', 'simple-tags'),
764 'merge_none_merged' => esc_html__('No terms were merged.', 'simple-tags'),
765 'batch_merge_progress' => esc_html__('Batch %1$s of %2$s merged.', 'simple-tags'),
766 'terms_merged_text' => esc_html__('terms merged', 'simple-tags'),
767 'posts_updated_text' => esc_html__('posts updated', 'simple-tags'),
768 'merge_success_update' => esc_html__('All terms merged into %s', 'simple-tags'),
769 'ajax_merge_terms_error' => esc_html__('AJAX error on batch', 'simple-tags'),
770 'batch_error_text' => esc_html__('Error on batch %1$s:', 'simple-tags'),
771 'enable_merge_terms_slug' => SimpleTags_Plugin::get_option_value('enable_merge_terms_slug'),
772 'enable_add_terms_slug' => SimpleTags_Plugin::get_option_value('enable_add_terms_slug'),
773 'enable_remove_terms_slug' => SimpleTags_Plugin::get_option_value('enable_remove_terms_slug'),
774 'enable_rename_terms_slug' => SimpleTags_Plugin::get_option_value('enable_rename_terms_slug'),
775 'enable_mass_edit_terms_slug' => SimpleTags_Plugin::get_option_value('enable_mass-edit_terms_slug'),
776 'select_post_label' => esc_html__('Search Posts...', 'simple-tags'),
777 'loading' => esc_html__('Loading...', 'simple-tags'),
778 'preview_error' => esc_html__('Error loading preview', 'simple-tags'),
779 'enable_ibm_watson_ai_source' => SimpleTags_Plugin::get_option_value('enable_ibm_watson_ai_source'),
780 'enable_dandelion_ai_source' => SimpleTags_Plugin::get_option_value('enable_dandelion_ai_source'),
781 'enable_lseg_ai_source' => SimpleTags_Plugin::get_option_value('enable_lseg_ai_source'),
782 'plugin_url' => STAGS_URL,
783 'using_default_text' => __('Using default TaxoPress image', 'simple-tags'),
784 'select_image_label' => esc_html__('Select Media', 'simple-tags'),
785 'change_image_label' => esc_html__('Change Media', 'simple-tags'),
786 'use_default_label' => esc_html__('Use Default', 'simple-tags'),
787 'see_more_suggestions' => esc_html__('See More', 'simple-tags'),
788 'see_less_suggestions' => esc_html__('See Less', 'simple-tags'),
789 'apply_selected' => esc_html__('Apply Selected', 'simple-tags'),
790 'close_suggestions' => esc_html__('Close', 'simple-tags'),
791 'select_suggestion_alert' => esc_html__('Please select at least one suggestion to apply.', 'simple-tags'),
792 'multiple_merge_warning' => esc_html__('You have selected multiple merge suggestions. All selected terms will be merged into a single new term. Do you want to continue?', 'simple-tags'),
793 'no_merge_suggestions' => esc_html__('No merge suggestions found for this taxonomy.', 'simple-tags'),
794 'suggested_terms_title' => esc_html__('Suggested Terms to Merge:', 'simple-tags'),
795 'duplicates_text' => esc_html__('duplicates', 'simple-tags'),
796 'reason_text' => esc_html__('Reason:', 'simple-tags'),
797 'select_all_label' => esc_html__('Select All', 'simple-tags'),
798 'deselect_all_label' => esc_html__('Deselect All', 'simple-tags'),
799 'terms_to_merge_text' => esc_html__('Terms to Merge', 'simple-tags'),
800 'new_term_text' => esc_html__('New Term', 'simple-tags'),
801 'reasons_text' => esc_html__('Reasons', 'simple-tags'),
802 ]);
803
804
805 //Register remodal assets
806 wp_register_script('st-remodal-js', STAGS_URL . '/assets/js/remodal.min.js', array('jquery'), STAGS_VERSION);
807 wp_register_style('st-remodal-css', STAGS_URL . '/assets/css/remodal.css', array(), STAGS_VERSION, 'all');
808 wp_register_style('st-remodal-default-theme-css', STAGS_URL . '/assets/css/remodal-default-theme.css', array(), STAGS_VERSION, 'all');
809
810 // Register location
811 $wp_post_pages = array('post.php', 'post-new.php');
812 $wp_page_pages = array('page.php', 'page-new.php');
813
814 wp_enqueue_style('st-admin-global');
815
816 // Common Helper for Post, Page and Plugin Page
817 if (
818 in_array($pagenow, $wp_post_pages) ||
819 (in_array($pagenow, $wp_page_pages) && is_page_have_tags()) ||
820 (isset($_GET['page']) && in_array($_GET['page'], $taxopress_pages))
821 ) {
822 wp_enqueue_script('st-remodal-js');
823 wp_enqueue_style('st-remodal-css');
824 wp_enqueue_style('st-remodal-default-theme-css');
825 wp_enqueue_style('st-admin');
826
827 do_action('taxopress_admin_class_after_styles_enqueue');
828 }
829
830 // add jQuery tabs for options page. Use jQuery UI Tabs from WP
831 if (isset($_GET['page']) && in_array($_GET['page'], array('st_options', 'st_terms_display', 'st_post_tags', 'st_related_posts',))) {
832 wp_enqueue_script('jquery-ui-tabs');
833 wp_enqueue_script('st-helper-options');
834 }
835
836 do_action('taxopress_admin_class_after_assets_enqueue');
837 }
838
839 /**
840 * Add settings page on WordPress admin menu
841 *
842 * @return void
843 * @author WebFactory Ltd
844 */
845 public static function admin_menu()
846 {
847 self::$admin_url = admin_url('admin.php?page=' . self::MENU_SLUG);
848
849 add_menu_page(
850 __('TaxoPress: Options', 'simple-tags'),
851 __('TaxoPress', 'simple-tags'),
852 'admin_simple_tags',
853 self::MENU_SLUG,
854 array(
855 __CLASS__,
856 'page_options',
857 ),
858 'dashicons-tag',
859 69
860 );
861 add_submenu_page(
862 self::MENU_SLUG,
863 __('TaxoPress: Options', 'simple-tags'),
864 __('Settings', 'simple-tags'),
865 'admin_simple_tags',
866 self::MENU_SLUG,
867 array(
868 __CLASS__,
869 'page_options',
870 )
871 );
872 }
873
874 /**
875 * Build HTML for page options, manage also save/reset settings
876 *
877 * @return void
878 * @author WebFactory Ltd
879 */
880 public static function page_options()
881 {
882 // Get options
883 $options = (array) SimpleTags_Plugin::get_option();
884
885 if (current_user_can('admin_simple_tags')) {
886 // Update or reset options
887 if (isset($_POST['updateoptions'])) {
888 $dashboard_options = taxopress_dashboard_options();
889 $dashboard_option_keys = array_column($dashboard_options, 'option_key');
890
891 check_admin_referer('updateresetoptions-simpletags');
892
893 $sanitized_options = [];
894
895 $is_fast_update_submission = isset($_GET['page']) && $_GET['page'] === 'st_taxopress_ai';
896
897 // This settings has been migrated to fast update screen so only update from there
898 if ($is_fast_update_submission) {
899 // add taxopress ai post type and taxonomies options so we can have all post types. TODO: This need to be a filter
900 foreach (get_post_types(['public' => true], 'names') as $post_type => $post_type_object) {
901 if ($post_type == 'post') {
902 $opt_default_value = 'post_tag';
903 } else {
904 $opt_default_value = 0;
905 }
906 $options['taxopress_ai_' . $post_type . '_metabox_default_taxonomy'] = $opt_default_value;
907 $options['taxopress_ai_' . $post_type . '_metabox_display_option'] = 'default';
908 $options['taxopress_ai_' . $post_type . '_support_private_taxonomy'] = 0;
909
910 $options['taxopress_ai_' . $post_type . '_metabox_orderby'] = 'count';
911 $options['taxopress_ai_' . $post_type . '_metabox_order'] = 'desc';
912 $options['taxopress_ai_' . $post_type . '_metabox_maximum_terms'] = 45;
913 $options['taxopress_ai_' . $post_type . '_metabox_show_post_count'] = 0;
914 $options['taxopress_ai_' . $post_type . '_metabox_show_term_slug'] = 0;
915
916 $options['taxopress_ai_' . $post_type . '_minimum_term_length'] = 2;
917 $options['taxopress_ai_' . $post_type . '_maximum_term_length'] = 40;
918
919 $options['taxopress_ai_' . $post_type . '_exclusions'] = '';
920 $options['enable_taxopress_ai_' . $post_type . '_metabox'] = $opt_default_value;
921 $options['taxopress_ai_' . $post_type . '_metabox_filters'] = 1;
922 foreach (['post_terms', 'existing_terms', 'suggest_local_terms', 'create_terms'] as $taxopress_ai_tab) {
923 $options['enable_taxopress_ai_' . $post_type . '_' . $taxopress_ai_tab . '_tab'] = $opt_default_value;
924 }
925 }
926
927 // add metabox post type and taxonomies options so we can have all post types. TODO: This need to be a filter
928 foreach (taxopress_get_all_wp_roles() as $role_name => $role_info) {
929 if (in_array($role_name, ['administrator', 'editor', 'author', 'contributor'])) {
930 $enable_acess_default_value = 1;
931 } else {
932 $enable_acess_default_value = 0;
933 }
934 $options['enable_' . $role_name . '_metabox'] = $enable_acess_default_value;
935 $options['enable_restrict' . $role_name . '_metabox'] = $enable_acess_default_value;
936
937 // ONLY admin + editor default to can edit
938 if (!isset($options['enable_edit_' . $role_name . '_metabox'])) {
939 $options['enable_edit_' . $role_name . '_metabox'] = in_array($role_name, ['administrator', 'editor']) ? 1 : 0;
940 }
941
942 $options['enable_metabox_' . $role_name . ''] = [];
943 $options['remove_taxonomy_metabox_' . $role_name . ''] = [];
944 }
945 }
946
947 foreach ($options as $key => $value) {
948 // If this is NOT a Fast Update submission, preserve metabox/metabox-access keys
949 if (!$is_fast_update_submission && preg_match('/^(enable_taxopress_ai_|taxopress_ai_|enable_.*_metabox|enable_restrict.*_metabox|enable_edit_.*_metabox|enable_metabox_|remove_taxonomy_metabox_)/', $key)) {
950 // Keep existing value as-is
951 if (!is_array($value)) {
952 $sanitized_options[$key] = taxopress_sanitize_text_field($value);
953 } else {
954 $sanitized_options[$key] = map_deep($value, 'sanitize_text_field');
955 }
956 continue;
957 }
958
959 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
960 $post_value = isset($_POST[$key]) ? wp_unslash($_POST[$key]) : '';
961
962 if (empty($post_value) && in_array($key, $dashboard_option_keys)) {
963 $post_value = SimpleTags_Plugin::get_option_value($key);
964 }
965
966 if (!is_array($post_value)) {
967 $sanitized_options[$key] = taxopress_sanitize_text_field($post_value);
968 } else {
969 $sanitized_options[$key] = map_deep($post_value, 'sanitize_text_field');
970 }
971 }
972 $options = $sanitized_options;
973
974 SimpleTags_Plugin::set_option($options);
975
976 do_action('simpletags_settings_save_general_end');
977 do_action('taxopress_settings_saved');
978
979 add_settings_error(__CLASS__, __CLASS__, esc_html__('Options saved', 'simple-tags'), 'updated taxopress-notice');
980 } elseif (isset($_POST['reset_options'])) {
981 check_admin_referer('updateresetoptions-simpletags');
982
983 SimpleTags_Plugin::set_default_option();
984
985 add_settings_error(__CLASS__, __CLASS__, esc_html__('TaxoPress options resetted to default options!', 'simple-tags'), 'updated taxopress-notice');
986 } else {
987 //add_settings_error(__CLASS__, __CLASS__, esc_html__('Settings updated', 'simple-tags'), 'updated');
988 }
989 }
990
991 settings_errors(__CLASS__);
992 include STAGS_DIR . '/views/admin/page-settings.php';
993 }
994
995 /**
996 * Get terms for a post, format terms for input and autocomplete usage
997 *
998 * @param string $taxonomy
999 * @param integer $post_id
1000 *
1001 * @return string
1002 * @author WebFactory Ltd
1003 */
1004 public static function getTermsToEdit($taxonomy = 'post_tag', $post_id = 0)
1005 {
1006 $post_id = (int) $post_id;
1007 if (!$post_id) {
1008 return '';
1009 }
1010
1011 $is_mass_edit_page = isset($_GET['page']) && $_GET['page'] === 'st_mass_terms';
1012 $show_slug = SimpleTags_Plugin::get_option_value('enable_mass-edit_terms_slug');
1013
1014 if ($is_mass_edit_page) {
1015 $term_objects = wp_get_post_terms($post_id, $taxonomy);
1016 if (empty($term_objects) || is_wp_error($term_objects)) {
1017 return '';
1018 }
1019
1020 $terms = array();
1021 foreach ($term_objects as $term) {
1022 if ($show_slug) {
1023 if (!empty($term->slug)) {
1024 $terms[] = $term->name . ' (' . $term->slug . ')';
1025 } else {
1026 $terms[] = $term->name;
1027 }
1028 } else {
1029 $terms[] = $term->name;
1030 }
1031 }
1032
1033 $terms = join(', ', $terms);
1034 } else {
1035 $terms = wp_get_post_terms($post_id, $taxonomy, array('fields' => 'names'));
1036 if (empty($terms) || is_wp_error($terms)) {
1037 return '';
1038 }
1039
1040 $terms = array_unique($terms);
1041 $terms = join(', ', $terms);
1042 }
1043
1044 $terms = esc_attr($terms);
1045 $terms = apply_filters('tags_to_edit', $terms);
1046
1047 return $terms;
1048 }
1049
1050 /**
1051 * Default content for meta box of TaxoPress
1052 *
1053 * @return string
1054 * @author WebFactory Ltd
1055 */
1056 public static function getDefaultContentBox()
1057 {
1058 if ((int) wp_count_terms(array('taxonomy' => 'post_tag', 'hide_empty' => false)) == 0) { // TODO: Custom taxonomy
1059 return esc_html__('This feature requires at least 1 tag to work. Begin by adding tags!', 'simple-tags');
1060 } else {
1061 return esc_html__('This feature works only with activated JavaScript. Activate it in your Web browser so you can!', 'simple-tags');
1062 }
1063 }
1064
1065 /**
1066 * A short public static function for display the same copyright on all admin pages
1067 *
1068 * @return void
1069 * @author WebFactory Ltd
1070 */
1071 public static function printAdminFooter()
1072 {
1073 /* ?>
1074 <p class="footer_st"><?php printf( __( 'Thanks for using TaxoPress | <a href="https://taxopress.com/">TaxoPress.com</a> | Version %s', 'simple-tags' ), STAGS_VERSION ); ?></p>
1075 <?php */
1076 }
1077
1078 /**
1079 * A short public static function for display the same copyright on all taxopress admin pages
1080 *
1081 * @return void
1082 * @author Olatechpro
1083 */
1084 public static function taxopress_admin_footer()
1085 {
1086
1087 $taxopress_pages = taxopress_admin_pages();
1088
1089 if (isset($_GET['page']) && in_array($_GET['page'], $taxopress_pages)) {
1090 ?>
1091 <p class="footer_st">
1092 <?php
1093 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1094 printf(__('Thanks for using TaxoPress | %1sTaxoPress.com%2s | Version %3s', 'simple-tags'), '<a href="https://taxopress.com/">', '</a>', esc_html(STAGS_VERSION)); ?>
1095 </p>
1096 <?php
1097 }
1098 }
1099
1100 /**
1101 * Ouput formatted options
1102 *
1103 * @param array $option_data
1104 *
1105 * @return string
1106 * @author WebFactory Ltd
1107 */
1108 public static function print_options($option_data)
1109 {
1110 // Get options
1111 $option_actual = SimpleTags_Plugin::get_option();
1112
1113 // Generate output
1114 $output = '';
1115 foreach ($option_data as $section => $options) {
1116 $colspan = count($options) > 1 ? 'colspan="2"' : '';
1117
1118 if ($section === 'legacy') {
1119 $table_sub_tab = '<div class="st-legacy-subtab">
1120 <span class="active" data-content=".legacy-tag-cloud-content">' . esc_html__("Tag Cloud", "simple-tags") . '</span> |
1121 <span data-content=".legacy-post-tags-content">' . esc_html__("Tags for Current Post", "simple-tags") . '</span> |
1122 <span data-content=".legacy-related-posts-content">' . esc_html__("Related Posts", "simple-tags") . '</span> |
1123 <span data-content=".legacy-auto-link-content">' . esc_html__("Auto Links", "simple-tags") . '</span>
1124 </div>' . PHP_EOL;
1125 } elseif ($section === 'taxopress-ai') {
1126 $table_sub_tab_lists = [];
1127 $pt_index = 0;
1128 foreach (TaxoPressAiUtilities::get_post_types_options() as $post_type => $post_type_object) {
1129 if (!in_array($post_type, ['attachment'])) {
1130 $active_pt = ($pt_index === 0) ? 'active' : '';
1131 $table_sub_tab_lists[] = '<span class="' . $active_pt . '" data-content=".taxopress-ai-' . $post_type . '-content">' . esc_html($post_type_object->labels->name) . '</span>';
1132 $pt_index++;
1133 }
1134 }
1135 $table_sub_tab = '<div class="st-taxopress-ai-subtab">' . join(' | ', $table_sub_tab_lists) . '</div>' . PHP_EOL;
1136 } elseif ($section === 'metabox') {
1137 $table_sub_tab_lists = [];
1138 $pt_index = 0;
1139 foreach (taxopress_get_all_wp_roles() as $role_name => $role_info) {
1140 $active_pt = ($pt_index === 0) ? 'active' : '';
1141 $table_sub_tab_lists[] = '<span class="' . $active_pt . '" data-content=".metabox-' . $role_name . '-content">' . esc_html(translate_user_role($role_info['name'])) . '</span>';
1142 $pt_index++;
1143 }
1144 $table_sub_tab = '<div class="st-metabox-subtab">' . join(' | ', $table_sub_tab_lists) . '</div>' . PHP_EOL;
1145 } else {
1146 $table_sub_tab = '';
1147 }
1148
1149 $output .= '<div class="group" id="' . sanitize_title($section) . '">' . PHP_EOL;
1150 $output .= $table_sub_tab;
1151 $output .= '<fieldset class="options">' . PHP_EOL;
1152 $output .= '<legend>' . self::getNiceTitleOptions($section) . '</legend>' . PHP_EOL;
1153 $output .= '<table class="form-table">' . PHP_EOL;
1154 foreach ((array) $options as $option) {
1155 $class = '';
1156 if (in_array($section, ['legacy', 'taxopress-ai', 'metabox'])) {
1157 $class = $option[5];
1158 }
1159
1160 // Helper
1161 if ($option[2] == 'helper') {
1162 $output .= '<tr style="vertical-align: middle;" class="' . $class . '"><td class="helper stpexplan" ' . $colspan . '>' . stripslashes($option[4]) . '</td></tr>' . PHP_EOL;
1163 continue;
1164 }
1165
1166 // Fix notices
1167 if (!isset($option_actual[$option[0]])) {
1168 $option_actual[$option[0]] = '';
1169 }
1170
1171 // Add our custom core_terms_promo type
1172 if ($option[2] == 'core_terms_promo') {
1173 if (isset($option[4]) && !empty($option[4])) {
1174 $output .= '<tr style="vertical-align: middle;" class="' . $class . '"><td class="helper" ' . $colspan . '>' . apply_filters('taxopress_admin_manage_' . $option[0], $option[4]) . '</td></tr>' . PHP_EOL;
1175 }
1176 continue;
1177 }
1178
1179 $input_type = '';
1180 $desc_html_tag = 'div';
1181 switch ($option[2]) {
1182 case 'radio':
1183 $input_type = array();
1184 foreach ($option[3] as $value => $text) {
1185 $input_type[] = '<label><input type="radio" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($value) . '" ' . checked($value, $option_actual[$option[0]], false) . ' /> ' . $text . '</label>' . PHP_EOL;
1186 }
1187 $input_type = implode('<br />', $input_type);
1188 break;
1189
1190 case 'checkbox':
1191 $desc_html_tag = 'span';
1192 $input_type = '<input type="checkbox" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($option[3]) . '" ' . (($option_actual[$option[0]]) ? 'checked="checked"' : '') . ' />' . PHP_EOL;
1193 break;
1194
1195 case 'multiselect':
1196 $desc_html_tag = 'div';
1197 $input_type = array();
1198 foreach ($option[3] as $field_name => $text) {
1199 $selected_option = (is_array($option_actual[$option[0]]) && in_array($field_name, $option_actual[$option[0]])) ? true : false;
1200 $input_type[] = '<label><input type="checkbox" id="' . $option[0] . '-' . $field_name . '" name="' . $option[0] . '[]" value="' . $field_name . '" ' . checked($selected_option, true, false) . ' /> ' . $text . '</label> <br />' . PHP_EOL;
1201 }
1202 $input_type = implode('<br />', $input_type);
1203 break;
1204
1205 case 'sub_multiple_checkbox':
1206 $desc_html_tag = 'div';
1207 $input_type = array();
1208 foreach ($option[3] as $field_name => $field_option) {
1209 $checked_option = !empty($option_actual[$field_name]) ? (int) $option_actual[$field_name] : 0;
1210 $selected_option = ($checked_option > 0) ? true : false;
1211 $field_description = !empty($field_option['description']) ? '<br /><span class="description stpexplan">' . $field_option['description'] . '</span>' : '';
1212 $input_type[] = '<label><input type="checkbox" id="' . $option[0] . '" name="' . $field_name . '" value="1" ' . checked($selected_option, true, false) . ' /> ' . $field_option['label'] . '</label> ' . $field_description . '<br />' . PHP_EOL;
1213 }
1214 $input_type = implode('<br />', $input_type);
1215 break;
1216
1217 case 'dropdown':// legacy
1218 $selopts = explode('/', $option[3]);
1219 $seldata = '';
1220 foreach ((array) $selopts as $sel) {
1221 $seldata .= '<option value="' . esc_attr($sel) . '" ' . ((isset($option_actual[$option[0]]) && $option_actual[$option[0]] == $sel) ? 'selected="selected"' : '') . ' >' . ucfirst($sel) . '</option>' . PHP_EOL;
1222 }
1223 $input_type = '<select id="' . $option[0] . '" name="' . $option[0] . '">' . $seldata . '</select>' . PHP_EOL;
1224 break;
1225
1226
1227 case 'select':
1228 $selopts = $option[3];
1229 $seldata = '';
1230 foreach ((array) $selopts as $sel_key => $sel_label) {
1231 $seldata .= '<option value="' . esc_attr($sel_key) . '" ' . ((isset($option_actual[$option[0]]) && $option_actual[$option[0]] == $sel_key) ? 'selected="selected"' : '') . ' >' . ucfirst($sel_label) . '</option>' . PHP_EOL;
1232 }
1233 $input_type = '<select id="' . $option[0] . '" name="' . $option[0] . '">' . $seldata . '</select>' . PHP_EOL;
1234 break;
1235
1236 case 'select_with_icon':
1237 $selopts = $option[3];
1238 $seldata = '';
1239 foreach ((array) $selopts as $sel_key => $sel_label) {
1240 $seldata .= '<option value="' . esc_attr($sel_key) . '" ' . ((isset($option_actual[$option[0]]) && $option_actual[$option[0]] == $sel_key) ? 'selected="selected"' : '') . ' >' . ucfirst($sel_label) . '</option>' . PHP_EOL;
1241 }
1242
1243 $icon_class = isset($option[6]['icon']) ? $option[6]['icon'] : 'dashicons-lock';
1244 $modal_content = isset($option[6]['modal']) ? $option[6]['modal'] : '';
1245 $disabled = !empty($option[8]) && isset($option[8]['disabled']) ? 'disabled="disabled"' : '';
1246 $class_attr = isset($option[5]) ? esc_attr($option[5]) : '';
1247 $icon_wrapper_class = isset($option[6]['icon_wrapper_class']) ? esc_attr($option[6]['icon_wrapper_class']) : 'taxopress-select-icon';
1248 $modal_wrapper_class = isset($option[6]['modal_wrapper_class']) ? esc_attr($option[6]['modal_wrapper_class']) : 'taxopress-select-icon-modal';
1249
1250 $input_type = '<div class="' . $class_attr . '">
1251 <select id="' . $option[0] . '" name="' . $option[0] . '" ' . $disabled . '>' . $seldata . '</select>
1252 <span class="' . $icon_wrapper_class . ' dashicons ' . esc_attr($icon_class) . '">
1253 <div class="' . $modal_wrapper_class . '">' . $modal_content . '</div>
1254 </span>
1255 </div>' . PHP_EOL;
1256 break;
1257
1258 case 'multiselect_with_desc_top':
1259 $desc_html_tag = 'div';
1260 $input_type_array = array();
1261 $prefix = !empty($field_description) ? '<' . $desc_html_tag . ' class="stpexplan">' . $field_description . '</' . $desc_html_tag . '>' : '';
1262 foreach ($field_options as $option_key => $option_label) {
1263 $field_value = isset($option_actual[$field_id]) ? $option_actual[$field_id] : array();
1264 $selected_option = (is_array($field_value) && in_array($option_key, $field_value)) ? true : false;
1265 $input_type_array[] = '<label><input type="checkbox" id="' . esc_attr($field_id . '-' . $option_key) . '" name="' . esc_attr($field_id) . '[]" value="' . esc_attr($option_key) . '" ' . checked($selected_option, true, false) . ' /> ' . esc_html($option_label) . '</label><br />';
1266 }
1267 $input_type = $prefix . implode('', $input_type_array);
1268 $field_description = '';
1269 break;
1270
1271 case 'text-color':
1272 $input_type = '<input type="text" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($option_actual[$option[0]]) . '" class="text-color ' . $option[3] . '" />' . PHP_EOL;
1273 break;
1274
1275 case 'text':
1276 $input_type = '<input type="text" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($option_actual[$option[0]]) . '" class="' . $option[3] . '" />' . PHP_EOL;
1277 break;
1278
1279 case 'licence_field':
1280 $input_type = '<input type="text" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($option[3]) . '" class="' . $option[5] . '" />' . PHP_EOL;
1281 break;
1282
1283 case 'number':
1284 $min_attr = isset($option[6]) ? ' min="' . esc_attr($option[6]) . '"' : '';
1285 $input_type = '<input type="number" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($option_actual[$option[0]]) . '" class="' . $option[3] . '"' . $min_attr . ' />' . PHP_EOL;
1286 break;
1287
1288 case 'textarea':
1289 $rows_attr = isset($option[7]['rows']) ? ' rows="' . esc_attr($option[7]['rows']) . '"' : ' rows="4"';
1290 $placeholder_attr = isset($option[7]['placeholder']) ? ' placeholder="' . esc_attr($option[7]['placeholder']) . '"' : '';
1291 $width_attr = (!empty($option[7]['width'])) ? ' style="width:' . esc_attr($option[7]['width']) . ';"' : ' style="width:100%; max-width:600px;"';
1292 $input_type = '<textarea id="' . $option[0] . '" name="' . $option[0] . '"' . $rows_attr . $placeholder_attr . $width_attr . ' class="' . $option[3] . '">' . esc_textarea($option_actual[$option[0]]) . '</textarea>' . PHP_EOL;
1293 break;
1294 }
1295
1296 if (is_array($option[2])) {
1297 $input_type = '<input type="' . $option[2]["type"] . '" id="' . $option[0] . '" name="' . $option[0] . '" value="' . esc_attr($option_actual[$option[0]]) . '" class="' . $option[3] . '" ' . $option[2]["attr"] . ' />' . PHP_EOL;
1298 }
1299
1300 // Additional Information
1301 $extra_prefix = '';
1302 $extra_suffix = '';
1303 if (!empty($option[4])) {
1304 if ($option[2] == 'sub_multiple_checkbox') {
1305 $extra_prefix = '<' . $desc_html_tag . ' class="stpexplan">' . $option[4] . '</' . $desc_html_tag . '>' . PHP_EOL;
1306 } else {
1307 $extra_suffix = '<' . $desc_html_tag . ' class="stpexplan">' . $option[4] . '</' . $desc_html_tag . '>' . PHP_EOL;
1308 }
1309 }
1310
1311 // Output
1312 $output .= '<tr style="vertical-align: top;" class="' . $class . '"><th scope="row"><label for="' . $option[0] . '">' . $option[1] . '</label></th><td>' . $extra_prefix . ' ' . $input_type . ' ' . $extra_suffix . '</td></tr>' . PHP_EOL;
1313 }
1314 $output .= '</table>' . PHP_EOL;
1315 $output .= '</fieldset>' . PHP_EOL;
1316 $output .= '</div>' . PHP_EOL;
1317 }
1318
1319 return $output;
1320 }
1321
1322 /**
1323 * Get nice title for tabs title option
1324 *
1325 * @param string $id
1326 *
1327 * @return string
1328 */
1329 public static function getNiceTitleOptions($id = '')
1330 {
1331 switch ($id) {
1332 case 'administration':
1333 return esc_html__('Administration', 'simple-tags');
1334 case 'auto-links':
1335 return esc_html__('Auto link', 'simple-tags');
1336 case 'features':
1337 return esc_html__('Features', 'simple-tags');
1338 case 'embeddedtags':
1339 return esc_html__('Embedded Tags', 'simple-tags');
1340 case 'tagspost':
1341 return esc_html__('Tags for Current Post', 'simple-tags');
1342 case 'relatedposts':
1343 return esc_html__('Related Posts', 'simple-tags');
1344 case 'legacy':
1345 return esc_html__('Legacy', 'simple-tags');
1346 case 'posts':
1347 return esc_html__('Posts', 'simple-tags');
1348 case 'taxopress-ai':
1349 return esc_html__('Metaboxes', 'simple-tags');
1350 case 'metabox':
1351 return esc_html__('Metabox Access', 'simple-tags');
1352 case 'linked_terms':
1353 return esc_html__('Linked Terms', 'simple-tags');
1354 case 'synonyms':
1355 return esc_html__('Term Synonyms', 'simple-tags');
1356 case 'licence':
1357 return esc_html__('License', 'simple-tags');
1358 case 'hidden_terms':
1359 return esc_html__('Hidden Terms', 'simple-tags');
1360 case 'frontend_scripts':
1361 return esc_html__('Frontend Scripts', 'simple-tags');
1362 case 'manage_terms':
1363 return esc_html__('Manage Terms', 'simple-tags');
1364 case 'mass_edit_terms':
1365 return esc_html__('Mass Edit Terms', 'simple-tags');
1366 case 'core_linked_terms':
1367 return esc_html__('Linked Terms', 'simple-tags');
1368 case 'core_synonyms_terms':
1369 return esc_html__('Term Synonyms', 'simple-tags');
1370 case 'legacy_ai_sources':
1371 return esc_html__('Auto Terms', 'simple-tags');
1372 }
1373
1374 return '';
1375 }
1376
1377 /**
1378 * This method allow to check if the DB is up to date, and if a upgrade is need for options
1379 * TODO, useful or delete ?
1380 *
1381 * @return void
1382 * @author WebFactory Ltd
1383 */
1384 public static function upgrade()
1385 {
1386 // Get current version number
1387 $current_version = get_option(STAGS_OPTIONS_NAME . '-version');
1388
1389 // Upgrade needed ?
1390 if ($current_version == false || version_compare($current_version, STAGS_VERSION, '<')) {
1391 $current_options = get_option(STAGS_OPTIONS_NAME);
1392 $default_options = (array) include(STAGS_DIR . '/inc/helper.options.default.php');
1393
1394 // Add new options
1395 foreach ($default_options as $key => $default_value) {
1396 if (!isset($current_options[$key])) {
1397 $current_options[$key] = $default_value;
1398 }
1399 }
1400
1401 // Remove old options
1402 /*foreach ($current_options as $key => $current_value) {
1403 if (!isset($default_options[$key])) {
1404 unset($current_options[$key]);
1405 }
1406 }*/
1407
1408 update_option(STAGS_OPTIONS_NAME . '-version', STAGS_VERSION);
1409 update_option(STAGS_OPTIONS_NAME, $current_options);
1410 }
1411 }
1412
1413 /**
1414 * Make a simple SQL query with some args for get terms for ajax display
1415 *
1416 * @param string $taxonomy
1417 * @param string $search
1418 * @param string $order_by
1419 * @param string $order
1420 *
1421 * @return array
1422 * @author WebFactory Ltd
1423 */
1424 public static function getTermsForAjax($taxonomy = 'post_tag', $search = '', $order_by = 'name', $order = 'ASC', $limit = 0)
1425 {
1426 global $wpdb;
1427
1428 $order = strtoupper($order);
1429 if (!in_array($order, ['ASC', 'DESC'], true)) {
1430 $order = 'ASC';
1431 }
1432
1433 $allowed_orderby = [
1434 'name' => 't.name',
1435 'count' => 'tt.count',
1436 'random' => 'RAND()',
1437 ];
1438
1439 if (isset($allowed_orderby[$order_by])) {
1440 $order_by_sql = $allowed_orderby[$order_by];
1441 } else {
1442 $order_by_sql = $allowed_orderby['name'];
1443 }
1444
1445 $limit_sql = '';
1446 $limit = (int) $limit;
1447 if ($limit > 0) {
1448 $limit_sql = $wpdb->prepare('LIMIT 0, %d', $limit);
1449 }
1450
1451 if ($taxonomy == 'linked_term_taxonomies') {
1452 $taxonomies = SimpleTags_Plugin::get_option_value('linked_terms_taxonomies');
1453 if (empty($taxonomies) || !is_array($taxonomies)) {
1454 $taxonomies = ['category', 'post_tag'];
1455 }
1456 $taxonomies_list = "'" . implode("', '", $taxonomies) . "'";
1457 }
1458
1459 if (!empty($search)) {
1460 if ($taxonomy == 'linked_term_taxonomies') {
1461 $query = $wpdb->prepare(
1462 "
1463 SELECT DISTINCT t.name, t.term_id, tt.taxonomy
1464 FROM {$wpdb->terms} AS t
1465 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
1466 WHERE tt.taxonomy IN ($taxonomies_list)
1467 AND t.name LIKE %s
1468 ORDER BY $order_by_sql $order $limit_sql
1469 ",
1470 '%' . $wpdb->esc_like($search) . '%'
1471 );
1472 } else {
1473 $query = $wpdb->prepare(
1474 "
1475 SELECT DISTINCT t.name, t.slug, t.term_id, tt.taxonomy
1476 FROM {$wpdb->terms} AS t
1477 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
1478 WHERE tt.taxonomy = %s
1479 AND t.name LIKE %s
1480 ORDER BY $order_by_sql $order $limit_sql
1481 ",
1482 $taxonomy,
1483 '%' . $wpdb->esc_like($search) . '%'
1484 );
1485 }
1486 return $wpdb->get_results($query);
1487 } else {
1488 if ($taxonomy == 'linked_term_taxonomies') {
1489 $query = "
1490 SELECT DISTINCT t.name, t.term_id, tt.taxonomy
1491 FROM {$wpdb->terms} AS t
1492 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
1493 WHERE tt.taxonomy IN ($taxonomies_list)
1494 ORDER BY $order_by_sql $order $limit_sql
1495 ";
1496 } else {
1497 $query = $wpdb->prepare("
1498 SELECT DISTINCT t.name, t.slug, t.term_id, tt.taxonomy
1499 FROM {$wpdb->terms} AS t
1500 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
1501 WHERE tt.taxonomy = %s
1502 ORDER BY $order_by_sql $order $limit_sql
1503 ", $taxonomy);
1504 }
1505
1506 return $wpdb->get_results($query);
1507 }
1508 }
1509
1510 /**
1511 * Plugin installer/uograde code
1512 *
1513 * @return void
1514 */
1515 public static function plugin_installer_upgrade_code()
1516 {
1517 if (!get_option('taxopress_3_23_0_upgrade_completed')) {
1518 $options = SimpleTags_Plugin::get_option();
1519
1520 // add metabox default values
1521 $tax_names = array_keys(get_taxonomies([], 'names'));
1522 foreach (taxopress_get_all_wp_roles() as $role_name => $role_info) {
1523 if (in_array($role_name, ['administrator', 'editor', 'author', 'contributor'])) {
1524 $enable_acess_default_value = 1;
1525 } else {
1526 $enable_acess_default_value = 0;
1527 }
1528 $options['enable_' . $role_name . '_metabox'] = $enable_acess_default_value;
1529 $options['enable_metabox_' . $role_name . ''] = $tax_names;
1530 $options['remove_taxonomy_metabox_' . $role_name . ''] = [];
1531 }
1532
1533 SimpleTags_Plugin::set_option($options);
1534
1535 update_option('taxopress_3_23_0_upgrade_completed', true);
1536 } elseif (!get_option('taxopress_3_28_0_upgrade_completed')) {
1537 if (function_exists('taxopress_get_autoterm_data')) {
1538 $autoterms = taxopress_get_autoterm_data();
1539 foreach ($autoterms as $autoterm_index => $autoterm) {
1540 //enable when to fields
1541 $autoterms[$autoterm_index]['autoterm_for_post'] = 1;
1542 $autoterms[$autoterm_index]['autoterm_for_schedule'] = 1;
1543 $autoterms[$autoterm_index]['autoterm_for_existing_content'] = 1;
1544 $autoterms[$autoterm_index]['autoterm_for_metaboxes'] = 1;
1545 // update new cloned fields for other groups
1546 $autoterms[$autoterm_index]['schedule_terms_limit'] = !empty($autoterm['terms_limit']) ? $autoterm['terms_limit'] : 5;
1547 $autoterms[$autoterm_index]['schedule_autoterm_target'] = !empty($autoterm['autoterm_target']) ? $autoterm['autoterm_target'] : 0;
1548 $autoterms[$autoterm_index]['schedule_autoterm_word'] = !empty($autoterm['autoterm_word']) ? $autoterm['autoterm_word'] : 0;
1549 $autoterms[$autoterm_index]['schedule_autoterm_hash'] = !empty($autoterm['autoterm_hash']) ? $autoterm['autoterm_hash'] : 0;
1550
1551 $autoterms[$autoterm_index]['existing_content_terms_limit'] = !empty($autoterm['terms_limit']) ? $autoterm['terms_limit'] : 5;
1552 }
1553 update_option('taxopress_autoterms', $autoterms);
1554 }
1555 update_option('taxopress_3_28_0_upgrade_completed', true);
1556 }
1557 }
1558
1559 /**
1560 * Redirect user on plugin activation
1561 *
1562 * @return void
1563 */
1564 public static function redirect_on_activate()
1565 {
1566 if (get_option('taxopress_activate')) {
1567 delete_option('taxopress_activate');
1568 wp_redirect(admin_url("admin.php?page=st_dashboard&welcome"));
1569 exit;
1570 }
1571 }
1572 }
1573