PluginProbe
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder / 3.1.4
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder v3.1.4
3.1.4 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.0.7 3.0.5 3.0.4 3.0.3 3.0.2 trunk 1.5.0 1.5.1 1.5.2 1.6.1 1.6.2 1.6.3 1.6.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 All 93 releases
← All changes | includes/builder/builder-cpt.php +516 -412 1.5.03.1.4 View file →
@@ -1,412 +1,516 @@
1 -<?php
2 -
3 -namespace UltimateStoreKit\Includes\Builder;
4 -
5 -use UltimateStoreKit\Base\Singleton;
6 -
7 -if (!defined('ABSPATH')) {
8 - exit;
9 -} // Exit if accessed directly
10 -
11 -class Builder_Cpt {
12 -
13 - use Singleton;
14 -
15 - public function init_hooks() {
16 - $builderCpt = Meta::POST_TYPE;
17 -
18 - add_action('init', [$this, 'registered_post_type']);
19 - add_action('admin_footer', [$this, 'add_modal_html'], 1);
20 - add_action('delete_post', [$this, 'trashed_or_delete_post'], 10, 2);
21 - add_action('trashed_post', [$this, 'trashed_or_delete_post'], 10, 1);
22 -
23 - add_action('wp_ajax_ultimate_store_kit_builder_create_template', [$this, 'create_builder_template']);
24 - add_action('wp_ajax_ultimate_store_kit_builder_get_edit_template', [$this, 'get_builder_template_action']);
25 - add_filter("manage_{$builderCpt}_posts_columns", [$this, 'set_post_columns']);
26 - add_action("manage_{$builderCpt}_posts_custom_column", [$this, 'set_custom_column_value'], 10, 2);
27 - add_filter('post_row_actions', [$this, 'post_row_actions_filter'], 20, 2);
28 -
29 - if (is_admin()) {
30 - add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts'], 1);
31 - add_action('admin_menu', [$this, 'add_admin_menu'], 202);
32 - add_action('restrict_manage_posts', [$this, 'add_filter']);
33 - add_filter('parse_query', [$this, 'parse_query_filter']);
34 - }
35 -
36 - // $this->resetTemplateCache();
37 - }
38 -
39 - public function resetTemplateCache() {
40 - global $wpdb;
41 -
42 - $postType = Meta::POST_TYPE;
43 -
44 - $query = $wpdb->get_results("SELECT {$wpdb->posts}.ID,{$wpdb->posts}.post_type, {$wpdb->posts}.post_status, {$wpdb->postmeta}.meta_value as template_type
45 -FROM $wpdb->posts
46 - LEFT JOIN $wpdb->postmeta
47 - ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID
48 -WHERE 1=1
49 -AND {$wpdb->posts}.post_type ='{$postType}'
50 -AND {$wpdb->postmeta}.meta_key ='_ultimate_store_kit_template_type'
51 -ORDER BY {$wpdb->posts}.post_date DESC");
52 -
53 - foreach ($query as $q) {
54 - if (!$q->template_type) {
55 - continue;
56 - }
57 -
58 - $optionKey = Meta::TEMPLATE_ID . $q->template_type;
59 -
60 - if ($q->post_status == 'publish') {
61 - update_option($optionKey, $q->ID);
62 - } else {
63 - delete_option($optionKey, $q->ID);
64 - }
65 - }
66 - }
67 -
68 - public function trashed_or_delete_post($postId) {
69 - if (get_post_type($postId) != Meta::POST_TYPE) {
70 - return;
71 - }
72 -
73 - if ($template = get_post_meta($postId, Meta::TEMPLATE_TYPE, true)) {
74 - delete_option(Meta::TEMPLATE_ID . $template);
75 - }
76 - }
77 -
78 - public function post_row_actions_filter($actions, $post) {
79 -
80 - global $typenow;
81 -
82 - if ($typenow !== Meta::POST_TYPE) {
83 - return $actions;
84 - }
85 -
86 - if (isset($actions['edit_with_elementor'])) {
87 - unset($actions['edit_with_elementor']);
88 - }
89 -
90 - if (get_post_meta($post->ID, Meta::EDIT_WITH, true) == 'gutenberg') {
91 - $actions['usk_edit_with_gutenberg'] = sprintf(
92 - '<a href="%1$s">%2$s</a>',
93 - add_query_arg(['post' => $post->ID, 'action' => 'edit'], admin_url('post.php')),
94 - esc_html__('Edit with Gutenberg', 'ultimate-store-kit')
95 - );
96 -
97 - }
98 -
99 - if (get_post_meta($post->ID, Meta::EDIT_WITH, true) == 'elementor') {
100 - $actions['usk_edit_with_elementor'] = sprintf(
101 - '<a href="%1$s">%2$s</a>',
102 - add_query_arg(['post' => $post->ID, 'action' => 'elementor','usk-template' => 1], admin_url('post.php')),
103 - esc_html__('Edit with Elementor', 'ultimate-store-kit')
104 - );
105 -
106 - }
107 -
108 - $editActionLink = sprintf(
109 - '<a href="%1$s" data-id="%2$s" >%3$s</a>',
110 - 'javascript:void(0)',
111 - $post->ID,
112 - esc_html__('Edit', 'ultimate-store-kit')
113 - );
114 -
115 - if (isset($actions['edit']) && apply_filters('ultimate_store_kit_remove_action_edit_link', __return_true())) {
116 - unset($actions['edit']);
117 - }
118 -
119 - return array_slice($actions, 0, 1, true) + ['usk-edit-action' => $editActionLink] + array_slice($actions, 1, null, true);
120 - }
121 -
122 - public function set_post_columns($columns) {
123 - return array_slice($columns, 0, 2, true) + ['template_type' => 'Type', 'is_enabled' => 'Status'] + array_slice($columns, 2, null, true);
124 - }
125 -
126 - public function set_custom_column_value($column, $post_id) {
127 - $templateType = get_post_meta(
128 - $post_id,
129 - Meta::TEMPLATE_TYPE,
130 - true
131 - );
132 -
133 - switch ($column) {
134 - case 'template_type':
135 - $postType = Builder_Template_Helper::getTemplatePostTypeByIndex($templateType);
136 - $postTypeLabel = isset($postType->name) ? ' <strong>-- ' . ucwords($postType->name) . '</strong>' : '';
137 -
138 - echo Builder_Template_Helper::getTemplateByIndex($templateType) . $postTypeLabel;
139 - break;
140 - case 'is_enabled':
141 - echo (Builder_Template_Helper::getTemplateId($templateType) == $post_id ? 'Active' : 'Inactive');
142 - break;
143 - }
144 - }
145 -
146 - public function add_filter() {
147 - global $typenow;
148 -
149 - if ($typenow !== Meta::POST_TYPE) {
150 - return;
151 - }
152 -
153 - $selected = isset($_GET['type']) ? sanitize_key($_GET['type']) : '';
154 -?>
155 - <select name="type" id="type">
156 - <option value="all" <?php
157 - selected('all', $selected); ?>><?php
158 - esc_html_e(
159 - 'Template Type ',
160 - 'ultimate-store-kit'
161 - ); ?></option>
162 - <?php
163 - $templates = Builder_Template_Helper::templateForSelectDropdown();
164 - // It is single
165 - if (count($templates) == 1) {
166 - $templateKey = array_key_last($templates);
167 - $template = $templates[$templateKey];
168 - foreach ($template as $key => $item) :
169 - $selectValue = "{$templateKey}_$key";
170 - ?>
171 - <option value="<?php
172 - echo $selectValue ?>"><?php
173 - echo $item ?></option>
174 - <?php
175 - endforeach;
176 - }
177 -
178 - if (count($templates) > 1) {
179 - foreach ($templates as $keys => $items) :
180 - $label = ucwords(str_replace(
181 - ['-', '_'],
182 - [' '],
183 - $keys
184 - ));
185 - if (is_array($items)) {
186 - ?>
187 - <optgroup label="<?php
188 - echo $label ?>"><?php
189 - foreach ($items as $key => $item) :
190 - $itemValue = "{$keys}_$key"
191 - ?>
192 - <option value="<?php
193 - echo $itemValue ?>" <?php
194 - selected($key, $selected); ?>><?php
195 - echo $item ?></option>
196 - <?php
197 - endforeach;
198 - ?>
199 - </optgroup>
200 - <?php
201 - }
202 - endforeach;
203 - }
204 - ?>
205 - </select>
206 -<?php
207 - }
208 -
209 - public function parse_query_filter($query) {
210 - global $pagenow, $typenow;
211 -
212 - if ($typenow !== Meta::POST_TYPE) {
213 - return;
214 - }
215 -
216 - if (
217 - 'edit.php' == $pagenow
218 - && isset($_GET['type'])
219 - && $_GET['type'] != ''
220 - && $_GET['type'] != 'all'
221 - ) {
222 - $query->query_vars['meta_key'] = Meta::TEMPLATE_TYPE;
223 - $query->query_vars['meta_value'] = sanitize_key($_GET['type']);
224 - $query->query_vars['meta_compare'] = '=';
225 - }
226 - }
227 -
228 -
229 - public function create_builder_template() {
230 - parse_str($_POST['data'], $data);
231 -
232 - $templateId = isset($data['template_id']) ? trim($data['template_id']) : '';
233 - $name = isset($data['template_name']) ? trim($data['template_name']) : '';
234 - $type = isset($data['template_type']) ? trim($data['template_type']) : '';
235 - $editWith = isset($data['edit_with']) ? trim($data['edit_with']) : 'elementor'; //gutenberg
236 - $isEnabled = (isset($data['template_status']) && $data['template_status']) == 1 ? 1 : 0;
237 -
238 - $errors = [];
239 -
240 - if (empty($name)) {
241 - $errors['template_name'] = 'Field is required';
242 - }
243 -
244 - if (empty($type)) {
245 - $errors['template_type'] = 'Field is required';
246 - } else {
247 - if (!Builder_Template_Helper::getTemplateByIndex($type)) {
248 - $errors['template_type'] = 'Invalid section';
249 - }
250 - }
251 -
252 -
253 - if (count($errors) > 0) {
254 - wp_send_json_error(['success' => false, 'errors_arr' => $errors], 422);
255 - }
256 -
257 - $page_data = [
258 - 'post_status' => 'publish',
259 - 'post_type' => Meta::POST_TYPE,
260 - 'post_author' => get_current_user_id(),
261 - 'post_title' => $name,
262 - 'comment_status' => 'closed',
263 - 'meta_input' => [
264 - Meta::EDIT_WITH => $editWith,
265 - Meta::TEMPLATE_TYPE => $type,
266 - ],
267 - ];
268 -
269 - global $wp_rewrite;
270 - $wp_rewrite->flush_rules();
271 - $wp_rewrite->init();
272 -
273 - if ($templateId) {
274 - $page_data['ID'] = $templateId;
275 - }
276 -
277 - $post_id = wp_insert_post($page_data);
278 -
279 - $enabledTemplate = strtolower(Meta::TEMPLATE_ID . $type);
280 - if ($isEnabled == 1) {
281 - update_option($enabledTemplate, $post_id);
282 - } else {
283 - if (get_option($enabledTemplate) == $post_id) {
284 - delete_option($enabledTemplate);
285 - }
286 - }
287 -
288 -
289 - if ($editWith == 'elementor') {
290 - if (!get_post_meta($post_id, '_elementor_data', [])) {
291 - update_post_meta($post_id, '_elementor_data', []);
292 - }
293 -
294 - if (!$templateId) {
295 - update_post_meta($post_id, '_elementor_data', []);
296 - }
297 - update_post_meta($post_id, '_wp_page_template', 'elementor_header_footer');
298 - update_post_meta($post_id, '_elementor_edit_mode', 'builder');
299 - update_post_meta($post_id, '_elementor_version', '3.7.1');
300 - }
301 -
302 - if ($templateId) {
303 - $url = add_query_arg(
304 - ['post_type' => Meta::POST_TYPE],
305 - admin_url('edit.php')
306 - );
307 - } else {
308 - $url = add_query_arg([
309 - 'post' => $post_id,
310 - 'action' => $editWith,
311 - ], admin_url('post.php'));
312 - }
313 -
314 - wp_send_json_success(['success' => true, 'redirect' => $url]);
315 - }
316 -
317 - public function get_builder_template_action() {
318 - if (isset($_REQUEST['template_id']) && !empty($_REQUEST['template_id'])) {
319 - $templateId = $_REQUEST['template_id'];
320 - $templateData = get_post($templateId);
321 -
322 - if ($templateData) {
323 - $meta = get_post_meta($templateData->ID);
324 -
325 -
326 - $templateType = isset($meta[Meta::TEMPLATE_TYPE][0]) ? $meta[Meta::TEMPLATE_TYPE][0] : '';
327 - $enabledTemplate = strtolower(Meta::TEMPLATE_ID . $templateType);
328 - $enabledTemplate = get_option($enabledTemplate);
329 -
330 - wp_send_json_success([
331 - 'id' => $templateData->ID,
332 - 'name' => $templateData->post_title,
333 - 'type' => $templateType,
334 - 'status' => is_numeric($enabledTemplate) ? 1 : 0,
335 - ]);
336 - }
337 - }
338 - }
339 -
340 - public function add_modal_html($hook_suffix) {
341 - require_once 'modal/modal.php';
342 - }
343 -
344 - public function enqueue_scripts($hook_suffix) {
345 - if (in_array($hook_suffix, ['edit.php', 'post-new.php'])) {
346 - $screen = get_current_screen();
347 -
348 - if (is_object($screen) && Meta::POST_TYPE == $screen->post_type) {
349 - wp_enqueue_style('ultimate-store-kit-builder', BDTUSK_ADM_ASSETS_URL . 'css/ultimate-builder.css', [], BDTUSK_VER);
350 - wp_enqueue_script('ultimate-store-kit-builder', BDTUSK_ADM_ASSETS_URL . 'js/ultimate-builder.js', ['jquery'], BDTUSK_VER);
351 - }
352 - }
353 - }
354 -
355 -
356 - public function add_admin_menu() {
357 - add_submenu_page(
358 - 'ultimate_store_kit_options',
359 - esc_html__('Template Builder', 'ultimate-store-kit'),
360 - esc_html__('Template Builder', 'ultimate-store-kit'),
361 - 'edit_pages',
362 - 'edit.php?post_type=' . Meta::POST_TYPE
363 - );
364 - }
365 -
366 - public function registered_post_type() {
367 - $labels = [
368 - 'name' => _x('Template Items', 'post type general name', 'ultimate-store-kit'),
369 - 'singular_name' => _x('Template Item', 'post type singular name', 'ultimate-store-kit'),
370 - 'menu_name' => _x('Template Manager', 'admin menu', 'ultimate-store-kit'),
371 - 'name_admin_bar' => _x('Template Manager', 'add new on admin bar', 'ultimate-store-kit'),
372 - 'add_new' => _x('Add New', 'template_manager', 'ultimate-store-kit'),
373 - 'add_new_item' => __('Add New Template', 'ultimate-store-kit'),
374 - 'new_item' => __('New Template', 'ultimate-store-kit'),
375 - 'edit_item' => __('Edit Template', 'ultimate-store-kit'),
376 - 'view_item' => __('View Template', 'ultimate-store-kit'),
377 - 'all_items' => __('All Templates', 'ultimate-store-kit'),
378 - 'search_items' => __('Search Templates', 'ultimate-store-kit'),
379 - 'parent_item_colon' => __('Parent Template:', 'ultimate-store-kit'),
380 - 'not_found' => __('No Template found.', 'ultimate-store-kit'),
381 - 'not_found_in_trash' => __('No Template found in Trash.', 'ultimate-store-kit'),
382 - ];
383 -
384 - $args = [
385 - 'labels' => $labels,
386 - 'description' => __('Description.', 'ultimate-store-kit'),
387 - 'taxonomies' => [],
388 - 'hierarchical' => false,
389 - 'public' => true,
390 - 'show_in_menu' => false,
391 - 'show_ui' => true,
392 - 'show_in_admin_bar' => true,
393 - 'menu_position' => null,
394 - 'menu_icon' => null,
395 - 'publicly_queryable' => true,
396 - 'supports' => ['title', 'editor', 'elementor'],
397 - 'exclude_from_search' => true,
398 - 'has_archive' => false,
399 - 'query_var' => true,
400 - 'can_export' => true,
401 - 'rewrite' => false,
402 - 'show_in_nav_menus' => false,
403 - 'capability_type' => 'post',
404 - // 'rest_base' => $this->getPostType(),
405 - // 'register_meta_box_cb' => [ $this, 'register_meta_box_cb' ],
406 - ];
407 -
408 - register_post_type(Meta::POST_TYPE, $args);
409 - }
410 -}
411 -
412 -Builder_Cpt::instance()->init_hooks();
1 +<?php
2 +
3 +namespace UltimateStoreKit\Includes\Builder;
4 +
5 +use UltimateStoreKit\Base\Singleton;
6 +
7 +if (! defined('ABSPATH')) {
8 + exit;
9 +}
10 +
11 +class Builder_Cpt {
12 +
13 + use Singleton;
14 +
15 + public function init_hooks() {
16 + $builderCpt = Meta::POST_TYPE;
17 +
18 + add_action('init', [$this, 'registered_post_type']);
19 + add_action('admin_footer', [$this, 'add_modal_html'], 1);
20 + add_action('delete_post', [$this, 'trashed_or_delete_post'], 10, 2);
21 + add_action('trashed_post', [$this, 'trashed_or_delete_post'], 10, 1);
22 +
23 + add_action('wp_ajax_ultimate_store_kit_builder_create_template', [$this, 'create_builder_template']);
24 + add_action('wp_ajax_ultimate_store_kit_builder_get_edit_template', [$this, 'get_builder_template_action']);
25 + add_filter("manage_{$builderCpt}_posts_columns", [$this, 'set_post_columns']);
26 + add_action("manage_{$builderCpt}_posts_custom_column", [$this, 'set_custom_column_value'], 10, 2);
27 + add_filter('post_row_actions', [$this, 'post_row_actions_filter'], 20, 2);
28 +
29 + // Simple WPML fix
30 + if (function_exists('icl_object_id')) {
31 + add_filter('elementor/editor/before_enqueue_scripts', [$this, 'fix_wpml_elementor_data'], 1);
32 + }
33 +
34 + if (is_admin()) {
35 + add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts'], 1);
36 + add_action('admin_menu', [$this, 'add_admin_menu'], 202);
37 + add_action('restrict_manage_posts', [$this, 'add_filter']);
38 + add_filter('parse_query', [$this, 'parse_query_filter']);
39 + }
40 +
41 + // $this->resetTemplateCache();
42 + }
43 +
44 + public function resetTemplateCache() {
45 + global $wpdb;
46 +
47 + $postType = Meta::POST_TYPE;
48 +
49 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Rebuilds the template cache; this is the call that populates it.
50 + $query = $wpdb->get_results($wpdb->prepare(
51 + "SELECT {$wpdb->posts}.ID, {$wpdb->posts}.post_type, {$wpdb->posts}.post_status, {$wpdb->postmeta}.meta_value as template_type
52 + FROM {$wpdb->posts}
53 + LEFT JOIN {$wpdb->postmeta}
54 + ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID
55 + WHERE 1=1
56 + AND {$wpdb->posts}.post_type = %s
57 + AND {$wpdb->postmeta}.meta_key = %s
58 + ORDER BY {$wpdb->posts}.post_date DESC",
59 + $postType,
60 + '_ultimate_store_kit_template_type'
61 + ));
62 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
63 +
64 + foreach ($query as $q) {
65 + if (! $q->template_type) {
66 + continue;
67 + }
68 +
69 + if ($q->post_status == 'publish') {
70 + Meta::update_template_option($q->template_type, $q->ID);
71 + } else {
72 + Meta::delete_template_option($q->template_type);
73 + }
74 + }
75 + }
76 +
77 + public function trashed_or_delete_post($postId) {
78 + if (get_post_type($postId) != Meta::POST_TYPE) {
79 + return;
80 + }
81 +
82 + if ($template = get_post_meta($postId, Meta::TEMPLATE_TYPE, true)) {
83 + Meta::delete_template_option($template);
84 + }
85 + }
86 +
87 + public function post_row_actions_filter($actions, $post) {
88 +
89 + global $typenow;
90 +
91 + if ($typenow !== Meta::POST_TYPE) {
92 + return $actions;
93 + }
94 +
95 + if (isset($actions['edit_with_elementor'])) {
96 + unset($actions['edit_with_elementor']);
97 + }
98 +
99 + if (get_post_meta($post->ID, Meta::EDIT_WITH, true) == 'gutenberg') {
100 + $actions['usk_edit_with_gutenberg'] = sprintf(
101 + '<a href="%1$s">%2$s</a>',
102 + add_query_arg(['post' => $post->ID, 'action' => 'edit'], admin_url('post.php')),
103 + esc_html__('Edit with Gutenberg', 'ultimate-store-kit')
104 + );
105 + }
106 +
107 + if (get_post_meta($post->ID, Meta::EDIT_WITH, true) == 'elementor') {
108 + $actions['usk_edit_with_elementor'] = sprintf(
109 + '<a href="%1$s">%2$s</a>',
110 + add_query_arg(
111 + [
112 + 'post' => $post->ID,
113 + 'action' => 'elementor',
114 + 'usk-template' => 1
115 + ],
116 + admin_url('post.php')
117 + ),
118 + esc_html__('Edit with Elementor', 'ultimate-store-kit')
119 + );
120 + } else {
121 + // Always offer Elementor edit option regardless of stored preference
122 + $actions['usk_edit_with_elementor'] = sprintf(
123 + '<a href="%1$s">%2$s</a>',
124 + add_query_arg(
125 + [
126 + 'post' => $post->ID,
127 + 'action' => 'elementor',
128 + 'usk-template' => 1
129 + ],
130 + admin_url('post.php')
131 + ),
132 + esc_html__('Edit with Elementor', 'ultimate-store-kit')
133 + );
134 + }
135 +
136 + $editActionLink = sprintf(
137 + '<a href="%1$s" data-id="%2$s" >%3$s</a>',
138 + 'javascript:void(0)',
139 + $post->ID,
140 + esc_html__('Edit', 'ultimate-store-kit')
141 + );
142 +
143 + if (isset($actions['edit']) && apply_filters('ultimate_store_kit_remove_action_edit_link', __return_true())) {
144 + unset($actions['edit']);
145 + }
146 +
147 + return array_slice($actions, 0, 1, true) + ['usk-edit-action' => $editActionLink] + array_slice($actions, 1, null, true);
148 + }
149 +
150 + public function set_post_columns($columns) {
151 + return array_slice($columns, 0, 2, true) + [
152 + 'template_type' => esc_html__('Type', 'ultimate-store-kit'),
153 + 'is_enabled' => esc_html__('Status', 'ultimate-store-kit')
154 + ] + array_slice($columns, 2, null, true);
155 + }
156 +
157 + public function set_custom_column_value($column, $post_id) {
158 + $templateType = get_post_meta(
159 + $post_id,
160 + Meta::TEMPLATE_TYPE,
161 + true
162 + );
163 +
164 + switch ($column) {
165 + case 'template_type':
166 + $postType = Builder_Template_Helper::getTemplatePostTypeByIndex($templateType);
167 + echo esc_html(Builder_Template_Helper::getTemplateByIndex($templateType));
168 + if (isset($postType->name)) {
169 + echo ' <strong>-- ' . esc_html(ucwords($postType->name)) . '</strong>';
170 + }
171 + break;
172 + case 'is_enabled':
173 + echo Builder_Template_Helper::getTemplateId($templateType) == $post_id
174 + ? esc_html__('Active', 'ultimate-store-kit')
175 + : esc_html__('Inactive', 'ultimate-store-kit');
176 + break;
177 + }
178 + }
179 +
180 + public function add_filter() {
181 + global $typenow;
182 +
183 + if ($typenow !== Meta::POST_TYPE) {
184 + return;
185 + }
186 +
187 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin list-table filter; the value only re-selects the current dropdown option.
188 + $selected = isset($_GET['type']) ? sanitize_text_field(wp_unslash($_GET['type'])) : '';
189 +?>
190 + <select name="type" id="type">
191 + <option value="all" <?php
192 + selected('all', $selected); ?>><?php
193 + esc_html_e(
194 + 'Template Type ',
195 + 'ultimate-store-kit'
196 + ); ?></option>
197 + <?php
198 + $templates = Builder_Template_Helper::templateForSelectDropdown();
199 + // It is single
200 + if (count($templates) == 1) {
201 + $templateKey = array_key_last($templates);
202 + $template = $templates[$templateKey];
203 + foreach ($template as $key => $item) :
204 + $selectValue = "{$templateKey}_$key";
205 + ?>
206 + <option value="<?php
207 + echo esc_attr($selectValue) ?>"><?php
208 + echo wp_kses_post($item) ?></option>
209 + <?php
210 + endforeach;
211 + }
212 +
213 + if (count($templates) > 1) {
214 + foreach ($templates as $keys => $items) :
215 + $label = ucwords(str_replace(
216 + ['-', '_'],
217 + [' '],
218 + $keys
219 + ));
220 + if (is_array($items)) {
221 + ?>
222 + <optgroup label="<?php
223 + echo esc_attr($label) ?>"><?php
224 + foreach ($items as $key => $item) :
225 + $itemValue = "{$keys}_$key"
226 + ?>
227 + <option value="<?php
228 + echo esc_attr($itemValue) ?>" <?php
229 + selected($key, $selected); ?>><?php
230 + echo wp_kses_post($item) ?></option>
231 + <?php
232 + endforeach;
233 + ?>
234 + </optgroup>
235 + <?php
236 + }
237 + endforeach;
238 + }
239 + ?>
240 + </select>
241 +<?php
242 + }
243 +
244 + public function parse_query_filter($query) {
245 + global $pagenow, $typenow;
246 +
247 + if ($typenow !== Meta::POST_TYPE) {
248 + return;
249 + }
250 +
251 + // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.DB.SlowDBQuery -- Admin list-table filter; the value only narrows the query that is already running.
252 + if (
253 + 'edit.php' == $pagenow
254 + && isset($_GET['type'])
255 + && $_GET['type'] != ''
256 + && $_GET['type'] != 'all'
257 + ) {
258 + $requested_type = sanitize_text_field(wp_unslash($_GET['type']));
259 +
260 + if (Builder_Template_Helper::getTemplateByIndex($requested_type)) {
261 + $query->query_vars['meta_key'] = Meta::TEMPLATE_TYPE;
262 + $query->query_vars['meta_value'] = $requested_type;
263 + $query->query_vars['meta_compare'] = '=';
264 + }
265 + }
266 + // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.DB.SlowDBQuery
267 + }
268 +
269 +
270 + public function create_builder_template() {
271 +
272 + if (! current_user_can('manage_options')) {
273 + wp_send_json_error(['success' => false, 'errors_arr' => ['permission' => 'Permission denied']], 403);
274 + }
275 +
276 + $data = [];
277 + // The form arrives as one serialized string, so it is unslashed before parsing
278 + // and every field is sanitized individually below — parse_str itself does not
279 + // sanitize anything.
280 + if (isset($_POST['data'])) {
281 + parse_str(wp_unslash($_POST['data']), $data); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Serialized form string; every parsed field is sanitized individually below.
282 + }
283 +
284 + $nonce = isset($data['nonce']) ? sanitize_text_field($data['nonce']) : '';
285 +
286 + if (! wp_verify_nonce($nonce, 'usk-builder')) {
287 + wp_send_json_error(['success' => false, 'errors_arr' => ['nonce' => 'Invalid nonce']], 403);
288 + }
289 +
290 + $templateId = isset($data['template_id']) ? absint($data['template_id']) : 0;
291 + $name = isset($data['template_name']) ? sanitize_text_field($data['template_name']) : '';
292 + $type = isset($data['template_type']) ? sanitize_text_field($data['template_type']) : '';
293 + $editWith = isset($data['edit_with']) ? sanitize_key($data['edit_with']) : 'elementor'; //gutenberg
294 + $isEnabled = (isset($data['template_status']) && $data['template_status']) == 1 ? 1 : 0;
295 +
296 + // Only these two editors are ever handled below, and the value ends up in a
297 + // redirect URL, so anything else falls back to the default.
298 + if (! in_array($editWith, ['elementor', 'gutenberg'], true)) {
299 + $editWith = 'elementor';
300 + }
301 +
302 + $errors = [];
303 +
304 + if (empty($name)) {
305 + $errors['template_name'] = 'Field is required';
306 + }
307 +
308 + if (empty($type)) {
309 + $errors['template_type'] = 'Field is required';
310 + } else {
311 + if (! Builder_Template_Helper::getTemplateByIndex($type)) {
312 + $errors['template_type'] = 'Invalid section';
313 + }
314 + }
315 +
316 +
317 + if (count($errors) > 0) {
318 + wp_send_json_error(['success' => false, 'errors_arr' => $errors], 422);
319 + }
320 +
321 + $page_data = [
322 + 'post_status' => 'publish',
323 + 'post_type' => Meta::POST_TYPE,
324 + 'post_author' => get_current_user_id(),
325 + 'post_title' => $name,
326 + 'comment_status' => 'closed',
327 + 'meta_input' => [
328 + Meta::EDIT_WITH => $editWith,
329 + Meta::TEMPLATE_TYPE => $type,
330 + ],
331 + ];
332 +
333 + global $wp_rewrite;
334 + $wp_rewrite->flush_rules();
335 + $wp_rewrite->init();
336 +
337 + if ($templateId) {
338 + $page_data['ID'] = $templateId;
339 + }
340 +
341 + $post_id = wp_insert_post($page_data);
342 +
343 + if ($isEnabled == 1) {
344 + Meta::update_template_option($type, $post_id);
345 + } else {
346 + if (Meta::get_template_option($type) == $post_id) {
347 + Meta::delete_template_option($type);
348 + }
349 + }
350 +
351 +
352 + if ($editWith == 'elementor') {
353 + if (! get_post_meta($post_id, '_elementor_data')) {
354 + update_post_meta($post_id, '_elementor_data', []);
355 + }
356 +
357 + if (! $templateId) {
358 + update_post_meta($post_id, '_elementor_data', []);
359 + }
360 + update_post_meta($post_id, '_wp_page_template', 'elementor_header_footer');
361 + update_post_meta($post_id, '_elementor_edit_mode', 'builder');
362 + update_post_meta($post_id, '_elementor_version', '3.7.1');
363 + }
364 +
365 + if ($templateId) {
366 + $url = add_query_arg(
367 + ['post_type' => Meta::POST_TYPE],
368 + admin_url('edit.php')
369 + );
370 + } else {
371 + $url = add_query_arg([
372 + 'post' => $post_id,
373 + 'action' => $editWith,
374 + ], admin_url('post.php'));
375 + }
376 +
377 + wp_send_json_success(['success' => true, 'redirect' => $url]);
378 + }
379 +
380 + public function get_builder_template_action() {
381 +
382 + if (! current_user_can('manage_options')) {
383 + wp_send_json_error(['success' => false, 'errors_arr' => ['permission' => 'Permission denied']], 403);
384 + }
385 +
386 + $nonce = isset($_REQUEST['nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['nonce'])) : '';
387 +
388 + if (! wp_verify_nonce($nonce, 'ultimate_store_kit_builder_nonce')) {
389 + wp_send_json_error(['success' => false, 'errors_arr' => ['nonce' => 'Invalid nonce']], 403);
390 + }
391 +
392 + if (isset($_REQUEST['template_id']) && ! empty($_REQUEST['template_id'])) {
393 + $templateId = absint($_REQUEST['template_id']);
394 + $templateData = get_post($templateId);
395 +
396 + if ($templateData && $templateData->post_type === Meta::POST_TYPE) {
397 + $meta = get_post_meta($templateData->ID);
398 +
399 +
400 + $templateType = isset($meta[Meta::TEMPLATE_TYPE][0]) ? $meta[Meta::TEMPLATE_TYPE][0] : '';
401 + $enabledTemplate = Meta::get_template_option($templateType);
402 +
403 + wp_send_json_success([
404 + 'id' => $templateData->ID,
405 + 'name' => $templateData->post_title,
406 + 'type' => $templateType,
407 + 'status' => is_numeric($enabledTemplate) ? 1 : 0,
408 + ]);
409 + }
410 + }
411 +
412 + wp_send_json_error(['success' => false, 'errors_arr' => ['template' => 'Template not found']], 404);
413 + }
414 +
415 + public function add_modal_html($hook_suffix) {
416 + require_once 'modal/modal.php';
417 + }
418 +
419 + public function enqueue_scripts($hook_suffix) {
420 + if (in_array($hook_suffix, ['edit.php', 'post-new.php'])) {
421 + $screen = get_current_screen();
422 +
423 + if (is_object($screen) && Meta::POST_TYPE == $screen->post_type) {
424 + wp_enqueue_style('ultimate-store-kit-builder', BDTUSK_ASSETS_URL . 'admin/others/css/ultimate-builder.css', [], BDTUSK_VER);
425 + wp_enqueue_script('ultimate-store-kit-builder', BDTUSK_ASSETS_URL . 'admin/others/js/ultimate-builder.js', ['jquery', 'wp-i18n'], BDTUSK_VER, true);
426 + wp_set_script_translations('ultimate-store-kit-builder', 'ultimate-store-kit');
427 +
428 + wp_localize_script('ultimate-store-kit-builder', 'UltimateStoreKitConfigBuilder', [
429 + 'ajaxurl' => admin_url('admin-ajax.php'),
430 + 'nonce' => wp_create_nonce('ultimate_store_kit_builder_nonce'),
431 + 'resturl' => rest_url('usk/v1/'),
432 + ]);
433 + }
434 + }
435 + }
436 +
437 +
438 + public function add_admin_menu() {
439 + add_submenu_page(
440 + 'ultimate-store-kit',
441 + esc_html__('Template Builder', 'ultimate-store-kit'),
442 + esc_html__('Template Builder', 'ultimate-store-kit'),
443 + 'manage_options',
444 + 'edit.php?post_type=' . Meta::POST_TYPE
445 + );
446 + }
447 +
448 + public function registered_post_type() {
449 + $labels = [
450 + 'name' => _x('Template Items', 'post type general name', 'ultimate-store-kit'),
451 + 'singular_name' => _x('Template Item', 'post type singular name', 'ultimate-store-kit'),
452 + 'menu_name' => _x('Template Manager', 'admin menu', 'ultimate-store-kit'),
453 + 'name_admin_bar' => _x('Template Manager', 'add new on admin bar', 'ultimate-store-kit'),
454 + 'add_new' => _x('Add New', 'template_manager', 'ultimate-store-kit'),
455 + 'add_new_item' => __('Add New Template', 'ultimate-store-kit'),
456 + 'new_item' => __('New Template', 'ultimate-store-kit'),
457 + 'edit_item' => __('Edit Template', 'ultimate-store-kit'),
458 + 'view_item' => __('View Template', 'ultimate-store-kit'),
459 + 'all_items' => __('All Templates', 'ultimate-store-kit'),
460 + 'search_items' => __('Search Templates', 'ultimate-store-kit'),
461 + 'parent_item_colon' => __('Parent Template:', 'ultimate-store-kit'),
462 + 'not_found' => __('No Template found.', 'ultimate-store-kit'),
463 + 'not_found_in_trash' => __('No Template found in Trash.', 'ultimate-store-kit'),
464 + ];
465 +
466 + $args = [
467 + 'labels' => $labels,
468 + 'description' => __('Description.', 'ultimate-store-kit'),
469 + 'taxonomies' => [],
470 + 'hierarchical' => false,
471 + 'public' => true,
472 + 'show_in_menu' => false,
473 + 'show_ui' => true,
474 + 'show_in_admin_bar' => true,
475 + 'menu_position' => null,
476 + 'menu_icon' => null,
477 + 'publicly_queryable' => true,
478 + 'supports' => ['title', 'editor', 'elementor'],
479 + 'exclude_from_search' => true,
480 + 'has_archive' => false,
481 + 'query_var' => true,
482 + 'can_export' => true,
483 + 'rewrite' => false,
484 + 'show_in_nav_menus' => false,
485 + 'capability_type' => 'post',
486 + // 'rest_base' => $this->getPostType(),
487 + // 'register_meta_box_cb' => [ $this, 'register_meta_box_cb' ],
488 + ];
489 +
490 + register_post_type(Meta::POST_TYPE, $args);
491 +
492 + // Fix WPML integration with Elementor
493 + if (function_exists('icl_object_id')) {
494 + add_filter('wpml_pb_elementor_get_data', [$this, 'fix_wpml_elementor_data'], 10, 2);
495 + }
496 + }
497 +
498 + /**
499 + * Simple fix for WPML and Elementor integration
500 + */
501 + public function fix_wpml_elementor_data() {
502 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reads the post being edited so WPML/Elementor metadata can be normalised.
503 + $post_id = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : 0;
504 +
505 + if ($post_id && get_post_type($post_id) === Meta::POST_TYPE) {
506 + $meta_data = get_post_meta($post_id, '_elementor_data', true);
507 +
508 + // If metadata exists but is in array format, convert it to JSON string
509 + if (is_array($meta_data)) {
510 + update_post_meta($post_id, '_elementor_data', wp_json_encode($meta_data));
511 + }
512 + }
513 + }
514 +}
515 +
516 +Builder_Cpt::instance()->init_hooks();