From 438117b01c0deee7e2679b92a1bba4b0de61cd0b Mon Sep 17 00:00:00 2001 From: KJ Roelke Date: Fri, 14 Nov 2025 22:10:17 -0600 Subject: [PATCH 1/9] Migrate cornerstone code (#12) * update repo (#6) * update repo * update gha name * add package-lock * test * add missing key path * update key * update deploy * update theme * switch ssh test * update ssh config * update tests * update config * add build steps back in * add needs to wait for artifact upload * update ci * finalize devops * init theme migration * reset theme and changelog semver * add styles * enqueue assets * finish theme init * fix missing asset enqueue * swap to fse * update styles * update footer * remove bs card for now * add styles and patterns * add new index template * add missing php bits * import npm code and add packages * fix flex reverse toggle * fix configs * update styles * opt out of core patterns * add single * add block style override * update templates * update single template * update theme.json fonts * add templates * reset styles and templates * update footer template * init form block * update configs * update form and init cf turnstile * add cloudflare protection * update form controls * finish form block * fix webpack * final fixes to v2 --- .github/workflows/deploy.yml | 27 + .vscode/launch.json | 49 + .vscode/settings.json | 16 +- changelog.md | 4 + eslint.config.mjs | 2 +- inc/theme/class-gutenberg-handler.php | 40 +- inc/theme/class-rest-router.php | 179 + inc/theme/class-theme-init.php | 124 +- inc/theme/class-utils-loader.php | 80 + inc/theme/navwalkers/class-navwalker.php | 245 + package-lock.json | 4899 +++++++++++------ package.json | 31 +- parts/footer.html | 1 + parts/header.html | 1 + patterns/footer.php | 19 + patterns/header.php | 19 + patterns/hidden-blog-heading.php | 16 + patterns/page-no-header.php | 21 + patterns/post-card.php | 32 + patterns/pricing-card.php | 36 + patterns/pricing-columns.php | 172 + patterns/template-query-loop.php | 46 + src/index.ts | 15 - .../interest-form-block/BlockStyles.tsx | 71 + src/js/blocks/interest-form-block/Edit.tsx | 94 + .../interest-form-block/_lib/parseSpacing.ts | 21 + src/js/blocks/interest-form-block/block.json | 51 + src/js/blocks/interest-form-block/consts.ts | 13 + .../hooks/useColorPalette.tsx | 25 + src/js/blocks/interest-form-block/index.tsx | 23 + src/js/blocks/interest-form-block/render.php | 127 + src/js/blocks/interest-form-block/style.scss | 197 + src/js/blocks/interest-form-block/view.ts | 58 + src/js/front-page/index.ts | 12 + src/js/global.d.ts | 9 + src/js/gutenberg/editDefaultBlocks.ts | 8 + .../flex-reverse-toggle/FlexReverse.tsx | 247 + .../addFlexReverseToggle.tsx | 15 + src/js/vendors/bootstrap.js | 18 + src/styles/_themeco-overrides.scss | 9 - src/styles/abstracts/_bs_breakpoints.scss | 172 + src/styles/abstracts/_fluid-type-utils.scss | 133 + src/styles/abstracts/_functions.scss | 16 + src/styles/abstracts/_mixins.scss | 9 + src/styles/abstracts/_variables.scss | 27 + src/styles/base/_base.scss | 15 +- src/styles/base/_typography.scss | 108 + src/styles/base/_utilities.scss | 14 +- src/styles/block-overrides/_button.scss | 30 + src/styles/block-overrides/_post-excerpt.scss | 36 + src/styles/block-overrides/_query.scss | 11 + src/styles/main.scss | 9 +- .../plugin-overrides/_contact-form-seven.scss | 71 +- src/styles/vendors/bootstrap.scss | 196 + style.css | 5 +- templates/category.html | 94 + templates/index.html | 101 + templates/page-blank.html | 5 + templates/page-no-footer.html | 7 + templates/page-no-header.html | 7 + templates/page-no-title.html | 9 + templates/page.html | 22 + templates/search.html | 102 + templates/single.html | 30 + theme.json | 337 +- tsconfig.json | 7 +- webpack.config.cjs | 96 + 67 files changed, 6732 insertions(+), 2009 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 .vscode/launch.json create mode 100644 inc/theme/class-rest-router.php create mode 100644 inc/theme/class-utils-loader.php create mode 100644 inc/theme/navwalkers/class-navwalker.php create mode 100644 parts/footer.html create mode 100644 parts/header.html create mode 100644 patterns/footer.php create mode 100644 patterns/header.php create mode 100644 patterns/hidden-blog-heading.php create mode 100644 patterns/page-no-header.php create mode 100644 patterns/post-card.php create mode 100644 patterns/pricing-card.php create mode 100644 patterns/pricing-columns.php create mode 100644 patterns/template-query-loop.php create mode 100644 src/js/blocks/interest-form-block/BlockStyles.tsx create mode 100644 src/js/blocks/interest-form-block/Edit.tsx create mode 100644 src/js/blocks/interest-form-block/_lib/parseSpacing.ts create mode 100644 src/js/blocks/interest-form-block/block.json create mode 100644 src/js/blocks/interest-form-block/consts.ts create mode 100644 src/js/blocks/interest-form-block/hooks/useColorPalette.tsx create mode 100644 src/js/blocks/interest-form-block/index.tsx create mode 100644 src/js/blocks/interest-form-block/render.php create mode 100644 src/js/blocks/interest-form-block/style.scss create mode 100644 src/js/blocks/interest-form-block/view.ts create mode 100644 src/js/front-page/index.ts create mode 100644 src/js/global.d.ts create mode 100644 src/js/gutenberg/editDefaultBlocks.ts create mode 100644 src/js/gutenberg/flex-reverse-toggle/FlexReverse.tsx create mode 100644 src/js/gutenberg/flex-reverse-toggle/addFlexReverseToggle.tsx create mode 100644 src/js/vendors/bootstrap.js delete mode 100644 src/styles/_themeco-overrides.scss create mode 100644 src/styles/abstracts/_bs_breakpoints.scss create mode 100644 src/styles/abstracts/_fluid-type-utils.scss create mode 100644 src/styles/abstracts/_functions.scss create mode 100644 src/styles/abstracts/_mixins.scss create mode 100644 src/styles/abstracts/_variables.scss create mode 100644 src/styles/base/_typography.scss create mode 100644 src/styles/block-overrides/_button.scss create mode 100644 src/styles/block-overrides/_post-excerpt.scss create mode 100644 src/styles/block-overrides/_query.scss create mode 100644 src/styles/vendors/bootstrap.scss create mode 100644 templates/category.html create mode 100644 templates/index.html create mode 100644 templates/page-blank.html create mode 100644 templates/page-no-footer.html create mode 100644 templates/page-no-header.html create mode 100644 templates/page-no-title.html create mode 100644 templates/page.html create mode 100644 templates/search.html create mode 100644 templates/single.html create mode 100644 webpack.config.cjs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..5102723 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,27 @@ +name: Deploy to SiteGround +on: + push: + branches: [stg, main] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + deploy-prod: + name: Deploy to Production + if: github.ref == 'refs/heads/main' + uses: macrosbysara/shared-github-actions/.github/workflows/deploy-theme.yml@main + with: + REMOTE: # Remote folder to deploy to + secrets: inherit + + deploy-stg: + name: Deploy to Staging + if: github.ref == 'refs/heads/stg' + uses: macrosbysara/shared-github-actions/.github/workflows/deploy-theme.yml@main + with: + REMOTE: staging6.macrosbysara.com + theme_name: "macros-by-sara" + flags: "-azvr --delete" + secrets: inherit diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..986ffb4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,49 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug 3.0 (Local)", + "type": "php", + "request": "launch", + "port": 9003, + "xdebugSettings": { + "max_children": 128, + "max_data": 1024, + "max_depth": 3, + "show_hidden": 1 + }, + "pathMappings": { + "/Users/kjroelke/Local Sites/macros-by-sara/app/public/wp-content/themes/macros-by-sara": "${workspaceFolder}" + } + }, + { + "name": "Listen for Xdebug (Local)", + "type": "php", + "request": "launch", + "port": 9000, + "xdebugSettings": { + "max_children": 128, + "max_data": 1024, + "max_depth": 3, + "show_hidden": 1 + }, + "pathMappings": { + "/Users/kjroelke/Local Sites/macros-by-sara/app/public/wp-content/themes/macros-by-sara": "${workspaceFolder}" + } + }, + { + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 9000, + "xdebugSettings": { + "max_children": 128, + "max_data": 1024, + "max_depth": 3, + "show_hidden": 1 + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index a3145ce..15f9023 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,7 +35,21 @@ "editor.useTabStops": true, "prettier.useTabs": false }, - "cSpell.words": [ "cpts", "Linktree", "macrosbysara", "wpcf" ], + "cSpell.words": [ + "alignfull", + "alignwide", + "atts", + "azvr", + "bloginfo", + "choctawnationofoklahoma", + "cpts", + "Linktree", + "macrosbysara", + "remoteip", + "trackbacks", + "wght", + "wpcf" + ], "css.format.spaceAroundSelectorSeparator": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": "always", diff --git a/changelog.md b/changelog.md index a786783..1a97ce2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## 2.0.0 - [November 1, 2025] + +- New Theme! + ## 1.3.2 - [October 29, 2025] - Chore: Add lints and configs diff --git a/eslint.config.mjs b/eslint.config.mjs index 95ed3cc..98ccf31 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -29,7 +29,7 @@ export default defineConfig( [ ) ), { - files: [ 'wp-content/themes/**/src/js/**/*.{js,ts,jsx,tsx}' ], + files: [ 'src/js/**/*.{js,ts,jsx,tsx}' ], languageOptions: { globals: globals.browser, }, diff --git a/inc/theme/class-gutenberg-handler.php b/inc/theme/class-gutenberg-handler.php index ace6708..d2b87bf 100644 --- a/inc/theme/class-gutenberg-handler.php +++ b/inc/theme/class-gutenberg-handler.php @@ -18,7 +18,27 @@ class Gutenberg_Handler { * Constructor */ public function __construct() { + add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_assets' ) ); add_action( 'after_setup_theme', array( $this, 'theme_supports' ) ); + add_action( 'init', array( $this, 'register_theme_blocks' ) ); + } + + /** + * Enqueue the block editor assets that control the layout of the Block Editor. + */ + public function enqueue_block_assets() { + $files = array( 'editDefaultBlocks' ); + foreach ( $files as $handle ) { + $assets = require_once get_stylesheet_directory() . "/build/admin/{$handle}.asset.php"; + + wp_enqueue_script( + $handle, + get_stylesheet_directory_uri() . "/build/admin/{$handle}.js", + $assets['dependencies'], + $assets['version'], + array( 'strategy' => 'defer' ) + ); + } } /** @@ -26,14 +46,26 @@ public function __construct() { */ public function theme_supports() { $opt_in_features = array( - 'disable-custom-colors', 'responsive-embeds', - 'disable-custom-gradients', - 'disable-custom-font-sizes', ); - foreach ( $opt_in_features as $feature ) { add_theme_support( $feature ); } + + $opt_out_features = array( + 'core-block-patterns', + ); + foreach ( $opt_out_features as $feature ) { + remove_theme_support( $feature ); + } + } + + /** + * Register any theme-specific blocks + */ + public function register_theme_blocks() { + // Load blocks + $blocks_path = get_template_directory() . '/build'; + wp_register_block_types_from_metadata_collection( $blocks_path . '/js/blocks', $blocks_path . '/blocks-manifest.php' ); } } diff --git a/inc/theme/class-rest-router.php b/inc/theme/class-rest-router.php new file mode 100644 index 0000000..060a5c4 --- /dev/null +++ b/inc/theme/class-rest-router.php @@ -0,0 +1,179 @@ +namespace = 'mbs/v1'; + add_action( 'rest_api_init', array( $this, 'register_routes' ) ); + add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_interest_form_script' ), 100 ); + } + + /** + * Register routes. + */ + public function register_routes() { + register_rest_route( + $this->namespace . '/forms', + '/interest-form', + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'handle_interest_form' ), + 'permission_callback' => array( $this, 'allow_public_access' ), + 'args' => array( + 'firstName' => array( + 'required' => true, + 'sanitize_callback' => 'sanitize_text_field', + ), + 'lastName' => array( + 'required' => true, + 'sanitize_callback' => 'sanitize_text_field', + ), + 'email' => array( + 'required' => true, + 'sanitize_callback' => 'sanitize_email', + 'validate_callback' => 'is_email', + ), + 'interest' => array( + 'required' => true, + 'sanitize_callback' => 'sanitize_text_field', + 'validate_callback' => function ( $param ) { + $valid_options = array( + 'macros', + 'habits', + 'one-time-macros', + 'fitness', + ); + return in_array( $param, $valid_options, true ); + }, + ), + ), + ) + ); + } + + /** + * Example endpoint callback. + * + * @param WP_REST_Request $request The REST request. + * @return WP_REST_Response The REST response. + */ + public function handle_interest_form( WP_REST_Request $request ): WP_REST_Response { + $first_name = $request->get_param( 'firstName' ); + $last_name = $request->get_param( 'lastName' ); + $email = $request->get_param( 'email' ); + $interest = $request->get_param( 'interest' ); + $data = array( + 'code' => 'success', + 'message' => 'Interest form submitted successfully!', + 'data' => array( + 'status' => 200, + 'firstName' => $first_name, + 'lastName' => $last_name, + 'email' => $email, + 'interest' => $interest, + ), + ); + return rest_ensure_response( $data ); + } + + /** + * Enqueue interest form script with localized REST API data. + */ + public function enqueue_interest_form_script() { + wp_localize_script( + 'global', + 'mbsRestApi', + array( + 'root' => esc_url_raw( rest_url() . $this->namespace ), + 'nonce' => wp_create_nonce( 'wp_rest' ), + ) + ); + wp_enqueue_script( + 'cloudflare', + 'https://challenges.cloudflare.com/turnstile/v0/api.js', + array( 'global' ), + null, // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion + array( + 'strategy' => 'async', + ) + ); + } + + /** + * Allow public access to the endpoint. + * + * @param WP_REST_Request $request The REST request. + * @return bool + */ + public function allow_public_access( WP_REST_Request $request ): bool { + $nonce = null; + $headers = $request->get_headers(); + if ( isset( $headers['x_wp_nonce'] ) ) { + $nonce = $headers['x_wp_nonce']; + } + $verified = wp_verify_nonce( $nonce[0], 'wp_rest' ); + if ( ! $verified ) { + return false; + } + if ( ! isset( $_POST['cf-turnstile-response'] ) ) { + return false; + } + return $this->cloudflare_validation( + sanitize_text_field( $_POST['cf-turnstile-response'] ?? '' ) + ); + } + + + /** + * Validate Cloudflare Turnstile response. + * + * @param string $token The Turnstile token from the client. + * @param string|null $remoteip Optional. The user's IP address. + * @return bool True if validation is successful, false otherwise. + */ + private function cloudflare_validation( string $token, ?string $remoteip = null ): bool { + $url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; + + $data = array( + 'secret' => CF_TURNSTILE_SECRET, + 'response' => $token, + ); + + if ( $remoteip ) { + $data['remoteip'] = $remoteip; + } + + $response = wp_remote_post( + $url, + array( + 'headers' => array( 'Content-Type' => 'application/x-www-form-urlencoded' ), + 'body' => $data, + 'timeout' => 10, + ) + ); + if ( is_wp_error( $response ) ) { + return false; + } + + $response = wp_remote_retrieve_body( $response ); + $response_data = json_decode( $response, true ); + return $response_data['success'] ?? false; + } +} diff --git a/inc/theme/class-theme-init.php b/inc/theme/class-theme-init.php index 165493a..951cf4b 100644 --- a/inc/theme/class-theme-init.php +++ b/inc/theme/class-theme-init.php @@ -13,68 +13,110 @@ * Class: Theme Init */ class Theme_Init { + /** + * Utils Loader + * + * @var Utils_Loader $loader + */ + private Utils_Loader $loader; /** * Constructor */ public function __construct() { - $this->load_files(); - add_filter( 'x_enqueue_parent_stylesheet', '__return_true' ); + require_once get_stylesheet_directory() . '/inc/theme/class-utils-loader.php'; + $this->loader = new Utils_Loader(); + $this->loader->load_files(); + $this->disable_discussion(); + add_action( 'after_setup_theme', array( $this, 'configure_theme_support' ) ); + add_action( 'init', array( $this, 'alter_post_types' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_filter( 'wp_speculation_rules_configuration', array( $this, 'handle_speculative_loading' ) ); } - /** - * Load Required Files - */ - private function load_files() { - $base_path = get_stylesheet_directory() . '/inc'; - $theme_files = array( - 'gutenberg-handler' => 'Gutenberg_Handler', - ); - foreach ( $theme_files as $file => $class ) { - require_once $base_path . "/theme/class-{$file}.php"; - if ( $class ) { - $class = __NAMESPACE__ . "\\{$class}"; - new $class(); + /** Remove comments, pings and trackbacks support from posts types. */ + private function disable_discussion() { + // Close comments on the front-end + add_filter( 'comments_open', '__return_false', 20, 2 ); + add_filter( 'pings_open', '__return_false', 20, 2 ); + + // Hide existing comments. + add_filter( 'comments_array', '__return_empty_array', 10, 2 ); + // Remove comments page in menu. + add_action( + 'admin_menu', + function () { + remove_menu_page( 'edit-comments.php' ); } - } - $plugin_files = array( - 'acf-handler' => array( - 'class' => 'ACF_Handler', - 'dir' => 'acf', - ), ); - foreach ( $plugin_files as $file => $data ) { - require_once $base_path . "/plugins/{$data['dir']}/class-{$file}.php"; - if ( $data['class'] ) { - $class = __NAMESPACE__ . "\\{$data['class']}"; - new $class(); + // Remove comments links from admin bar. + add_action( + 'init', + function () { + if ( is_admin_bar_showing() ) { + remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 ); + } } - } + ); } + /** Registers Theme Supports */ + public function configure_theme_support() { + add_theme_support( 'post-thumbnails' ); + add_theme_support( 'title-tag' ); + + register_nav_menus( + array( + 'primary_menu' => 'Primary Menu', + 'footer_menu' => 'Footer Menu', + ) + ); + } + + /** Alter Post Types. */ + public function alter_post_types() { + add_post_type_support( 'page', 'excerpt' ); + } + + /** * Enqueue scripts and styles. */ public function enqueue_scripts(): void { - $global_assets = require_once get_stylesheet_directory() . '/build/index.asset.php'; - - wp_enqueue_script( - 'global', - get_stylesheet_directory_uri() . '/build/index.js', - $global_assets['dependencies'], - $global_assets['version'], - array( 'strategy' => 'defer' ) - ); - wp_enqueue_style( - 'global', - get_stylesheet_directory_uri() . '/build/index.css', - $global_assets['dependencies'], - $global_assets['version'], + $files = array( + 'bootstrap' => array( + 'js' => 'vendors/bootstrap', + 'css' => 'vendors/bootstrap', + ), + 'global' => array( + 'js' => 'global', + 'css' => 'global', + ), ); + foreach ( $files as $handle => $paths ) { + $assets = require_once get_stylesheet_directory() . "/build/{$paths['js']}.asset.php"; + + $deps = $assets['dependencies']; + if ( 'bootstrap' !== $handle ) { + // Ensure assets load after bootstrap for proper overrides + $deps = array_merge( $deps, array( 'bootstrap' ) ); + } + wp_enqueue_script( + $handle, + get_stylesheet_directory_uri() . "/build/{$paths['js']}.js", + $deps, + $assets['version'], + array( 'strategy' => 'defer' ) + ); + wp_enqueue_style( + $handle, + get_stylesheet_directory_uri() . "/build/{$paths['css']}.css", + $deps, + $assets['version'], + ); + } } /** diff --git a/inc/theme/class-utils-loader.php b/inc/theme/class-utils-loader.php new file mode 100644 index 0000000..d8d3628 --- /dev/null +++ b/inc/theme/class-utils-loader.php @@ -0,0 +1,80 @@ +base_path = get_stylesheet_directory() . '/inc'; + } + + /** + * Load Required Files + */ + public function load_files() { + + // Require Navwalker + require_once $this->base_path . '/theme/navwalkers/class-navwalker.php'; + + // Theme Utils + $theme_files = array( + 'gutenberg-handler' => 'Gutenberg_Handler', + 'rest-router' => 'Rest_Router', + ); + $this->load_utils( '/theme', $theme_files ); + $this->load_acf_utils(); + } + + /** + * Load Utils + * + * @param string $path Path to utils. + * @param array $files Array of files to load. + */ + private function load_utils( string $path, array $files ) { + foreach ( $files as $file => $class ) { + require_once $this->base_path . "{$path}/class-{$file}.php"; + if ( $class ) { + $class = __NAMESPACE__ . "\\{$class}"; + new $class(); + } + } + } + + /** + * Load ACF Utils + */ + private function load_acf_utils() { + $plugin_files = array( + 'acf-handler' => array( + 'class' => 'ACF_Handler', + 'dir' => 'acf', + ), + ); + foreach ( $plugin_files as $file => $data ) { + require_once $this->base_path . "/plugins/{$data['dir']}/class-{$file}.php"; + if ( $data['class'] ) { + $class = __NAMESPACE__ . "\\{$data['class']}"; + new $class(); + + } + } + } +} diff --git a/inc/theme/navwalkers/class-navwalker.php b/inc/theme/navwalkers/class-navwalker.php new file mode 100644 index 0000000..1809e3c --- /dev/null +++ b/inc/theme/navwalkers/class-navwalker.php @@ -0,0 +1,245 @@ + + * + * // end_lvl() + * + * @package MacrosBySara + */ + +namespace MacrosBySara; + +use stdClass; +use Walker_Nav_Menu; +use WP_Post; + +/** + * Extends the WP Nav Walker + * Based on the CNO Navwalker + * + * @link https://github.com/choctaw-nation/cno-template-theme/blob/hybrid-block-theme/wp-content/themes/cno-starter-theme/inc/theme/navwalkers/class-navwalker.php + */ +class Navwalker extends Walker_Nav_Menu { + /** The current nav item + * + * @var WP_Post $current_item + */ + protected WP_Post $current_item; + + /** + * Bootstrap alignment classes + * + * @var string[] $dropdown_menu_alignment_values + */ + protected $dropdown_menu_alignment_values = array( + 'dropdown-menu-start', + 'dropdown-menu-end', + 'dropdown-menu-sm-start', + 'dropdown-menu-sm-end', + 'dropdown-menu-md-start', + 'dropdown-menu-md-end', + 'dropdown-menu-lg-start', + 'dropdown-menu-lg-end', + 'dropdown-menu-xl-start', + 'dropdown-menu-xl-end', + 'dropdown-menu-xxl-start', + 'dropdown-menu-xxl-end', + ); + + /** + * Depth of menu item. Used for padding. + * + * @var int $depth + */ + protected int $depth; + + /** + * The array of wp_nav_menu() arguments as an object. + * + * @var ?stdClass $args + */ + protected ?stdClass $args; + + /** + * Optional. ID of the current menu item. Default 0. + * + * @var int $id + */ + protected int $id; + + /** Whether Current Item in Navwalker is Top Level or not + * + * @var bool $is_top_level + */ + protected bool $is_top_level; + + /** + * Whether the current item has an href pointing to '#' or not + * + * @var bool $href_is_empty + */ + protected bool $href_is_empty; + + /** + * The Opening Level + * + * @param string $output the html + * @param int $depth whether we are at the top-level or a sub-level + * @param ?stdClass $args An object of wp_nav_menu() arguments. + */ + public function start_lvl( &$output, $depth = 0, $args = \null ) { + $dropdown_menu_class = array(); + // handle user-inputted classes + foreach ( $this->current_item->classes as $class ) { + if ( in_array( $class, $this->dropdown_menu_alignment_values, true ) ) { + $dropdown_menu_class[] = $class; + } + } + $indent = str_repeat( "\t", $depth ); + $this->is_top_level = 0 === $depth; + $submenu = ( $this->is_top_level ) ? '' : ' sub-menu'; + + $output .= "\n$indent + + + + + + + + diff --git a/src/js/blocks/interest-form-block/Edit.tsx b/src/js/blocks/interest-form-block/Edit.tsx index 688e273..a6a2326 100644 --- a/src/js/blocks/interest-form-block/Edit.tsx +++ b/src/js/blocks/interest-form-block/Edit.tsx @@ -73,6 +73,7 @@ export default function Edit( props ) { aria-label="Interest" autoComplete="section-interest" > + { selectOptions.map( ( option ) => (