PluginProbe
Orderable – Restaurant & Food Ordering System / 1.10.0
Orderable – Restaurant & Food Ordering System v1.10.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.10.0, at inc/modules/layouts/class-layouts.php

566 lines 15.5 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' => true,
111 'can_export' => true,
112 'has_archive' => true,
113 'exclude_from_search' => false,
114 'publicly_queryable' => true,
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 } else if ( '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 to be saved.
186 *
187 * @since 1.0.0
188 * @hook orderable_layout_settings_save_data
189 * @param array $data The data to be saved.
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 'sort' => empty( $_POST['orderable_sort'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['orderable_sort'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
198 '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
199 'images' => empty( $_POST['orderable_images'] ) ? false : 'yes' === sanitize_text_field( wp_unslash( $_POST['orderable_images'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
200 'card_click' => empty( $_POST['orderable_card_click'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['orderable_card_click'] ) ), // phpcs:ignore WordPress.Security.NonceVerification
201 )
202 );
203
204 update_post_meta( $post_id, self::$layout_settings_key, $layout_settings );
205 }
206
207 /**
208 * Render Layout Settings Metabox.
209 *
210 * @param WP_Post $post WP_Post object.
211 *
212 * @return void
213 */
214 public static function render_layout_settings_metabox( $post ) {
215 $layout_settings = self::get_layout_settings( $post );
216
217 include Orderable_Helpers::get_template_path( 'admin/layout-settings-metabox.php', 'layouts' );
218 }
219
220 /**
221 * Get max orders field.
222 *
223 * @param string $field_name The field name. Example: `sort`.
224 * @param array $layout_settings The layout settings.
225 *
226 * @return string
227 */
228 public static function get_layout_field( $field_name, $layout_settings ) {
229 if ( empty( $field_name ) ) {
230 return '';
231 }
232
233 $allowed_html = array(
234 'a' => array(
235 'class' => array(),
236 'href' => array(),
237 'target' => array(),
238 ),
239 );
240
241 ob_start();
242 ?>
243 <?php echo wp_kses( Orderable_Helpers::get_pro_button( $field_name ), $allowed_html ); ?>
244 <?php
245
246 /**
247 * Filter the layout field.
248 *
249 * The dynamic portion of the hook name, `$field_name`, refers to
250 * the field name e.g. `sort`, `max-orders`, etc.
251 *
252 * @since 1.10.0
253 * @hook filter_hook
254 * @param string $html The html markup.
255 * @param array $layout_settings The layout settings.
256 * @return string New value
257 */
258 $html = apply_filters( "orderable_layout_{$field_name}_field", ob_get_clean(), $layout_settings );
259
260 echo wp_kses_post( $html );
261 }
262
263 /**
264 * Render Layout Preview Metabox.
265 *
266 * @param WP_Post $post WP_Post object.
267 *
268 * @return void
269 */
270 public static function render_layout_preview_metabox( $post ) {
271 ?>
272 <div class="orderable-layout-preview-notice">
273 <p><?php _e( 'This preview is for demo purposes and is not interactive.', 'orderable' ); ?></p>
274 </div>
275 <div class="orderable-main-wrap">
276 <?php
277 echo do_shortcode( sprintf( '[orderable id="%d"]', $post->ID ) );
278 ?>
279 </div>
280 <?php
281 }
282
283 /**
284 * Render layout from ajax data.
285 */
286 public static function render_layout_preview_ajax() {
287 $data = (array) filter_input( INPUT_POST, 'data', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
288
289 if ( empty( $data ) ) {
290 wp_send_json_error();
291 }
292
293 $return = array(
294 'shortcode' => self::orderable_shortcode( $data ),
295 );
296
297 wp_send_json_success( $return );
298 }
299
300 /**
301 * Main orderable shortcode.
302 *
303 * @param array $args
304 * @param string $content
305 * @param string $name
306 *
307 * @return string|void
308 */
309 public static function orderable_shortcode( $args, $content = '', $name = '' ) {
310 $defaults = self::get_layout_defaults();
311
312 $args = wp_parse_args( $args, $defaults );
313 $args['sort_on_frontend'] = (bool) json_decode( strtolower( $args['sort_on_frontend'] ) );
314 $args['images'] = (bool) json_decode( strtolower( $args['images'] ) );
315
316 if ( ! is_null( $args['id'] ) ) {
317 $args = self::get_layout_settings( $args['id'] );
318 }
319
320 if ( ! empty( $args['categories'] ) ) {
321 $args['categories'] = ( is_string( $args['categories'] ) && false !== strpos( $args['categories'], ',' ) ) ? array_filter( explode( ',', $args['categories'] ) ) : $args['categories'];
322 $args['categories'] = is_array( $args['categories'] ) ? $args['categories'] : array( $args['categories'] );
323 $args['categories'] = array_map( 'absint', $args['categories'] );
324 $args['categories'] = self::get_unique_categories( $args['categories'], $args );
325 }
326
327 $args = apply_filters( 'orderable_shortcode_args', $args, $content, $name );
328
329 $products = Orderable_Products::get_products_by_category( $args );
330
331 if ( empty( $products ) ) {
332 return;
333 }
334
335 ob_start();
336
337 include Orderable_Helpers::get_template_path( 'main.php', 'layouts' );
338
339 return ob_get_clean();
340 }
341
342 /**
343 * Get Unique Categories.
344 *
345 * Remove child categories if parent category exists already.
346 *
347 * @param array $categories Categories.
348 * @param array $args Layout Settings.
349 *
350 * @return array
351 */
352 public static function get_unique_categories( $categories, $args ) {
353 /**
354 * Exclude Sections for Unique Categories.
355 *
356 * @param array $exclude_sections The Excluded sections.
357 * @param array $categories The Unfiltered Categories.
358 * @param array $args Layout Settings.
359 *
360 * @return array
361 */
362 $exclude_sections = apply_filters( 'orderable_exclude_sections_for_unique_categories', array( 'side_tabs', 'top_tabs' ), $categories, $args );
363
364 if ( isset( $args['sections'] ) && in_array( $args['sections'], $exclude_sections, true ) ) {
365 $unique_categories = $categories;
366 } else {
367 $unique_categories = array();
368
369 foreach ( $categories as $category_id ) {
370 $ancestors = get_ancestors( $category_id, 'product_cat' );
371
372 if ( count( array_intersect( $ancestors, $categories ) ) > 0 ) {
373 continue;
374 }
375
376 $unique_categories[] = $category_id;
377 }
378 }
379
380 /**
381 * Get Unique Categories.
382 *
383 * @param array $unique_categories The Filtered Categories.
384 * @param array $categories The Unfiltered Categories.
385 * @param array $args Layout Settings.
386 *
387 * @return array
388 */
389 return apply_filters( 'orderable_get_unique_categories', $unique_categories, $categories, $args );
390 }
391
392 /**
393 * Enqueue admin assets.
394 */
395 public static function admin_assets( $hook ) {
396 if ( ! self::is_settings_page() && $hook !== 'post-new.php' && $hook !== 'post.php' ) {
397 return;
398 }
399
400 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
401
402 add_thickbox();
403
404 // Styles.
405 wp_enqueue_style( 'orderable-layouts', ORDERABLE_URL . 'inc/modules/layouts/assets/admin/css/layouts' . $suffix . '.css', array(), ORDERABLE_VERSION );
406
407 // Scripts.
408 wp_enqueue_script( 'thickbox' );
409 wp_enqueue_script( 'orderable-layouts', ORDERABLE_URL . 'inc/modules/layouts/assets/admin/js/main' . $suffix . '.js', array( 'jquery', 'thickbox' ), ORDERABLE_VERSION, true );
410 }
411
412 /**
413 * Get layout settings.
414 *
415 * @param int|WP_Post $layout
416 *
417 * @return array|bool
418 */
419 public static function get_layout_settings( $layout, $string = false ) {
420 if ( ! empty( $layout ) && is_numeric( $layout ) ) {
421 $layout = get_post( $layout );
422 }
423
424 $layout_settings = self::get_layout_defaults();
425
426 if ( ! empty( $layout ) && is_a( $layout, 'WP_Post' ) ) {
427 $layout_settings['id'] = $layout->ID;
428 $saved_layout_settings = get_post_meta( $layout->ID, self::$layout_settings_key, true );
429 $layout_settings = wp_parse_args( $saved_layout_settings, $layout_settings );
430 }
431
432 if ( $string ) {
433 $layout_settings = self::convert_layout_settings_to_string( $layout_settings );
434 }
435
436 return apply_filters( 'orderable_layout_settings', $layout_settings, $layout, $string );
437 }
438
439 /**
440 * Get layout defaults.
441 *
442 * @param null $layout_id
443 *
444 * @return mixed|void
445 */
446 public static function get_layout_defaults( $layout_id = null ) {
447 return apply_filters(
448 'orderable_layout_defaults',
449 array(
450 'id' => $layout_id,
451 'categories' => array(),
452 'layout' => 'grid',
453 'sort' => 'menu_order',
454 'sort_on_frontend' => false,
455 'images' => true,
456 'card_click' => '',
457 ),
458 $layout_id
459 );
460 }
461
462 /**
463 * Convert layout settings to string.
464 *
465 * @param array $layout_settings
466 *
467 * @return string
468 */
469 public static function convert_layout_settings_to_string( $layout_settings ) {
470 $layout_settings_array = array();
471
472 if ( ! empty( $layout_settings ) ) {
473 foreach ( $layout_settings as $attribute => $value ) {
474 if ( empty( $value ) && false !== $value ) {
475 continue;
476 }
477
478 if ( is_bool( $value ) ) {
479 $value = $value ? 'true' : 'false';
480 } elseif ( is_array( $value ) ) {
481 $value = implode( ',', $value );
482 }
483
484 $layout_settings_array[] = sprintf( '%s="%s"', $attribute, $value );
485 }
486 }
487
488 return apply_filters( 'orderable_layout_settings_string', implode( ' ', $layout_settings_array ) );
489 }
490
491 /**
492 * Get categories list.
493 *
494 * @param array $categories
495 * @param int $parent
496 * @param int $level
497 *
498 * @return array
499 */
500 public static function get_categories( $categories = array(), $parent = 0, $level = 0 ) {
501 $terms = get_terms( array(
502 'taxonomy' => 'product_cat',
503 'hide_empty' => false,
504 'parent' => $parent,
505 ) );
506
507 if ( is_wp_error( $terms ) || empty( $terms ) ) {
508 return $categories;
509 }
510
511 foreach ( $terms as $term ) {
512 $categories[ $term->term_id ] = trim( sprintf( '%s %s', str_repeat( '', $level ), $term->name ) );
513
514 $categories = self::get_categories( $categories, $term->term_id, $level + 1 );
515 }
516
517 return $categories;
518 }
519
520 /**
521 * Add admin notice.
522 *
523 * @param array $notices
524 *
525 * @return array
526 */
527 public static function admin_notice( $notices = array() ) {
528 global $pagenow, $typenow;
529
530 if ( 'orderable_layouts' !== $typenow || 'edit.php' !== $pagenow ) {
531 return $notices;
532 }
533
534 $notices[] = array(
535 'name' => 'layout_builder',
536 'title' => __( 'What are Product Layouts?', 'orderable' ),
537 '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' ),
538 );
539
540 return $notices;
541 }
542
543 /**
544 * Get product card classes.
545 *
546 * @param array $args
547 *
548 * @return mixed|void
549 */
550 public static function get_product_card_classes( $args = array() ) {
551 $class = array(
552 'orderable-product',
553 );
554
555 if ( empty( $args['images'] ) ) {
556 $class[] = 'orderable-product--no-image';
557 }
558
559 if ( ! empty( $args['card_click'] ) ) {
560 $class[] = 'orderable-product--' . $args['card_click'];
561 }
562
563 return apply_filters( 'orderable_get_product_card_classes', $class, $args );
564 }
565 }
566