| @@ -190,8 +190,13 @@ | ||
| 190 | 190 | 'permission_callback' => array( __CLASS__, 'rest_permission_check' ), |
| 191 | 191 | ), |
| 192 | 192 | ) ); |
| 193 | 193 | |
| 194 | + register_rest_route( $namespace, '/admin/search-content', array( | |
| 195 | + 'methods' => 'GET', | |
| 196 | + 'callback' => array( __CLASS__, 'rest_search_content' ), | |
| 197 | + 'permission_callback' => array( __CLASS__, 'rest_permission_check' ), | |
| 198 | + ) ); | |
| 194 | 199 | register_rest_route( $namespace, '/admin/sync-triggers', array( |
| 195 | 200 | 'methods' => 'POST', |
| 196 | 201 | 'callback' => array( __CLASS__, 'rest_sync_triggers' ), |
| 197 | 202 | 'permission_callback' => array( __CLASS__, 'rest_permission_check' ), |
| @@ -307,8 +312,18 @@ | ||
| 307 | 312 | $data = $request->get_json_params(); |
| 308 | 313 | $errors = array(); |
| 309 | 314 | $allowed = self::get_settings_field_definitions(); |
| 310 | 315 | |
| 316 | + // The chat button can't be enabled without a WhatsApp number (it would silently not render). | |
| 317 | + $enabling_ctc = isset( $data['ctc_enable'] ) && ( 'yes' === $data['ctc_enable'] || '1' === $data['ctc_enable'] || true === $data['ctc_enable'] ); | |
| 318 | + $ctc_number = isset( $data['ctc_whatsapp_number'] ) ? trim( (string) $data['ctc_whatsapp_number'] ) : get_option( 'notifier_ctc_whatsapp_number', '' ); | |
| 319 | + if ( $enabling_ctc && '' === $ctc_number ) { | |
| 320 | + return new WP_REST_Response( array( | |
| 321 | + 'success' => false, | |
| 322 | + 'errors' => array( __( 'Please enter a WhatsApp number to enable the chat button.', 'notifier' ) ), | |
| 323 | + ), 200 ); | |
| 324 | + } | |
| 325 | + | |
| 311 | 326 | foreach ( $data as $key => $value ) { |
| 312 | 327 | if ( ! isset( $allowed[ $key ] ) ) { |
| 313 | 328 | continue; |
| 314 | 329 | } |
| @@ -333,10 +348,16 @@ | ||
| 333 | 348 | break; |
| 334 | 349 | case 'textarea': |
| 335 | 350 | $value = wp_kses_post( trim( $value ) ); |
| 336 | 351 | break; |
| 352 | + case 'display_rules': | |
| 353 | + $value = self::sanitize_ctc_display_rules( is_array( $value ) ? $value : array() ); | |
| 354 | + break; | |
| 337 | 355 | case 'array': |
| 338 | 356 | $value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : array(); |
| 357 | + if ( ! empty( $def['options'] ) ) { | |
| 358 | + $value = array_values( array_intersect( $value, array_keys( $def['options'] ) ) ); | |
| 359 | + } | |
| 339 | 360 | break; |
| 340 | 361 | default: |
| 341 | 362 | $value = sanitize_text_field( $value ); |
| 342 | 363 | break; |
| @@ -778,17 +799,30 @@ | ||
| 778 | 799 | |
| 779 | 800 | public static function get_all_settings() { |
| 780 | 801 | return array( |
| 781 | 802 | 'default_country_code' => get_option( 'notifier_default_country_code', '' ), |
| 803 | + 'disable_background_processing' => get_option( 'notifier_disable_background_processing', 'no' ), | |
| 782 | 804 | 'ctc_enable' => get_option( 'notifier_ctc_enable', 'no' ), |
| 783 | 805 | 'ctc_whatsapp_number' => get_option( 'notifier_ctc_whatsapp_number', '' ), |
| 784 | 806 | 'ctc_greeting_text' => get_option( 'notifier_ctc_greeting_text', '' ), |
| 785 | 807 | 'ctc_button_style' => get_option( 'notifier_ctc_button_style', 'default' ), |
| 786 | 808 | 'ctc_custom_button_image_url' => get_option( 'notifier_ctc_custom_button_image_url', '' ), |
| 809 | + 'ctc_position' => get_option( 'notifier_ctc_position', 'bottom-right' ), | |
| 810 | + 'ctc_offset_x' => get_option( 'notifier_ctc_offset_x', 20 ), | |
| 811 | + 'ctc_offset_y' => get_option( 'notifier_ctc_offset_y', 20 ), | |
| 812 | + 'ctc_mobile_position_enable' => get_option( 'notifier_ctc_mobile_position_enable', 'no' ), | |
| 813 | + 'ctc_mobile_position' => get_option( 'notifier_ctc_mobile_position', 'bottom-right' ), | |
| 814 | + 'ctc_mobile_offset_x' => get_option( 'notifier_ctc_mobile_offset_x', 20 ), | |
| 815 | + 'ctc_mobile_offset_y' => get_option( 'notifier_ctc_mobile_offset_y', 20 ), | |
| 816 | + 'ctc_display_rules' => self::get_ctc_display_rules_for_ui(), | |
| 817 | + 'ctc_devices' => get_option( 'notifier_ctc_devices', array_keys( self::get_ctc_device_options() ) ), | |
| 787 | 818 | 'enable_activity_log' => get_option( 'notifier_enable_activity_log', 'no' ), |
| 788 | 819 | 'wp_enabled_merge_tags' => get_option( 'notifier_wp_enabled_merge_tags', array() ), |
| 789 | 820 | 'wp_enabled_recipient_fields' => get_option( 'notifier_wp_enabled_recipient_fields', array() ), |
| 790 | 821 | 'button_styles' => self::get_button_styles(), |
| 822 | + 'ctc_position_options' => self::get_ctc_position_options(), | |
| 823 | + 'ctc_location_options' => self::get_ctc_location_options(), | |
| 824 | + 'ctc_device_options' => self::get_ctc_device_options(), | |
| 791 | 825 | ); |
| 792 | 826 | } |
| 793 | 827 | |
| 794 | 828 | private static function get_settings_field_definitions() { |
| @@ -793,13 +827,23 @@ | ||
| 793 | 827 | |
| 794 | 828 | private static function get_settings_field_definitions() { |
| 795 | 829 | return array( |
| 796 | 830 | 'default_country_code' => array( 'type' => 'text' ), |
| 831 | + 'disable_background_processing' => array( 'type' => 'checkbox' ), | |
| 797 | 832 | 'ctc_enable' => array( 'type' => 'checkbox' ), |
| 798 | 833 | 'ctc_whatsapp_number' => array( 'type' => 'text' ), |
| 799 | 834 | 'ctc_greeting_text' => array( 'type' => 'text' ), |
| 800 | 835 | 'ctc_button_style' => array( 'type' => 'select', 'options' => self::get_button_styles(), 'default' => 'default' ), |
| 801 | 836 | 'ctc_custom_button_image_url' => array( 'type' => 'text' ), |
| 837 | + 'ctc_position' => array( 'type' => 'select', 'options' => self::get_ctc_position_options(), 'default' => 'bottom-right' ), | |
| 838 | + 'ctc_offset_x' => array( 'type' => 'number', 'min' => 0 ), | |
| 839 | + 'ctc_offset_y' => array( 'type' => 'number', 'min' => 0 ), | |
| 840 | + 'ctc_mobile_position_enable' => array( 'type' => 'checkbox' ), | |
| 841 | + 'ctc_mobile_position' => array( 'type' => 'select', 'options' => self::get_ctc_position_options(), 'default' => 'bottom-right' ), | |
| 842 | + 'ctc_mobile_offset_x' => array( 'type' => 'number', 'min' => 0 ), | |
| 843 | + 'ctc_mobile_offset_y' => array( 'type' => 'number', 'min' => 0 ), | |
| 844 | + 'ctc_display_rules' => array( 'type' => 'display_rules' ), | |
| 845 | + 'ctc_devices' => array( 'type' => 'array', 'options' => self::get_ctc_device_options() ), | |
| 802 | 846 | 'enable_activity_log' => array( 'type' => 'checkbox' ), |
| 803 | 847 | 'wp_enabled_merge_tags' => array( 'type' => 'array' ), |
| 804 | 848 | 'wp_enabled_recipient_fields' => array( 'type' => 'array' ), |
| 805 | 849 | ); |
| @@ -812,8 +856,338 @@ | ||
| 812 | 856 | 'btn-style-2' => 'Style 2', |
| 813 | 857 | 'btn-style-3' => 'Style 3', |
| 814 | 858 | 'btn-style-4' => 'Style 4', |
| 815 | 859 | 'btn-custom-image' => 'Add your own image', |
| 860 | + ); | |
| 861 | + } | |
| 862 | + | |
| 863 | + public static function get_ctc_position_options() { | |
| 864 | + return array( | |
| 865 | + 'bottom-right' => 'Bottom Right', | |
| 866 | + 'bottom-left' => 'Bottom Left', | |
| 867 | + 'top-right' => 'Top Right', | |
| 868 | + 'top-left' => 'Top Left', | |
| 869 | + ); | |
| 870 | + } | |
| 871 | + | |
| 872 | + // ---------------------------------------- | |
| 873 | + // Chat button display rules | |
| 874 | + // ---------------------------------------- | |
| 875 | + | |
| 876 | + /** | |
| 877 | + * Grouped location options for the display / exclude rule dropdowns (react-select format). | |
| 878 | + * | |
| 879 | + * Rule keys: | |
| 880 | + * basic-global | basic-singulars | basic-archives | |
| 881 | + * special-front | special-blog | special-404 | special-search | special-date | special-author | |
| 882 | + * {post_type}|all | {post_type}|archive | {post_type}|tax|{taxonomy} | |
| 883 | + * wc-shop | wc-cart | wc-checkout | wc-account | wc-order-received | |
| 884 | + * specifics (with items: post-{id}, tax-{term_id}, tax-{term_id}-posts) | |
| 885 | + */ | |
| 886 | + public static function get_ctc_location_options() { | |
| 887 | + $groups = array( | |
| 888 | + array( | |
| 889 | + 'label' => 'Basic', | |
| 890 | + 'options' => array( | |
| 891 | + array('value' => 'basic-global', 'label' => 'Entire Website'), | |
| 892 | + array('value' => 'basic-singulars', 'label' => 'All Singulars'), | |
| 893 | + array('value' => 'basic-archives', 'label' => 'All Archives'), | |
| 894 | + ), | |
| 895 | + ), | |
| 896 | + array( | |
| 897 | + 'label' => 'Special Pages', | |
| 898 | + 'options' => array( | |
| 899 | + array('value' => 'special-front', 'label' => 'Front Page'), | |
| 900 | + array('value' => 'special-blog', 'label' => 'Blog / Posts Page'), | |
| 901 | + array('value' => 'special-404', 'label' => '404 Page'), | |
| 902 | + array('value' => 'special-search', 'label' => 'Search Results'), | |
| 903 | + array('value' => 'special-date', 'label' => 'Date Archive'), | |
| 904 | + array('value' => 'special-author', 'label' => 'Author Archive'), | |
| 905 | + ), | |
| 906 | + ), | |
| 907 | + ); | |
| 908 | + | |
| 909 | + $has_woo = class_exists('WooCommerce'); | |
| 910 | + | |
| 911 | + foreach (self::get_ctc_rule_post_types() as $post_type) { | |
| 912 | + $options = array( | |
| 913 | + array('value' => $post_type->name . '|all', 'label' => 'All ' . $post_type->labels->name), | |
| 914 | + ); | |
| 915 | + | |
| 916 | + // The product archive is the WooCommerce shop page, listed under WooCommerce below. | |
| 917 | + if ($post_type->has_archive && ! ($has_woo && 'product' === $post_type->name)) { | |
| 918 | + $options[] = array('value' => $post_type->name . '|archive', 'label' => $post_type->labels->name . ' Archive'); | |
| 919 | + } | |
| 920 | + | |
| 921 | + foreach (get_object_taxonomies($post_type->name, 'objects') as $taxonomy) { | |
| 922 | + if (! self::is_ctc_rule_taxonomy($taxonomy)) { | |
| 923 | + continue; | |
| 924 | + } | |
| 925 | + $options[] = array( | |
| 926 | + 'value' => $post_type->name . '|tax|' . $taxonomy->name, | |
| 927 | + 'label' => 'All ' . $taxonomy->labels->singular_name . ' Archives', | |
| 928 | + ); | |
| 929 | + } | |
| 930 | + | |
| 931 | + $groups[] = array('label' => $post_type->labels->name, 'options' => $options); | |
| 932 | + } | |
| 933 | + | |
| 934 | + if ($has_woo) { | |
| 935 | + $groups[] = array( | |
| 936 | + 'label' => 'WooCommerce', | |
| 937 | + 'options' => array( | |
| 938 | + array('value' => 'wc-shop', 'label' => 'Shop Page'), | |
| 939 | + array('value' => 'wc-cart', 'label' => 'Cart Page'), | |
| 940 | + array('value' => 'wc-checkout', 'label' => 'Checkout Page'), | |
| 941 | + array('value' => 'wc-account', 'label' => 'My Account Page'), | |
| 942 | + array('value' => 'wc-order-received', 'label' => 'Order Received (Thank You) Page'), | |
| 943 | + ), | |
| 944 | + ); | |
| 945 | + } | |
| 946 | + | |
| 947 | + $groups[] = array( | |
| 948 | + 'label' => 'Specific Target', | |
| 949 | + 'options' => array( | |
| 950 | + array('value' => 'specifics', 'label' => 'Specific Pages / Posts / Taxonomies'), | |
| 951 | + ), | |
| 952 | + ); | |
| 953 | + | |
| 954 | + return $groups; | |
| 955 | + } | |
| 956 | + | |
| 957 | + /** | |
| 958 | + * Flat list of valid rule keys. | |
| 959 | + */ | |
| 960 | + public static function get_ctc_location_keys() { | |
| 961 | + $keys = array(); | |
| 962 | + foreach (self::get_ctc_location_options() as $group) { | |
| 963 | + foreach ($group['options'] as $option) { | |
| 964 | + $keys[] = $option['value']; | |
| 965 | + } | |
| 966 | + } | |
| 967 | + return $keys; | |
| 968 | + } | |
| 969 | + | |
| 970 | + /** | |
| 971 | + * Public, frontend-viewable post types that rules can target. | |
| 972 | + * | |
| 973 | + * @return WP_Post_Type[] | |
| 974 | + */ | |
| 975 | + public static function get_ctc_rule_post_types() { | |
| 976 | + $post_types = array(); | |
| 977 | + foreach (get_post_types(array('public' => true), 'objects') as $post_type) { | |
| 978 | + if ('attachment' === $post_type->name || ! is_post_type_viewable($post_type)) { | |
| 979 | + continue; | |
| 980 | + } | |
| 981 | + $post_types[] = $post_type; | |
| 982 | + } | |
| 983 | + return $post_types; | |
| 984 | + } | |
| 985 | + | |
| 986 | + /** | |
| 987 | + * Whether a taxonomy has frontend archives worth targeting. | |
| 988 | + * | |
| 989 | + * @param WP_Taxonomy $taxonomy | |
| 990 | + */ | |
| 991 | + public static function is_ctc_rule_taxonomy($taxonomy) { | |
| 992 | + // Post formats and WooCommerce shipping classes are queryable but have no real archive pages. | |
| 993 | + if (in_array($taxonomy->name, array('post_format', 'product_shipping_class'), true)) { | |
| 994 | + return false; | |
| 995 | + } | |
| 996 | + return is_taxonomy_viewable($taxonomy); | |
| 997 | + } | |
| 998 | + | |
| 999 | + public static function get_default_ctc_display_rules() { | |
| 1000 | + return array( | |
| 1001 | + 'display' => array(array('rule' => 'basic-global', 'specifics' => array())), | |
| 1002 | + 'exclude' => array(), | |
| 1003 | + ); | |
| 1004 | + } | |
| 1005 | + | |
| 1006 | + /** | |
| 1007 | + * Validate submitted rules: unknown rule keys and malformed specific items are dropped, | |
| 1008 | + * as are "Specific" rows with nothing selected. | |
| 1009 | + */ | |
| 1010 | + public static function sanitize_ctc_display_rules($value) { | |
| 1011 | + $valid = self::get_ctc_location_keys(); | |
| 1012 | + $clean = array('display' => array(), 'exclude' => array()); | |
| 1013 | + | |
| 1014 | + foreach (array('display', 'exclude') as $list) { | |
| 1015 | + if (empty($value[$list]) || ! is_array($value[$list])) { | |
| 1016 | + continue; | |
| 1017 | + } | |
| 1018 | + foreach ($value[$list] as $row) { | |
| 1019 | + $rule = isset($row['rule']) ? sanitize_text_field((string) $row['rule']) : ''; | |
| 1020 | + if (! in_array($rule, $valid, true)) { | |
| 1021 | + continue; | |
| 1022 | + } | |
| 1023 | + | |
| 1024 | + $specifics = array(); | |
| 1025 | + if ('specifics' === $rule) { | |
| 1026 | + foreach ((array) ($row['specifics'] ?? array()) as $item) { | |
| 1027 | + $item = is_array($item) ? ($item['value'] ?? '') : $item; | |
| 1028 | + if (preg_match('/^(post|tax)-\d+(-posts)?$/', (string) $item)) { | |
| 1029 | + $specifics[] = (string) $item; | |
| 1030 | + } | |
| 1031 | + } | |
| 1032 | + if (empty($specifics)) { | |
| 1033 | + continue; | |
| 1034 | + } | |
| 1035 | + } | |
| 1036 | + | |
| 1037 | + $clean[$list][] = array('rule' => $rule, 'specifics' => array_values(array_unique($specifics))); | |
| 1038 | + } | |
| 1039 | + } | |
| 1040 | + | |
| 1041 | + return $clean; | |
| 1042 | + } | |
| 1043 | + | |
| 1044 | + /** | |
| 1045 | + * Saved rules (raw keys), falling back to "Entire Website". | |
| 1046 | + */ | |
| 1047 | + public static function get_ctc_display_rules() { | |
| 1048 | + $rules = get_option('notifier_ctc_display_rules', null); | |
| 1049 | + if (! is_array($rules) || ! isset($rules['display'])) { | |
| 1050 | + return self::get_default_ctc_display_rules(); | |
| 1051 | + } | |
| 1052 | + return wp_parse_args($rules, array('display' => array(), 'exclude' => array())); | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + /** | |
| 1056 | + * Saved rules with the specific items expanded to {value,label} options for the settings UI. | |
| 1057 | + * Items whose post/term no longer exists are left out. | |
| 1058 | + */ | |
| 1059 | + public static function get_ctc_display_rules_for_ui() { | |
| 1060 | + $rules = self::get_ctc_display_rules(); | |
| 1061 | + foreach ($rules as &$rows) { | |
| 1062 | + foreach ($rows as &$row) { | |
| 1063 | + $row['specifics'] = array_values(array_filter(array_map(array(__CLASS__, 'get_ctc_specific_option'), (array) $row['specifics']))); | |
| 1064 | + } | |
| 1065 | + unset($row); | |
| 1066 | + } | |
| 1067 | + unset($rows); | |
| 1068 | + return $rules; | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + /** | |
| 1072 | + * Build the {value,label} option for a specific item key (post-{id}, tax-{id}, tax-{id}-posts). | |
| 1073 | + * | |
| 1074 | + * @return array|null Null if the post/term no longer exists. | |
| 1075 | + */ | |
| 1076 | + public static function get_ctc_specific_option($key) { | |
| 1077 | + if (! preg_match('/^(post|tax)-(\d+)(-posts)?$/', (string) $key, $m)) { | |
| 1078 | + return null; | |
| 1079 | + } | |
| 1080 | + $id = (int) $m[2]; | |
| 1081 | + | |
| 1082 | + if ('post' === $m[1]) { | |
| 1083 | + $post = get_post($id); | |
| 1084 | + if (! $post || 'trash' === $post->post_status) { | |
| 1085 | + return null; | |
| 1086 | + } | |
| 1087 | + $type = get_post_type_object($post->post_type); | |
| 1088 | + // Plain text: React renders labels as text nodes, so entities from wptexturize/kses would show literally. | |
| 1089 | + $title = trim(html_entity_decode(wp_strip_all_tags($post->post_title), ENT_QUOTES, 'UTF-8')); | |
| 1090 | + return array( | |
| 1091 | + 'value' => $key, | |
| 1092 | + 'label' => ('' !== $title ? $title : '#' . $id) . ' (' . ($type ? $type->labels->singular_name : $post->post_type) . ')', | |
| 1093 | + ); | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + $term = get_term($id); | |
| 1097 | + if (! $term || is_wp_error($term)) { | |
| 1098 | + return null; | |
| 1099 | + } | |
| 1100 | + $taxonomy = get_taxonomy($term->taxonomy); | |
| 1101 | + $tax_label = $taxonomy ? $taxonomy->labels->singular_name : $term->taxonomy; | |
| 1102 | + $term_name = html_entity_decode($term->name, ENT_QUOTES, 'UTF-8'); | |
| 1103 | + | |
| 1104 | + return array( | |
| 1105 | + 'value' => $key, | |
| 1106 | + 'label' => ! empty($m[3]) | |
| 1107 | + ? sprintf('%s (%s) – all items in it', $term_name, $tax_label) | |
| 1108 | + : sprintf('%s (%s) – archive page', $term_name, $tax_label), | |
| 1109 | + ); | |
| 1110 | + } | |
| 1111 | + | |
| 1112 | + /** | |
| 1113 | + * Search posts (all public post types) and terms (all public taxonomies) for the | |
| 1114 | + * "Specific Pages / Posts / Taxonomies" picker. Returns react-select option groups. | |
| 1115 | + */ | |
| 1116 | + public static function rest_search_content(WP_REST_Request $request) { | |
| 1117 | + $query = trim(sanitize_text_field((string) $request->get_param('q'))); | |
| 1118 | + $groups = array(); | |
| 1119 | + | |
| 1120 | + foreach (self::get_ctc_rule_post_types() as $post_type) { | |
| 1121 | + $args = array( | |
| 1122 | + 'post_type' => $post_type->name, | |
| 1123 | + 'post_status' => 'publish', | |
| 1124 | + 'posts_per_page' => 10, | |
| 1125 | + 'orderby' => '' !== $query ? 'relevance' : 'title', | |
| 1126 | + 'order' => 'ASC', | |
| 1127 | + 'fields' => 'ids', | |
| 1128 | + 'no_found_rows' => true, | |
| 1129 | + ); | |
| 1130 | + if ('' !== $query) { | |
| 1131 | + $args['s'] = $query; | |
| 1132 | + } | |
| 1133 | + $ids = get_posts($args); | |
| 1134 | + | |
| 1135 | + // Allow pasting an ID directly (published items only, like the search results). | |
| 1136 | + if (is_numeric($query) && get_post_type((int) $query) === $post_type->name && 'publish' === get_post_status((int) $query)) { | |
| 1137 | + array_unshift($ids, (int) $query); | |
| 1138 | + } | |
| 1139 | + | |
| 1140 | + $options = array(); | |
| 1141 | + foreach (array_unique(array_map('intval', $ids)) as $id) { | |
| 1142 | + $option = self::get_ctc_specific_option('post-' . $id); | |
| 1143 | + if ($option) { | |
| 1144 | + $options[] = $option; | |
| 1145 | + } | |
| 1146 | + } | |
| 1147 | + if (! empty($options)) { | |
| 1148 | + $groups[] = array('label' => $post_type->labels->name, 'options' => $options); | |
| 1149 | + } | |
| 1150 | + } | |
| 1151 | + | |
| 1152 | + foreach (get_taxonomies(array('public' => true), 'objects') as $taxonomy) { | |
| 1153 | + if (! self::is_ctc_rule_taxonomy($taxonomy)) { | |
| 1154 | + continue; | |
| 1155 | + } | |
| 1156 | + $args = array( | |
| 1157 | + 'taxonomy' => $taxonomy->name, | |
| 1158 | + 'hide_empty' => false, | |
| 1159 | + 'number' => 10, | |
| 1160 | + 'orderby' => 'name', | |
| 1161 | + ); | |
| 1162 | + if ('' !== $query) { | |
| 1163 | + $args['search'] = $query; | |
| 1164 | + } | |
| 1165 | + $terms = get_terms($args); | |
| 1166 | + if (is_wp_error($terms) || empty($terms)) { | |
| 1167 | + continue; | |
| 1168 | + } | |
| 1169 | + | |
| 1170 | + $options = array(); | |
| 1171 | + foreach ($terms as $term) { | |
| 1172 | + foreach (array('tax-' . $term->term_id, 'tax-' . $term->term_id . '-posts') as $key) { | |
| 1173 | + $option = self::get_ctc_specific_option($key); | |
| 1174 | + if ($option) { | |
| 1175 | + $options[] = $option; | |
| 1176 | + } | |
| 1177 | + } | |
| 1178 | + } | |
| 1179 | + $groups[] = array('label' => $taxonomy->labels->name, 'options' => $options); | |
| 1180 | + } | |
| 1181 | + | |
| 1182 | + return new WP_REST_Response($groups, 200); | |
| 1183 | + } | |
| 1184 | + | |
| 1185 | + public static function get_ctc_device_options() { | |
| 1186 | + return array( | |
| 1187 | + 'desktop' => 'Desktop', | |
| 1188 | + 'tablet' => 'Tablet', | |
| 1189 | + 'mobile' => 'Mobile', | |
| 816 | 1190 | ); |
| 817 | 1191 | } |
| 818 | 1192 | |
| 819 | 1193 | // ======================================== |