PluginProbe
Cooked – Recipe Management / 1.16.1
Cooked – Recipe Management v1.16.1
1.16.1 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 All 37 releases
cooked / includes / class.cooked-settings.php

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

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