PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.1.3
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.1.3
2.1.3 2.1.2 2.1.1 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 trunk 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 All 57 releases
← All changes | src/Admin/Rest/AbstractRestController.php +64 -58 2.0.02.1.3 View file →
@@ -15,8 +15,9 @@
15 15 */
16 16
17 17 namespace ThemeAtelier\Darkify\Admin\Rest;
18 18
19 +use ThemeAtelier\Darkify\Admin\Schema\SchemaDefaults;
19 20 use ThemeAtelier\Darkify\Admin\Schema\SchemaRegistry;
20 21
21 22 if (! defined('ABSPATH')) {
22 23 die;
@@ -279,8 +280,25 @@
279 280 return $out;
280 281 }
281 282
282 283 /**
284 + * Navigation sources that are stored as posts rather than `nav_menu` terms.
285 + *
286 + * Keyed by post type, valued by the short source label shown after the menu
287 + * name in the picker. `kadence_navigation` is only registered when Kadence
288 + * Blocks is active, which is why every caller checks post_type_exists()
289 + * before querying — the list itself is deliberately static so it costs
290 + * nothing to ask for.
291 + */
292 + protected static function darkify_block_menu_sources()
293 + {
294 + return [
295 + 'wp_navigation' => \__('Block menu', 'darkify'),
296 + 'kadence_navigation' => \__('Kadence', 'darkify'),
297 + ];
298 + }
299 +
300 + /**
283 301 * The read-only shortcode templates for the `switcher_shortcode` /
284 302 * `switcher_shortcode_v2` fields, byte-for-byte as the old framework's field
285 303 * renderers printed them.
286 304 */
@@ -350,8 +368,50 @@
350 368 case 'menus': {
351 369 foreach (\wp_get_nav_menus() as $menu) {
352 370 $out[(string) $menu->term_id] = $menu->name;
353 371 }
372 +
373 + /*
374 + * Block-theme and Kadence navigations are POSTS, not `nav_menu`
375 + * terms, so wp_get_nav_menus() above cannot see them. On a block
376 + * theme — or any site whose menus were built with Kadence
377 + * Navigation — this field came back completely empty even though
378 + * the site had menus, because there were no classic menus left to
379 + * list.
380 + *
381 + * Their ids are POST ids and would collide with the term ids
382 + * above (post 5 and term 5 are different menus), so they are
383 + * namespaced `<post_type>:<id>`. Bare numeric keys stay reserved
384 + * for classic menus, which is what keeps every already-saved
385 + * `switch_in_menu_location` resolving to exactly the menu it
386 + * always did.
387 + */
388 + foreach (self::darkify_block_menu_sources() as $post_type => $label) {
389 + if (! \post_type_exists($post_type)) {
390 + continue;
391 + }
392 +
393 + $navs = \get_posts([
394 + 'post_type' => $post_type,
395 + 'post_status' => 'publish',
396 + 'numberposts' => -1,
397 + 'orderby' => 'title',
398 + 'order' => 'ASC',
399 + 'suppress_filters' => false,
400 + ]);
401 +
402 + foreach (\is_array($navs) ? $navs : [] as $nav) {
403 + $title = ($nav->post_title !== '')
404 + ? $nav->post_title
405 + /* translators: %d: navigation menu post ID. */
406 + : \sprintf(\__('(no title) #%d', 'darkify'), $nav->ID);
407 +
408 + // The source is shown because a site can legitimately
409 + // have a classic menu, a block menu and a Kadence menu
410 + // all called "Primary Menu".
411 + $out[$post_type . ':' . $nav->ID] = $title . ' — ' . $label;
412 + }
413 + }
354 414 break;
355 415 }
356 416 }
357 417
@@ -411,66 +471,12 @@
411 471 * save their fields flat, so those recurse to the top level unchanged.
412 472 */
413 473 public function collect_defaults(array $sections): array
414 474 {
415 - $defaults = [];
416 - foreach ($sections as $section) {
417 - if (! empty($section['fields']) && \is_array($section['fields'])) {
418 - $this->collect_field_defaults($section['fields'], $defaults);
419 - }
420 - }
421 - return $defaults;
422 - }
423 -
424 - /**
425 - * Recursive worker for collect_defaults(). Writes into $out by reference,
426 - * building a fieldset's default as the nested object of its own children.
427 - *
428 - * @param array $fields The fields list to walk.
429 - * @param array $out Accumulator, keyed by field id.
430 - */
431 - protected function collect_field_defaults(array $fields, array &$out): void
432 - {
433 - foreach ($fields as $field) {
434 - if (! \is_array($field)) {
435 - continue;
436 - }
437 - $id = $field['id'] ?? '';
438 - $type = $field['type'] ?? '';
439 -
440 - // A fieldset's default is the nested object of its children's
441 - // defaults, stored under the fieldset's own id (recurses, so a
442 - // fieldset nested inside a fieldset nests correctly too).
443 - if (
444 - $type === 'fieldset'
445 - && $id !== ''
446 - && ! empty($field['fields'])
447 - && \is_array($field['fields'])
448 - ) {
449 - $nested = [];
450 - $this->collect_field_defaults($field['fields'], $nested);
451 - if (! empty($nested)) {
452 - $out[$id] = $nested;
453 - }
454 - continue;
455 - }
456 -
457 - // An ordinary field with a declared default (this also covers
458 - // group/repeater, whose own `default` is a list of rows — we do NOT
459 - // recurse into their per-row template fields).
460 - if ($id !== '' && \array_key_exists('default', $field)) {
461 - $out[$id] = $this->decode_labels($field['default']);
462 - }
463 -
464 - // section_tab sub-tabs: their fields save flat at the top level.
465 - if (! empty($field['tabs']) && \is_array($field['tabs'])) {
466 - foreach ($field['tabs'] as $tab) {
467 - if (! empty($tab['fields']) && \is_array($tab['fields'])) {
468 - $this->collect_field_defaults($tab['fields'], $out);
469 - }
470 - }
471 - }
472 - }
475 + // The walk itself lives in SchemaDefaults so the install seeder
476 + // (Admin::seed_default_options) resolves defaults through exactly the
477 + // same code path this controller does.
478 + return SchemaDefaults::collect($sections);
473 479 }
474 480
475 481 /**
476 482 * Merge saved values over schema defaults.