PluginProbe
Cooked – Recipe Management / trunk
Cooked – Recipe Management vtrunk
1.16.0 1.15.0 trunk 1.10.0 1.11.0 1.11.1 1.11.2 1.11.3 1.11.4 1.12.0 1.13.0 1.14.0 1.7.10 1.7.11 1.7.12 1.7.13 1.7.15.1 1.7.15.3 1.7.15.4 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 All 36 releases
cooked / includes / class.cooked-settings.php

class.cooked-settings.php in Cooked – Recipe Management trunk, at includes/class.cooked-settings.php

890 lines 42.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Register Settings
4 *
5 * @package Cooked
6 * @subpackage Settings
7 * @since 1.0.0
8 */
9
10 // Exit if accessed directly
11 if ( !defined( 'ABSPATH' ) ) exit;
12
13 /**
14 * Cooked_Settings Class
15 *
16 * This class handles the settings creation and contains functions for retreiving those settings.
17 *
18 * @since 1.0.0
19 */
20 class Cooked_Settings {
21
22 public function __construct() {
23 add_filter( 'admin_init', [&$this, 'init'] );
24 add_filter( 'init', [&$this, 'init'] );
25 add_action( 'save_post', [&$this, 'browse_page_saved'], 10, 1 );
26 add_action( 'admin_notices', [ &$this, 'cooked_settings_saved_admin_notice' ] );
27 add_action( 'admin_notices', [ &$this, 'browse_page_missing_notice' ] );
28 }
29
30 public function browse_page_saved( $post_id ) {
31 // Just a revision, don't do anything
32 if ( wp_is_post_revision( $post_id ) ) return;
33
34 $_cooked_settings = Cooked_Settings::get();
35 $main_browse_page_id = isset($_cooked_settings['browse_page']) ? $_cooked_settings['browse_page'] : false;
36
37 // Check if this is the main browse page
38 if ( $main_browse_page_id == $post_id ) {
39 flush_rewrite_rules(false);
40 return;
41 }
42
43 // Also flush if this is a translation of the browse page
44 $browse_pages = Cooked_Multilingual::get_all_browse_pages();
45 foreach ( $browse_pages as $lang => $page_data ) {
46 if ( $page_data['id'] == $post_id ) {
47 flush_rewrite_rules(false);
48 return;
49 }
50 }
51 }
52
53 public static function init() {
54 global $_cooked_settings, $list_id_counter;
55
56 $list_id_counter = 0;
57 $_cooked_settings = Cooked_Settings::get();
58 register_setting( 'cooked_settings_group', 'cooked_settings', ['sanitize_callback' => [__CLASS__, 'sanitize_settings']] );
59 register_setting( 'cooked_settings_group', 'cooked_settings_saved' );
60 }
61
62 // Add this new method to handle settings sanitization.
63 public static function sanitize_settings($settings) {
64 $cooked_tabs_fields = self::tabs_fields();
65
66 // Process each field
67 foreach ($cooked_tabs_fields as $tab) {
68 if (isset($tab['fields']) && !empty($tab['fields'])) {
69 foreach ($tab['fields'] as $field_name => $field) {
70 // Handle checkbox fields specifically
71 if ($field['type'] === 'checkboxes') {
72 // If the field is missing from submission, set it as an empty array
73 if (!isset($settings[$field_name])) {
74 $settings[$field_name] = [];
75 } else {
76 // Remove any empty string values from checkbox arrays
77 if (!isset($settings[$field_name]) || !is_array($settings[$field_name])) {
78 $settings[$field_name] = [];
79 } else {
80 $settings[$field_name] = array_filter($settings[$field_name], function($value) {
81 return $value !== '';
82 });
83 }
84 }
85 } elseif ( $field['type'] === 'image_field' ) {
86 $image_id = isset( $settings[ $field_name ] ) ? absint( $settings[ $field_name ] ) : 0;
87
88 if ( $image_id && ! wp_attachment_is_image( $image_id ) ) {
89 $image_id = 0;
90 }
91
92 $settings[ $field_name ] = $image_id;
93 }
94 }
95 }
96 }
97
98 if ( isset( $settings['dark_mode'] ) ) {
99 $settings['dark_mode'] = self::normalize_dark_mode( $settings['dark_mode'] );
100 }
101
102 return $settings;
103 }
104
105 function cooked_settings_saved_admin_notice() {
106 if (isset($_GET['settings-updated']) && $_GET['settings-updated'] && isset($_GET['page']) && $_GET['page'] === 'cooked_settings') {
107 add_settings_error(
108 'cooked_settings_group',
109 'cooked_settings_updated',
110 __( 'Cooked settings has been updated!', 'cooked' ),
111 'updated'
112 );
113 }
114 }
115
116 function browse_page_missing_notice() {
117 // Only show on admin pages, not on the Cooked settings page itself
118 if ( isset($_GET['page']) && $_GET['page'] === 'cooked_settings' ) {
119 return;
120 }
121
122 // Get Cooked settings
123 $_cooked_settings = self::get();
124
125 // Check if browse page is set
126 if ( empty($_cooked_settings['browse_page']) || !$_cooked_settings['browse_page'] ) {
127 $class = 'notice notice-warning is-dismissible';
128 $message = sprintf(
129 '<strong>' . __( 'Cooked Plugin Setup', 'cooked' ) . '</strong> ' .
130 __( 'To display your recipes properly, please set up your %s.', 'cooked' ),
131 '<a href="' . trailingslashit( admin_url() ) . 'admin.php?page=cooked_settings#recipe_settings">' . __( 'Browse/Search Recipes Page', 'cooked' ) . '</a>'
132 );
133 printf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), $message );
134 }
135 }
136
137 public static function reset() {
138 global $_cooked_settings;
139 $_cooked_settings = Cooked_Settings::get();
140 }
141
142 public static function get() {
143 $_cooked_settings = get_option( 'cooked_settings', [] );
144
145 // Get defaults for fields that are not set yet.
146 $cooked_tabs_fields = self::tabs_fields();
147
148 if ( isset($cooked_tabs_fields) && !empty($cooked_tabs_fields) ) {
149 foreach ( $cooked_tabs_fields as $tab ) {
150 if ( isset($tab['fields']) && !empty($tab['fields']) ) {
151 foreach ( $tab['fields'] as $name => $field ) {
152 if ( $field['type'] == 'nonce' || $field['type'] == 'misc_button' ) continue;
153
154 if ( $field['type'] === 'checkboxes' ) {
155 $_cooked_settings[$name] = isset($_cooked_settings[$name]) ? $_cooked_settings[$name] : ( isset( $field['default'] ) ? $field['default'] : [] );
156 } else {
157 $_cooked_settings[$name] = isset($_cooked_settings[$name]) ? $_cooked_settings[$name] : ( isset( $field['default'] ) ? $field['default'] : false );
158 }
159 }
160 }
161 }
162 }
163
164 if ( isset( $_cooked_settings['dark_mode'] ) ) {
165 $_cooked_settings['dark_mode'] = self::normalize_dark_mode( $_cooked_settings['dark_mode'] );
166 }
167
168 return apply_filters( 'cooked_get_settings', $_cooked_settings );
169 }
170
171 /**
172 * Normalize dark mode setting to off|enabled|auto.
173 *
174 * Accepts legacy checkbox arrays (e.g. ['enabled']) and the current select string.
175 *
176 * @param mixed $mode Raw dark_mode setting value.
177 * @return string One of: off, enabled, auto.
178 */
179 public static function normalize_dark_mode( $mode ) {
180 if ( is_array( $mode ) ) {
181 if ( in_array( 'auto', $mode, true ) ) {
182 return 'auto';
183 }
184 if ( in_array( 'enabled', $mode, true ) ) {
185 return 'enabled';
186 }
187 return 'off';
188 }
189
190 $mode = is_string( $mode ) ? $mode : 'off';
191
192 if ( in_array( $mode, [ 'off', 'enabled', 'auto' ], true ) ) {
193 return $mode;
194 }
195
196 return 'off';
197 }
198
199 /**
200 * Dark mode CSS scope for dynamic styles.
201 *
202 * @return string|false Empty string when dark mode is forced on; theme selector when auto; false when off.
203 */
204 public static function get_dark_mode_scope() {
205 $settings = self::get();
206 $mode = self::normalize_dark_mode( isset( $settings['dark_mode'] ) ? $settings['dark_mode'] : 'off' );
207
208 if ( 'auto' === $mode ) {
209 $scope = apply_filters( 'cooked_dark_mode_auto_scope', '[data-theme="dark"]' );
210
211 return $scope ? $scope : false;
212 }
213
214 if ( 'enabled' === $mode ) {
215 return '';
216 }
217
218 return false;
219 }
220
221 /**
222 * Prefix a comma-separated CSS selector list with the dark mode scope.
223 *
224 * @param string $selectors Comma-separated CSS selectors.
225 * @return string|false Prefixed selectors, or false when dark mode is off.
226 */
227 public static function prefix_dark_mode_css( $selectors ) {
228 $scope = self::get_dark_mode_scope();
229
230 if ( false === $scope ) {
231 return false;
232 }
233
234 if ( '' === $scope ) {
235 return $selectors;
236 }
237
238 $parts = array_map( 'trim', explode( ',', $selectors ) );
239 $parts = array_map(
240 function ( $part ) use ( $scope ) {
241 return $scope . ' ' . $part;
242 },
243 $parts
244 );
245
246 return implode( ', ', $parts );
247 }
248
249 public static function tabs_fields() {
250 $pages_array = self::pages_array( __('Choose a page...','cooked'), __('No pages','cooked') );
251 $categories_array = self::terms_array( 'cp_recipe_category', __('No default', 'cooked'), __('No categories', 'cooked') );
252 $recipes_per_page_array = self::per_page_array();
253 $recipe_archive_slug = sanitize_title_with_dashes( __( 'Recipe Archive', 'cooked' ) );
254 $recipe_archive_url = home_url( '/' . $recipe_archive_slug . '/' );
255
256 // Dynamically load roles.
257 $role_options = [];
258 if (is_user_logged_in()) {
259 global $wp_roles;
260 $roles = $wp_roles->roles;
261
262 if (!empty($roles)) {
263 foreach ( $roles as $role => $data ) {
264 $role_options[$role] = [
265 'label' => $data['name']
266 ];
267 }
268 }
269 }
270
271 return apply_filters('cooked_settings_tabs_fields', [
272 'recipe_settings' => [
273 'name' => __('General', 'cooked'),
274 'icon' => 'gear',
275 'fields' => [
276 'browse_page' => [
277 'title' => __('Browse/Search Recipes Page', 'cooked'),
278 /* translators: a description on how to add the [cooked-browse] shortcode to a page */
279 'desc' => sprintf(__('Create a page with the %s shortcode on it, then choose it from this dropdown.', 'cooked'), '<code>[cooked-browse]</code>') . '<br><em>' . __('<b>Note:</b> This setting is required for the plugin to function properly.', 'cooked') . '</em>',
280 'type' => 'select',
281 'default' => 0,
282 'options' => $pages_array
283 ],
284 'recipes_per_page' => [
285 'title' => __('Recipes Per Page', 'cooked'),
286 /* translators: a description on how to choose the default number of recipes per page. */
287 'desc' => sprintf(__('Choose the default (set via the %s panel) or choose a different number here.', 'cooked'), '<a href="' . trailingslashit(get_admin_url()) . 'options-reading.php">' . __('Settings > Reading', 'cooked') . '</a>'),
288 'type' => 'select',
289 'default' => 9,
290 'options' => $recipes_per_page_array
291 ],
292 'recipe_taxonomies' => [
293 'title' => __('Recipe Taxonomies', 'cooked'),
294 'desc' => __('Choose which taxonomies you want to enable for your recipes.', 'cooked'),
295 'type' => 'checkboxes',
296 'default' => ['cp_recipe_category'],
297 'options' => apply_filters(
298 'cooked_taxonomy_options',
299 [
300 'cp_recipe_category' => __('Categories', 'cooked')
301 ]
302 )
303 ],
304 'recipe_info_display_options' => [
305 'title' => __('Global Recipe Toggles', 'cooked'),
306 'desc' => __('You can quickly hide or show different recipe elements (site-wide) with these checkboxes.', 'cooked'),
307 'type' => 'checkboxes',
308 'default' => apply_filters(
309 'cooked_recipe_info_display_options_defaults',
310 [
311 'author',
312 'taxonomies',
313 'difficulty_level',
314 'excerpt',
315 'timing_prep',
316 'timing_cook',
317 'timing_total',
318 'servings'
319 ]
320 ),
321 'options' => apply_filters(
322 'cooked_recipe_info_display_options',
323 [
324 'author' => __('Author', 'cooked'),
325 'taxonomies' => __('Category', 'cooked'),
326 'difficulty_level' => __('Difficulty Level', 'cooked'),
327 'excerpt' => __('Excerpt', 'cooked'),
328 'notes' => __('Notes', 'cooked'),
329 'timing_prep' => __('Prep Time', 'cooked'),
330 'timing_cook' => __('Cook Time', 'cooked'),
331 'timing_total' => __('Total Time', 'cooked'),
332 'servings' => __('Servings', 'cooked')
333 ]
334 )
335 ],
336 'print_view_display_options' => [
337 'title' => __('Print View', 'cooked'),
338 'desc' => __('When enabled, the website logo will appear at the top of the recipe print screen.', 'cooked'),
339 'type' => 'checkboxes',
340 'default' => [],
341 'options' => apply_filters(
342 'cooked_print_view_display_options',
343 [
344 'site_logo' => __('Show Website Logo', 'cooked'),
345 ]
346 )
347 ],
348 'carb_format' => [
349 'title' => __('Carbs Format', 'cooked'),
350 'desc' => __('You can display carbs as "Total" or "Net".', 'cooked'),
351 'type' => 'select',
352 'default' => 'total',
353 'options' => apply_filters(
354 'cooked_settings_carb_formats',
355 [
356 'total' => __('Total Carbs', 'cooked'),
357 'net' => __('Net Carbs', 'cooked')
358 ]
359 )
360 ],
361 'author_name_format' => [
362 'title' => __('Author Name Format', 'cooked'),
363 'desc' => __('You can show the full author\'s name or just a part of it.', 'cooked'),
364 'type' => 'select',
365 'default' => 'full',
366 'options' => apply_filters(
367 'cooked_settings_author_formats',
368 [
369 'full' => __('Full name', 'cooked'),
370 'first_last_initial' => __('Full first name w/last name initial', 'cooked'),
371 'first_initial_last' => __('First name initial w/full last name', 'cooked'),
372 'first_only' => __('First name only', 'cooked')
373 ]
374 )
375 ],
376 'disable_author_links' => [
377 'title' => __('Author Links', 'cooked'),
378 'desc' => __('If you do not want the author names to link to the author recipe listings, you can disable them here.', 'cooked') . '<br><em>' . __('<b>Note:</b> Author links require the Browse/Search Recipes Page to be set up correctly to function properly.', 'cooked') . '</em>',
379 'type' => 'checkboxes',
380 'color' => 'red',
381 'default' => [],
382 'options' => apply_filters(
383 'cooked_author_link_options',
384 [
385 'disabled' => __('Disable Author Links', 'cooked'),
386 ]
387 )
388 ],
389 'browse_default_cp_recipe_category' => [
390 'title' => __('Default Category', 'cooked'),
391 /* translators: a description on how to set the default recipe category for the [cooked-browse] shortcode. */
392 'desc' => sprintf(__('Optionally set the default recipe category for your %s shortcode display.', 'cooked'), '<code>[cooked-browse]</code>'),
393 'type' => 'select',
394 'default' => 0,
395 'options' => $categories_array
396 ],
397 'browse_default_sort' => [
398 'title' => __('Default Sort Order', 'cooked'),
399 /* translators: a description on how to set the default sort order for the [cooked-browse] shortcode. */
400 'desc' => sprintf(__('Set the default sort order for your %s shortcode display.', 'cooked'), '<code>[cooked-browse]</code>'),
401 'type' => 'select',
402 'default' => 'date_desc',
403 'options' => apply_filters(
404 'cooked_settings_sort_options',
405 [
406 'date_desc' => __('Newest First', 'cooked'),
407 'date_asc' => __('Oldest First', 'cooked'),
408 'title_asc' => __('Alphabetical', 'cooked'),
409 'title_desc' => __('Alphabetical (reversed)', 'cooked'),
410 ]
411 )
412 ],
413 'section_heading_default_html_tag' => [
414 'title' => __('Section Heading Default HTML Tag', 'cooked'),
415 /* translators: a description on how to set the default sort order for the [cooked-browse] shortcode. */
416 'desc' => __('Set the default HTML tag for your section headings.', 'cooked'),
417 'type' => 'select',
418 'default' => 'div',
419 'options' => apply_filters(
420 'cooked_settings_section_heading_default_html_tag_options',
421 [
422 'div' => __('div', 'cooked'),
423 'h2' => __('h2', 'cooked'),
424 'h3' => __('h3', 'cooked'),
425 'h4' => __('h4', 'cooked'),
426 'h5' => __('h5', 'cooked'),
427 'h6' => __('h6', 'cooked'),
428 ]
429 )
430 ],
431 'recipe_wp_editor_roles' => [
432 'title' => __('WP Editor Roles', 'cooked'),
433 'desc' => __('Choose which user roles can use the WP Editor for the Excerpt, Directions & Notes fields.', 'cooked'),
434 'type' => 'checkboxes',
435 'default' => apply_filters('cooked_recipe_wp_editor_roles_defaults', ['administrator', 'editor', 'cooked_recipe_editor']),
436 'options' => $role_options
437 ],
438 'advanced' => [
439 'title' => __('Advanced Settings', 'cooked'),
440 'desc' => '',
441 'type' => 'checkboxes',
442 'color' => 'red',
443 'class' => 'cooked-danger',
444 'default' => [],
445 'options' => apply_filters(
446 'cooked_advanced_options',
447 [
448 /* translators: an option to only show recipes with the [cooked-recipe] shortcode. */
449 'disable_public_recipes' => '<strong>' . __('Disable Public Recipes', 'cooked') . '</strong> &mdash; ' . sprintf(__('Only show recipes using the %s shortcode.', 'cooked'), '<code>[cooked-recipe]</code>'),
450 /* translators: an option to disable "meta" tags. */
451 'disable_meta_tags' => '<strong>' . sprintf(__('Disable %s Tags', 'cooked'), 'Cooked <code>&lt;meta&gt;</code>') . '</strong> &mdash; ' . __('Prevents duplicates when tags already exist.', 'cooked'),
452 'disable_servings_switcher' => '<strong>' . __('Disable "Servings Switcher"', 'cooked') . '</strong> &mdash; ' . __('Removes the servings dropdown on recipes.', 'cooked'),
453 'enable_measurement_switcher' => '<strong>' . __('Enable "Measurement System Switcher"', 'cooked') . '</strong> &mdash; ' . __('Shows the Metric/Imperial toggle on recipes.', 'cooked'),
454 'disable_schema_output' => '<strong>' . __('Disable Recipe Schema Output', 'cooked') . '</strong> &mdash; ' . __('You should only do this if you\'re using something else to output schema information.', 'cooked'),
455 'disable_cp_recipe_archive' => '<strong>' . __( 'Disable Recipe Archive Page', 'cooked' ) . '</strong> &mdash; ' . sprintf(
456 /* translators: %s: recipe archive URL, e.g. https://example.com/recipe-archive/ */
457 __( 'Prevents the recipe archive from being displayed at %s.', 'cooked' ),
458 '<code>' . esc_html( untrailingslashit( $recipe_archive_url ) ) . '/</code>'
459 )
460 ]
461 )
462 ],
463 ]
464 ],
465 'design' => [
466 'name' => __('Design', 'cooked'),
467 'icon' => 'pencil',
468 'fields' => [
469 'dark_mode' => [
470 'title' => __('Dark Mode', 'cooked'),
471 'desc' => apply_filters(
472 'cooked_dark_mode_field_desc',
473 __( 'Use <strong>Auto</strong> if your theme has a visitor dark mode toggle. Cooked will then match that choice. Otherwise leave this Off.', 'cooked' )
474 ),
475 'type' => 'select',
476 'default' => 'off',
477 'options' => apply_filters(
478 'cooked_dark_mode_options',
479 [
480 'off' => __('Off', 'cooked'),
481 'enabled' => __('On', 'cooked'),
482 'auto' => __('Auto (match theme dark mode)', 'cooked'),
483 ]
484 )
485 ],
486 'hide_author_avatars' => [
487 'title' => __('Author Images', 'cooked'),
488 'desc' => __('If you do not want to display the author images (avatars), you can disable them here.', 'cooked'),
489 'type' => 'checkboxes',
490 'color' => 'red',
491 'default' => [],
492 'options' => apply_filters(
493 'cooked_author_image_options',
494 [
495 'hidden' => __('Hide Author Images', 'cooked'),
496 ]
497 )
498 ],
499 'default_recipe_image' => [
500 'title' => __( 'Default Recipe Image', 'cooked' ),
501 'desc' => __( 'Used as the featured image for recipes that do not have one set.', 'cooked' ),
502 'type' => 'image_field',
503 'default' => 0,
504 ],
505 'main_color' => [
506 'title' => __('Main Color', 'cooked'),
507 'desc' => __('Used on buttons, cooking timer, etc.', 'cooked'),
508 'type' => 'color_field',
509 'default' => '#16a780',
510 'options' => '#16a780'
511 ],
512 'main_color_hover' => [
513 'title' => __('Main Color (on hover)', 'cooked'),
514 'desc' => __('Used when hovering over buttons.', 'cooked'),
515 'type' => 'color_field',
516 'default' => '#1b9371',
517 'options' => '#1b9371'
518 ],
519 'responsive_breakpoint_1' => [
520 'title' => __('First Responsive Breakpoint', 'cooked'),
521 'desc' => __('Set the first responsive breakpoint. Best for large tablets.', 'cooked'),
522 'type' => 'number_field',
523 'default' => '1000',
524 'options' => ''
525 ],
526 'responsive_breakpoint_2' => [
527 'title' => __('Second Responsive Breakpoint', 'cooked'),
528 'desc' => __('Set the second responsive breakpoint. Best for small tablets.', 'cooked'),
529 'type' => 'number_field',
530 'default' => '750',
531 'options' => ''
532 ],
533 'responsive_breakpoint_3' => [
534 'title' => __('Third Responsive Breakpoint', 'cooked'),
535 'desc' => __('Set the third responsive breakpoint. Best for phones and other small devices.', 'cooked'),
536 'type' => 'number_field',
537 'default' => '520',
538 'options' => ''
539 ]
540 ]
541 ],
542 'permalinks' => [
543 'name' => __('Permalinks', 'cooked'),
544 'icon' => 'link-lt',
545 'fields' => [
546 'recipe_permalink' => [
547 'title' => __('Recipe Permalink', 'cooked'),
548 'desc' => '',
549 'type' => 'permalink_field',
550 'options' => __('recipe-name', 'cooked'),
551 'default' => 'recipes'
552 ],
553 'recipe_author_permalink' => [
554 'title' => __('Recipe Author Permalink', 'cooked'),
555 'desc' => '',
556 'type' => 'permalink_field',
557 'options' => __('author-name', 'cooked'),
558 'default' => 'recipe-author'
559 ],
560 'recipe_category_permalink' => [
561 'title' => __('Recipe Category Permalink', 'cooked'),
562 'desc' => '',
563 'type' => 'permalink_field',
564 'options' => __('recipe-category-name', 'cooked'),
565 'default' => 'recipe-category'
566 ]
567 ]
568 ]
569 ], $pages_array, $categories_array);
570 }
571
572 public static function per_page_array() {
573 $counter = 0;
574 /* translators: posts_per_page default */
575 $per_page_array[] = sprintf( __('WordPress Default %s','cooked'), '(' . get_option( 'posts_per_page' ) . ')' );
576 do {
577 $counter++;
578 $per_page_array[$counter] = $counter;
579 } while ( $counter < 50 );
580 $per_page_array['-1'] = __('Show All (no pagination)','cooked');
581
582 return apply_filters( 'cooked_per_page_options', $per_page_array );
583 }
584
585 public static function pages_array( $choose_text, $none_text = false ) {
586 $page_array = [];
587 $pages = get_posts([
588 'post_type' => 'page',
589 'posts_per_page' => -1
590 ]);
591
592 if( !empty($pages) ) {
593 $page_array[0] = $choose_text;
594 foreach ($pages as $_page) {
595 $page_array[$_page->ID] = $_page->post_title . ' (ID:' . $_page->ID . ')';
596 }
597 } elseif ( $none_text ) {
598 $page_array[0] = $none_text;
599 }
600
601 return apply_filters( 'cooked_settings_pages_array', $page_array );
602 }
603
604 public static function terms_array( $term, $choose_text, $none_text = false, $hide_empty = false, $parents_only = false, $child_of = false ) {
605 $terms_array = [];
606
607 $args = [
608 'taxonomy' => $term,
609 'hide_empty' => $hide_empty
610 ];
611
612 if ( $parents_only ) {
613 $args['parent'] = '0';
614 } elseif ( $child_of ) {
615 $_term = is_numeric($child_of) ? $child_of : get_term_by( 'slug', $child_of, $term );
616 $term_id = is_object( $_term ) ? $_term->term_id : $_term;
617 $args['parent'] = $term_id;
618 }
619
620 $terms = get_terms( $args );
621
622 if ( !empty($terms) ) {
623 if ($choose_text) {
624 $terms_array[0] = $choose_text;
625 }
626
627 foreach ($terms as $_term) {
628 if ( !is_array($_term) ) {
629 $terms_array[$_term->term_id] = $_term->name;
630 }
631 }
632 } elseif ( $none_text ) {
633 $terms_array[0] = $none_text;
634 }
635
636 return apply_filters( 'cooked_settings_' . $term . '_array', $terms_array );
637 }
638
639 public static function field_radio( $field_name, $options ) {
640 global $_cooked_settings, $conditions;
641
642 $counter = 1;
643
644 echo '<p class="cooked-padded">';
645 foreach ( $options as $value => $name) {
646 $is_disabled = '';
647 $conditional_value = '';
648 $conditional_requirement = '';
649
650 if ( is_array($name) ):
651 if ( isset($name['read_only']) && $name['read_only'] ):
652 $is_disabled = ' disabled';
653 endif;
654
655 if ( isset($name['conditional_value']) && $name['conditional_value'] ):
656 $conditional_value = ' v-model="' . esc_attr($name['conditional_value']) . '"';
657 if ( !in_array( $name['conditional_value'], $conditions ) ):
658 $conditions[$value] = esc_attr($name['conditional_requirement']);
659 endif;
660 endif;
661
662 if ( isset($name['conditional_requirement']) && $name['conditional_requirement'] ):
663 if ( is_array($name['conditional_requirement']) ):
664 $conditional_requirement = ' v-show="' . implode( ' && ', $name['conditional_requirement'] ) . '"';
665 else:
666 $conditional_requirement = ' v-show="' . esc_attr($name['conditional_requirement']) . '"';
667 endif;
668 endif;
669
670 $name = $name['label'];
671 endif;
672
673 $combined_extras = $is_disabled . $conditional_value;
674
675 if ( $conditional_requirement ): echo '<transition name="fade"><span class="conditional-requirement"' . esc_attr( $conditional_requirement ) . '>'; endif;
676 echo '<input' . $combined_extras . ' type="radio" id="radio-group-' . esc_attr( $field_name ) . '-' . esc_attr( $value ) . '" name="cooked_settings[' . esc_attr( $field_name ) . ']" value="' . esc_attr( $value ) . '"' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] == $value || isset( $_cooked_settings[$field_name][0] ) && $_cooked_settings[$field_name][0] == $value ? ' checked' : '' ) . '/>';
677 echo '&nbsp;<label for="radio-group-' . esc_attr( $field_name ) . '-' . esc_attr( $value ) . '">' . wp_kses_post( $name ) . '</label>';
678 echo '<br>';
679 if ( $conditional_requirement ): echo '</span></transition>'; endif;
680
681 $counter++;
682 }
683 echo '</p>';
684 }
685
686 public static function field_select( $field_name, $options, $color = false, $field = []) {
687 global $_cooked_settings;
688
689 $is_disabled = '';
690
691 if ( isset($field['read_only']) && $field['read_only'] ) {
692 $is_disabled = ' disabled';
693 }
694
695 echo '<p>';
696 echo '<select' . $is_disabled . ' name="cooked_settings[' . esc_attr( $field_name ) . ']">';
697 foreach ( $options as $value => $name) {
698 echo '<option value="' . esc_attr( $value ) . '"' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] == $value ? ' selected' : '' ) . '>' . esc_attr( $name ) . '</option>';
699 }
700 echo '</select>';
701 echo '</p>';
702 }
703
704 public static function field_nonce( $field_name, $options ) {
705 wp_nonce_field( $field_name, $field_name );
706 }
707
708 // Kept here for backwards compatibility only. Removed used in Cooked Pro 1.0.1
709 public static function field_misc_button( $field_name, $title ) {
710 echo '<p>';
711 echo '<input type="submit" class="button-secondary" name="' . esc_attr( $field_name ) . '" value="' . esc_attr( $title ) . '">';
712 echo '</p>';
713 }
714 // END
715
716 public static function field_migrate_button( $field_name, $title ) {
717 $old_recipes = get_transient('cooked_classic_recipes');
718
719 if ($old_recipes != 'complete') {
720 $total = count($old_recipes);
721
722 if ($total > 0) {
723 echo '<p>';
724 echo '<input id="cooked-migration-button" type="button" class="button-secondary" name="begin_cooked_migration" value="' . __( 'Begin Migration', 'cooked' ) . '">';
725 echo '</p>';
726 echo '<p>';
727 echo '<span id="cooked-migration-progress" class="cooked-progress"><span class="cooked-progress-bar"></span></span><span id="cooked-migration-progress-text" class="cooked-progress-text">0 / ' . esc_html( $total ) . '</span>';
728 echo '</p>';
729 echo '<p id="cooked-migration-completed"><strong>Migration Complete!</strong> You can now <a href="' . esc_url( add_query_arg(['page' => 'cooked_settings'], admin_url( 'admin.php' ) ) ) . '">' . __( 'reload', 'cooked' ) . '</a> the settings screen.</p>';
730 }
731 }
732 }
733
734 public static function field_text($field_name, $placeholder) {
735 global $_cooked_settings;
736
737 echo '<p>';
738 echo '<input id="cooked_field--' . esc_attr( $field_name ) . '" type="text"' . ( $placeholder ? ' placeholder="' . esc_attr( $placeholder ) . '"' : '' ) . ' name="cooked_settings[' . esc_attr( $field_name ) . ']" value="' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] ? esc_attr( $_cooked_settings[$field_name] ) : '' ) . '">';
739 echo '</p>';
740 }
741
742 public static function field_password($field_name, $placeholder) {
743 global $_cooked_settings;
744
745 echo '<p>';
746 echo '<input type="password"' . ( $placeholder ? ' placeholder="' . esc_attr( $placeholder ) . '"' : '' ) . ' name="cooked_settings[' . esc_attr( $field_name ) . ']" value="' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] ? esc_attr( $_cooked_settings[$field_name] ) : '' ) . '">';
747 echo '</p>';
748 }
749
750 public static function field_html($field_name, $html) {
751 echo wp_kses_post($html);
752 }
753
754 public static function field_permalink_field($field_name, $end_of_url) {
755 global $_cooked_settings;
756
757 $browse_page_id = $_cooked_settings['browse_page'];
758 $browse_page_url = '';
759
760 if (!empty($browse_page_id) && $field_name !== 'recipe_permalink') {
761 $browse_page_url = get_permalink( $browse_page_id );
762 }
763
764 if (empty($browse_page_url)) {
765 $browse_page_url = get_home_url();
766 }
767
768 if (substr($browse_page_url, -1) !== '/') {
769 $browse_page_url .= '/';
770 }
771
772 echo '<p class="cooked-permalink-field-wrapper">';
773 echo '<span>' . $browse_page_url . '</span><input type="text" class="cooked-permalink-field" name="cooked_settings[' . esc_attr( $field_name ) . ']" value="' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] ? esc_attr( $_cooked_settings[$field_name] ) : '' ) . '"><span>/' . esc_html( $end_of_url ) . '/</span>';
774 echo '</p>';
775 }
776
777 public static function field_number_field( $field_name, $options ) {
778 global $_cooked_settings;
779
780 echo '<p>';
781 echo '<input type="number" step="any" name="cooked_settings[' . esc_attr( $field_name ) . ']" value="' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] ? esc_attr( $_cooked_settings[$field_name] ) : '' ) . '">';
782 echo '</p>';
783 }
784
785 public static function field_color_field( $field_name, $default ) {
786 global $_cooked_settings;
787
788 echo '<p>';
789 echo '<input class="cooked-color-field" type="text"' . ( $default ? ' data-default-color="' . esc_attr( $default ) . '"' : '' ) . ' name="cooked_settings[' . esc_attr( $field_name ) . ']" value="' . ( isset( $_cooked_settings[$field_name] ) && $_cooked_settings[$field_name] ? esc_attr( $_cooked_settings[$field_name] ) : '' ) . '">';
790 echo '</p>';
791 }
792
793 public static function field_image_field( $field_name, $default ) {
794 global $_cooked_settings;
795
796 $attachment_id = isset( $_cooked_settings[ $field_name ] ) ? absint( $_cooked_settings[ $field_name ] ) : 0;
797 $has_image = $attachment_id && wp_attachment_is_image( $attachment_id );
798 $preview_id = 'cooked-settings-image-' . esc_attr( $field_name ) . '-src';
799
800 echo '<div class="cooked-settings-image-field' . ( $has_image ? ' cooked-has-image' : '' ) . '">';
801 echo '<input type="hidden" class="cooked-settings-image-input" name="cooked_settings[' . esc_attr( $field_name ) . ']" id="cooked-settings-image-' . esc_attr( $field_name ) . '" value="' . esc_attr( $attachment_id ) . '" />';
802 echo '<input type="button" class="button cooked-settings-image-button" value="' . esc_attr( $has_image ? __( 'Change Image', 'cooked' ) : __( 'Add Image', 'cooked' ) ) . '" />';
803
804 if ( $has_image ) {
805 echo wp_get_attachment_image( $attachment_id, 'thumbnail', false, [
806 'class' => 'cooked-settings-image-preview-img',
807 'id' => $preview_id,
808 ] );
809 } else {
810 echo '<img class="cooked-settings-image-preview-img" id="' . esc_attr( $preview_id ) . '" src="" alt="" />';
811 }
812
813 echo '<a href="#" class="cooked-settings-image-remove"><i class="cooked-icon cooked-icon-times"></i></a>';
814 echo '</div>';
815 }
816
817 public static function field_checkboxes($field_name, $options, $color = false, $field = []) {
818 global $_cooked_settings, $conditions;
819
820 echo '<p class="cooked-padded">';
821 foreach ($options as $value => $name) {
822 $is_disabled = '';
823 $conditional_value = '';
824 $conditional_requirement = '';
825
826 if (is_array($name)) {
827 if (isset($name['read_only']) && $name['read_only']):
828 $is_disabled = ' disabled';
829 endif;
830
831 if (isset($name['conditional_value']) && $name['conditional_value']):
832 $conditional_value = ' v-model="' . esc_attr($name['conditional_value']) . '"';
833 if ( !in_array( $name['conditional_value'], $conditions ) ):
834 $conditions[$field_name][$name['conditional_value']] = $value;
835 endif;
836 endif;
837
838 if (isset($name['conditional_requirement']) && $name['conditional_requirement']):
839 if (is_array($name['conditional_requirement'])):
840 $conditional_requirement = ' v-show="' . implode( ' && ', $name['conditional_requirement'] ) . '"';
841 else:
842 $conditional_requirement = ' v-show="' . esc_attr($name['conditional_requirement']) . '"';
843 endif;
844 endif;
845
846 $name = $name['label'];
847 }
848
849 $combined_extras = $is_disabled . $conditional_value;
850
851 if ($conditional_requirement) {
852 echo '<transition name="fade"><span class="conditional-requirement"' . esc_attr($conditional_requirement) . '>';
853 }
854
855 // Check if the setting exists at all
856 $setting_exists = isset($_cooked_settings[$field_name]) && is_array($_cooked_settings[$field_name]);
857
858 // Only use default if setting doesn't exist
859 $use_default = !$setting_exists && isset($field['default']);
860
861 // Determine if checkbox should be checked
862 $is_checked = ($setting_exists && in_array($value, $_cooked_settings[$field_name])) ||
863 ($use_default && in_array($value, (array)$field['default'])) ||
864 $is_disabled;
865
866 if ($is_disabled) {
867 echo '<input type="hidden" name="cooked_settings[' . esc_attr($field_name) . '][]" value="' . esc_attr($value) . '">';
868 echo '<input' . $combined_extras . ' class="cooked-switch' . ($color ? '-' . esc_attr($color) : '') .
869 '" type="checkbox" id="checkbox-group-' . esc_attr($field_name) . '-' . esc_attr($value) .
870 '"' . ($is_checked ? ' checked' : '') . '/>';
871 } else {
872 echo '<input' . $combined_extras . ' class="cooked-switch' . ($color ? '-' . esc_attr($color) : '') .
873 '" type="checkbox" id="checkbox-group-' . esc_attr($field_name) . '-' . esc_attr($value) .
874 '" name="cooked_settings[' . esc_attr($field_name) . '][]" value="' . esc_attr($value) .
875 '"' . ($is_checked ? ' checked' : '') . '/>';
876 }
877
878 echo '&nbsp;<label for="checkbox-group-' . esc_attr($field_name) . '-' . esc_attr($value) . '">' .
879 wp_kses_post($name) . '</label>';
880 echo '<br>';
881
882 if ($conditional_requirement) {
883 echo '</span></transition>';
884 }
885 }
886 echo '</p>';
887 }
888
889 }
890