PluginProbe
Orderable – Restaurant & Food Ordering System / 1.19.0
Orderable – Restaurant & Food Ordering System v1.19.0
0.1.4 0.1.5 0.2.0 1.0.0 1.1.0 1.1.1 1.10.0 1.10.1 1.11.0 1.12.0 1.12.1 1.12.2 1.13.0 1.14.0 1.15.0 1.16.0 1.17.0 1.17.1 1.18.0 1.19.0 1.19.1 1.19.2 1.2.0 1.20.0 1.20.1 All 44 releases
orderable / inc / modules / layouts / class-layouts.php

class-layouts.php in Orderable – Restaurant & Food Ordering System 1.19.0, at inc/modules/layouts/class-layouts.php

570 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Module: Layouts.
4 *
5 * @package Orderable/Classes
6 */
7
8 defined( 'ABSPATH' ) || exit;
9
10 /**
11 * Layouts module class.
12 */
13 class Orderable_Layouts {
14 /**
15 * Layout settings meta key.
16 *
17 * @var string
18 */
19 public static $layout_settings_key = '_orderable_layout_settings';
20
21 /**
22 * Init.
23 */
24 public static function run() {
25 self::load_functions();
26 self::load_classes();
27
28 add_action( 'init', array( __CLASS__, 'add_shortcodes' ) );
29 add_action( 'init', array( __CLASS__, 'register_post_type' ) );
30 add_filter( 'manage_orderable_layouts_posts_columns', array( __CLASS__, 'admin_columns' ), 1 );
31 add_action( 'manage_orderable_layouts_posts_custom_column', array( __CLASS__, 'admin_columns_content' ), 10, 2 );
32 add_action( 'load-post.php', array( __CLASS__, 'init_metabox' ) );
33 add_action( 'load-post-new.php', array( __CLASS__, 'init_metabox' ) );
34 add_action( 'save_post', array( __CLASS__, 'save_meta' ) );
35 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_assets' ) );
36 add_filter( 'orderable_is_settings_page', array( __CLASS__, 'is_settings_page' ) );
37 add_action( 'wp_ajax_orderable_preview', array( __CLASS__, 'render_layout_preview_ajax' ) );
38 add_filter( 'orderable_admin_notices', array( __CLASS__, 'admin_notice' ) );
39 }
40
41 /**
42 * Define settings page.
43 *
44 * @param bool $bool
45 *
46 * @return bool
47 */
48 public static function is_settings_page( $bool = false ) {
49 global $current_screen;
50
51 if ( is_null( $current_screen ) || 'orderable_layouts' !== $current_screen->id ) {
52 return $bool;
53 }
54
55 return true;
56 }
57
58 /**
59 * Load functions file for this module.
60 */
61 public static function load_functions() {
62 require_once ORDERABLE_MODULES_PATH . 'layouts/functions-layouts.php';
63 }
64
65 /**
66 * Load classes for this module.
67 */
68 public static function load_classes() {
69 $classes = array(
70 'layouts-blocks' => 'Orderable_Layouts_Blocks',
71 );
72
73 foreach ( $classes as $file_name => $class_name ) {
74 require_once ORDERABLE_MODULES_PATH . 'layouts/class-' . $file_name . '.php';
75
76 $class_name::run();
77 }
78 }
79
80 /**
81 * Add layout shrotcodes.
82 */
83 public static function add_shortcodes() {
84 add_shortcode( 'orderable', array( __CLASS__, 'orderable_shortcode' ) );
85 }
86
87 /**
88 * Register post type.
89 */
90 public static function register_post_type() {
91 $labels = Orderable_Helpers::prepare_post_type_labels(
92 array(
93 'plural' => __( 'Product Layouts', 'orderable' ),
94 'singular' => __( 'Product Layout', 'orderable' ),
95 )
96 );
97
98 $labels['all_items'] = __( 'Product Layouts', 'orderable' );
99
100 $args = array(
101 'labels' => $labels,
102 'supports' => array( 'title' ),
103 'hierarchical' => false,
104 'public' => false,
105 'show_ui' => true,
106 'show_in_menu' => 'orderable',
107 'show_in_rest' => true,
108 'menu_position' => 20,
109 'show_in_admin_bar' => true,
110 'show_in_nav_menus' => false,
111 'can_export' => true,
112 'has_archive' => true,
113 'exclude_from_search' => true,
114 'publicly_queryable' => false,
115 'capability_type' => 'page',
116 );
117
118 register_post_type( 'orderable_layouts', $args );
119 }
120
121 /**
122 * Post type columns.
123 *
124 * @param array $columns
125 *
126 * @return array
127 */
128 public static function admin_columns( $columns = array() ) {
129 return array(
130 'title' => $columns['title'],
131 'shortcode' => __( 'Shortcode', 'orderable' ),
132 'php_function' => __( 'PHP Function', 'orderable' ),
133 'date' => $columns['date'],
134 );
135 }
136
137 /**
138 * Output post type column content.
139 *
140 * @param string $column_name
141 * @param int $post_ID
142 */
143 public static function admin_columns_content( $column_name, $post_ID ) {
144 if ( 'shortcode' === $column_name ) {
145 echo '<code>[orderable id="' . (int) $post_ID . '"]</code>';
146 } elseif ( 'php_function' === $column_name ) {
147 echo '<code>&lt;?php orderable(' . (int) $post_ID . '); ?&gt;</code>';
148 }
149 }
150
151 /**
152 * Initialize meta boxes.
153 */
154 public static function init_metabox() {
155 add_meta_box(
156 'orderable-layout-settings-metabox',
157 __( 'Layout Settings', 'orderable' ),
158 array( __CLASS__, 'render_layout_settings_metabox' ),
159 'orderable_layouts',
160 'advanced',
161 'default'
162 );
163
164 add_meta_box(
165 'orderable-layout-preview-metabox',
166 __( 'Layout Preview', 'orderable' ),
167 array( __CLASS__, 'render_layout_preview_metabox' ),
168 'orderable_layouts',
169 'advanced',
170 'default'
171 );
172 }
173
174 /**
175 * Save layout meta.
176 *
177 * @param $post_id
178 */
179 public static function save_meta( $post_id ) {
180 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
181 return;
182 }
183
184 /**
185 * Filter the layout settings before saving.
186 *
187 * @since 1.6.0
188 * @hook orderable_layout_settings_save_data
189 * @param array $layout_settings The product layout settings.
190 * @return array New value
191 */
192 $layout_settings = apply_filters(
193 'orderable_layout_settings_save_data',
194 array(
195 'categories' => (array) filter_input( INPUT_POST, 'orderable_categories', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ),
196 'layout' => empty( $_POST['orderable_layout'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['orderable_layout'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
197 'images' => empty( $_POST['orderable_images'] ) ? false : 'yes' === sanitize_text_field( wp_unslash( $_POST['orderable_images'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
198 'card_click' => empty( $_POST['orderable_card_click'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['orderable_card_click'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
199 'quantity_roller' => 'yes' === sanitize_text_field( filter_input( INPUT_POST, 'orderable_quantity_roller' ) ),
200 'sort' => empty( $_POST['orderable_sort'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['orderable_sort'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
201 'sort_on_frontend' => empty( $_POST['orderable_sort_on_frontend'] ) ? false : 'yes' === sanitize_text_field( wp_unslash( $_POST['orderable_sort_on_frontend'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
202 )
203 );
204
205 update_post_meta( $post_id, self::$layout_settings_key, $layout_settings );
206 }
207
208 /**
209 * Render Layout Settings Metabox.
210 *
211 * @param WP_Post $post WP_Post object.
212 *
213 * @return void
214 */
215 public static function render_layout_settings_metabox( $post ) {
216 $layout_settings = self::get_layout_settings( $post );
217
218 include Orderable_Helpers::get_template_path( 'admin/layout-settings-metabox.php', 'layouts' );
219 }
220
221 /**
222 * Get max orders field.
223 *
224 * @param string $field_name The field name. Example: `sort`.
225 * @param array $layout_settings The layout settings.
226 *
227 * @return void|string
228 */
229 public static function get_layout_field( $field_name, $layout_settings ) {
230 if ( empty( $field_name ) ) {
231 return '';
232 }
233
234 $allowed_html = array(
235 'a' => array(
236 'class' => array(),
237 'href' => array(),
238 'target' => array(),
239 ),
240 );
241
242 ob_start();
243 ?>
244 <?php echo wp_kses( Orderable_Helpers::get_pro_button( $field_name ), $allowed_html ); ?>
245 <?php
246
247 /**
248 * Filter the layout field.
249 *
250 * The dynamic portion of the hook name, `$field_name`, refers to
251 * the field name e.g. `sort`, `max-orders`, etc.
252 *
253 * @since 1.10.0
254 * @hook filter_hook
255 * @param string $html The html markup.
256 * @param array $layout_settings The layout settings.
257 * @return string New value
258 */
259 $html = apply_filters( "orderable_layout_{$field_name}_field", ob_get_clean(), $layout_settings );
260
261 echo wp_kses_post( $html );
262 }
263
264 /**
265 * Render Layout Preview Metabox.
266 *
267 * @param WP_Post $post WP_Post object.
268 *
269 * @return void
270 */
271 public static function render_layout_preview_metabox( $post ) {
272 ?>
273 <div class="orderable-layout-preview-notice">
274 <p><?php _e( 'This preview is for demo purposes and is not interactive.', 'orderable' ); ?></p>
275 </div>
276 <div class="orderable-main-wrap">
277 <?php
278 echo do_shortcode( sprintf( '[orderable id="%d"]', $post->ID ) );
279 ?>
280 </div>
281 <?php
282 }
283
284 /**
285 * Render layout from ajax data.
286 */
287 public static function render_layout_preview_ajax() {
288 $data = (array) filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
289
290 if ( empty( $data ) ) {
291 wp_send_json_error();
292 }
293
294 $return = array(
295 'shortcode' => self::orderable_shortcode( $data ),
296 );
297
298 wp_send_json_success( $return );
299 }
300
301 /**
302 * Main orderable shortcode.
303 *
304 * @param array $args
305 * @param string $content
306 * @param string $name
307 *
308 * @return string|void
309 */
310 public static function orderable_shortcode( $args, $content = '', $name = '' ) {
311 $defaults = self::get_layout_defaults();
312
313 $args = wp_parse_args( $args, $defaults );
314 $args['sort_on_frontend'] = (bool) json_decode( strtolower( $args['sort_on_frontend'] ) );
315 $args['images'] = (bool) json_decode( strtolower( $args['images'] ) );
316
317 if ( ! is_null( $args['id'] ) ) {
318 $args = self::get_layout_settings( $args['id'] );
319 }
320
321 if ( ! empty( $args['categories'] ) ) {
322 $args['categories'] = ( is_string( $args['categories'] ) && false !== strpos( $args['categories'], ',' ) ) ? array_filter( explode( ',', $args['categories'] ) ) : $args['categories'];
323 $args['categories'] = is_array( $args['categories'] ) ? $args['categories'] : array( $args['categories'] );
324 $args['categories'] = array_map( 'absint', $args['categories'] );
325 $args['categories'] = self::get_unique_categories( $args['categories'], $args );
326 }
327
328 $args = apply_filters( 'orderable_shortcode_args', $args, $content, $name );
329
330 $products = Orderable_Products::get_products_by_category( $args );
331
332 if ( empty( $products ) ) {
333 return;
334 }
335
336 ob_start();
337
338 include Orderable_Helpers::get_template_path( 'main.php', 'layouts' );
339
340 return ob_get_clean();
341 }
342
343 /**
344 * Get Unique Categories.
345 *
346 * Remove child categories if parent category exists already.
347 *
348 * @param array $categories Categories.
349 * @param array $args Layout Settings.
350 *
351 * @return array
352 */
353 public static function get_unique_categories( $categories, $args ) {
354 /**
355 * Exclude Sections for Unique Categories.
356 *
357 * @param array $exclude_sections The Excluded sections.
358 * @param array $categories The Unfiltered Categories.
359 * @param array $args Layout Settings.
360 *
361 * @return array
362 */
363 $exclude_sections = apply_filters( 'orderable_exclude_sections_for_unique_categories', array( 'side_tabs', 'top_tabs' ), $categories, $args );
364
365 if ( isset( $args['sections'] ) && in_array( $args['sections'], $exclude_sections, true ) ) {
366 $unique_categories = $categories;
367 } else {
368 $unique_categories = array();
369
370 foreach ( $categories as $category_id ) {
371 $ancestors = get_ancestors( $category_id, 'product_cat' );
372
373 if ( count( array_intersect( $ancestors, $categories ) ) > 0 ) {
374 continue;
375 }
376
377 $unique_categories[] = $category_id;
378 }
379 }
380
381 /**
382 * Get Unique Categories.
383 *
384 * @param array $unique_categories The Filtered Categories.
385 * @param array $categories The Unfiltered Categories.
386 * @param array $args Layout Settings.
387 *
388 * @return array
389 */
390 return apply_filters( 'orderable_get_unique_categories', $unique_categories, $categories, $args );
391 }
392
393 /**
394 * Enqueue admin assets.
395 */
396 public static function admin_assets( $hook ) {
397 if ( ! self::is_settings_page() && $hook !== 'post-new.php' && $hook !== 'post.php' ) {
398 return;
399 }
400
401 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
402
403 add_thickbox();
404
405 // Styles.
406 wp_enqueue_style( 'orderable-layouts', ORDERABLE_URL . 'inc/modules/layouts/assets/admin/css/layouts' . $suffix . '.css', array(), ORDERABLE_VERSION );
407
408 // Scripts.
409 wp_enqueue_script( 'thickbox' );
410 wp_enqueue_script( 'orderable-layouts', ORDERABLE_URL . 'inc/modules/layouts/assets/admin/js/main' . $suffix . '.js', array( 'jquery', 'thickbox' ), ORDERABLE_VERSION, true );
411 }
412
413 /**
414 * Get layout settings.
415 *
416 * @param int|WP_Post $layout
417 *
418 * @return array|bool
419 */
420 public static function get_layout_settings( $layout, $string = false ) {
421 if ( ! empty( $layout ) && is_numeric( $layout ) ) {
422 $layout = get_post( $layout );
423 }
424
425 $layout_settings = self::get_layout_defaults();
426
427 if ( ! empty( $layout ) && is_a( $layout, 'WP_Post' ) ) {
428 $layout_settings['id'] = $layout->ID;
429 $saved_layout_settings = get_post_meta( $layout->ID, self::$layout_settings_key, true );
430 $layout_settings = wp_parse_args( $saved_layout_settings, $layout_settings );
431 }
432
433 if ( $string ) {
434 $layout_settings = self::convert_layout_settings_to_string( $layout_settings );
435 }
436
437 return apply_filters( 'orderable_layout_settings', $layout_settings, $layout, $string );
438 }
439
440 /**
441 * Get layout defaults.
442 *
443 * @param null $layout_id
444 *
445 * @return mixed|void
446 */
447 public static function get_layout_defaults( $layout_id = null ) {
448 return apply_filters(
449 'orderable_layout_defaults',
450 array(
451 'id' => $layout_id,
452 'categories' => array(),
453 'layout' => 'grid',
454 'images' => true,
455 'card_click' => '',
456 'quantity_roller' => false,
457 'sort' => 'menu_order',
458 'sort_on_frontend' => false,
459 ),
460 $layout_id
461 );
462 }
463
464 /**
465 * Convert layout settings to string.
466 *
467 * @param array $layout_settings
468 *
469 * @return string
470 */
471 public static function convert_layout_settings_to_string( $layout_settings ) {
472 $layout_settings_array = array();
473
474 if ( ! empty( $layout_settings ) ) {
475 foreach ( $layout_settings as $attribute => $value ) {
476 if ( empty( $value ) && false !== $value ) {
477 continue;
478 }
479
480 if ( is_bool( $value ) ) {
481 $value = $value ? 'true' : 'false';
482 } elseif ( is_array( $value ) ) {
483 $value = implode( ',', $value );
484 }
485
486 $layout_settings_array[] = sprintf( '%s="%s"', $attribute, $value );
487 }
488 }
489
490 return apply_filters( 'orderable_layout_settings_string', implode( ' ', $layout_settings_array ) );
491 }
492
493 /**
494 * Get categories list.
495 *
496 * @param array $categories
497 * @param int $parent
498 * @param int $level
499 *
500 * @return array
501 */
502 public static function get_categories( $categories = array(), $parent = 0, $level = 0 ) {
503 $terms = get_terms(
504 array(
505 'taxonomy' => 'product_cat',
506 'hide_empty' => false,
507 'parent' => $parent,
508 )
509 );
510
511 if ( is_wp_error( $terms ) || empty( $terms ) ) {
512 return $categories;
513 }
514
515 foreach ( $terms as $term ) {
516 $categories[ $term->term_id ] = trim( sprintf( '%s %s', str_repeat( '', $level ), $term->name ) );
517
518 $categories = self::get_categories( $categories, $term->term_id, $level + 1 );
519 }
520
521 return $categories;
522 }
523
524 /**
525 * Add admin notice.
526 *
527 * @param array $notices
528 *
529 * @return array
530 */
531 public static function admin_notice( $notices = array() ) {
532 global $pagenow, $typenow;
533
534 if ( 'orderable_layouts' !== $typenow || 'edit.php' !== $pagenow ) {
535 return $notices;
536 }
537
538 $notices[] = array(
539 'name' => 'layout_builder',
540 'title' => __( 'What are Product Layouts?', 'orderable' ),
541 'description' => __( 'This is where you can create product layouts and customize their settings. Save your layouts here and reuse them later using the block editor, shortcode (great for page builders), or PHP snippet.', 'orderable' ),
542 );
543
544 return $notices;
545 }
546
547 /**
548 * Get product card classes.
549 *
550 * @param array $args
551 *
552 * @return mixed|void
553 */
554 public static function get_product_card_classes( $args = array() ) {
555 $class = array(
556 'orderable-product',
557 );
558
559 if ( empty( $args['images'] ) ) {
560 $class[] = 'orderable-product--no-image';
561 }
562
563 if ( ! empty( $args['card_click'] ) ) {
564 $class[] = 'orderable-product--' . $args['card_click'];
565 }
566
567 return apply_filters( 'orderable_get_product_card_classes', $class, $args );
568 }
569 }
570