header-builder.php

I’ll build this as a reusable inc/builders/header-builder.php for your RX theme, with many header features: logo, menus, search, CTA, social links, top bar, sticky/mobile header, schema, accessibility, hooks, and customization filters.

Below is an advanced inc/builders/header-builder.php file for your RX Theme. It includes many possible header functions: logo, site title, primary menu, top bar, social icons, CTA button, search, mobile menu, sticky header, transparent header support, schema markup, hooks, accessibility, customizer-friendly filters, and safe fallback behavior.

Save this file here:

rx-theme/inc/builders/header-builder.php

Then include it from functions.php:

require_once get_template_directory() . '/inc/builders/header-builder.php';

Complete inc/builders/header-builder.php

<?php
/**
 * RX Theme Header Builder
 *
 * File: inc/builders/header-builder.php
 *
 * Advanced reusable header builder for RX Theme.
 *
 * Features:
 * - Top bar
 * - Header logo
 * - Site title and tagline
 * - Primary navigation
 * - Secondary navigation support
 * - Mobile navigation toggle
 * - Search button and search form
 * - CTA button
 * - Social links
 * - Sticky header
 * - Transparent header support
 * - Header layout filters
 * - Accessibility-ready markup
 * - Schema.org support
 * - WordPress hooks
 * - Safe fallbacks
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'RX_Header_Builder' ) ) :

	final class RX_Header_Builder {

		/**
		 * Class instance.
		 *
		 * @var RX_Header_Builder|null
		 */
		private static $instance = null;

		/**
		 * Header settings.
		 *
		 * @var array
		 */
		private $settings = array();

		/**
		 * Get instance.
		 *
		 * @return RX_Header_Builder
		 */
		public static function instance() {
			if ( null === self::$instance ) {
				self::$instance = new self();
			}

			return self::$instance;
		}

		/**
		 * Constructor.
		 */
		private function __construct() {
			$this->settings = $this->get_default_settings();

			add_action( 'after_setup_theme', array( $this, 'register_menus' ) );
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_header_assets' ) );

			add_action( 'rx_theme_header', array( $this, 'render_header' ) );
			add_action( 'rx_theme_mobile_header', array( $this, 'render_mobile_header' ) );

			add_filter( 'body_class', array( $this, 'body_classes' ) );
		}

		/**
		 * Default header settings.
		 *
		 * You can override these using:
		 * add_filter( 'rx_header_builder_settings', function( $settings ) { ... } );
		 *
		 * @return array
		 */
		private function get_default_settings() {
			$settings = array(
				'enable_top_bar'          => true,
				'enable_sticky_header'    => true,
				'enable_transparent'      => false,
				'enable_search'           => true,
				'enable_cta'              => true,
				'enable_social_links'     => true,
				'enable_tagline'          => true,
				'enable_mobile_header'    => true,
				'enable_schema'           => true,
				'enable_skip_link'        => true,

				'container_class'         => 'rx-container',
				'header_layout'           => 'default',
				'logo_position'           => 'left',
				'menu_position'           => 'right',

				'top_bar_left_text'       => __( 'A global war against illness!', 'rx-theme' ),
				'top_bar_right_text'      => '',

				'cta_text'                => __( 'Book Appointment', 'rx-theme' ),
				'cta_url'                 => home_url( '/contact/' ),
				'cta_target'              => '_self',

				'search_placeholder'      => __( 'Search...', 'rx-theme' ),

				'social_links'            => array(
					'facebook'  => '',
					'twitter'   => '',
					'linkedin'  => '',
					'youtube'   => '',
					'instagram' => '',
					'github'    => '',
				),
			);

			return apply_filters( 'rx_header_builder_settings', $settings );
		}

		/**
		 * Register menus.
		 *
		 * @return void
		 */
		public function register_menus() {
			register_nav_menus(
				array(
					'primary'   => esc_html__( 'Primary Menu', 'rx-theme' ),
					'secondary' => esc_html__( 'Secondary Menu', 'rx-theme' ),
					'mobile'    => esc_html__( 'Mobile Menu', 'rx-theme' ),
					'topbar'    => esc_html__( 'Top Bar Menu', 'rx-theme' ),
				)
			);
		}

		/**
		 * Enqueue header CSS and JS.
		 *
		 * @return void
		 */
		public function enqueue_header_assets() {
			$theme_version = wp_get_theme()->get( 'Version' );

			wp_register_style(
				'rx-header-builder',
				get_template_directory_uri() . '/assets/css/header-builder.css',
				array(),
				$theme_version
			);

			wp_register_script(
				'rx-header-builder',
				get_template_directory_uri() . '/assets/js/header-builder.js',
				array(),
				$theme_version,
				true
			);

			wp_localize_script(
				'rx-header-builder',
				'rxHeaderBuilder',
				array(
					'ajaxUrl'       => admin_url( 'admin-ajax.php' ),
					'homeUrl'       => home_url( '/' ),
					'isSticky'      => (bool) $this->settings['enable_sticky_header'],
					'isSearch'      => (bool) $this->settings['enable_search'],
					'menuLabelOpen' => esc_html__( 'Open menu', 'rx-theme' ),
					'menuLabelClose'=> esc_html__( 'Close menu', 'rx-theme' ),
				)
			);

			wp_enqueue_style( 'rx-header-builder' );
			wp_enqueue_script( 'rx-header-builder' );

			$this->inline_header_css();
		}

		/**
		 * Add body classes.
		 *
		 * @param array $classes Body classes.
		 * @return array
		 */
		public function body_classes( $classes ) {
			if ( ! empty( $this->settings['enable_sticky_header'] ) ) {
				$classes[] = 'rx-has-sticky-header';
			}

			if ( ! empty( $this->settings['enable_transparent'] ) ) {
				$classes[] = 'rx-has-transparent-header';
			}

			$classes[] = 'rx-header-layout-' . sanitize_html_class( $this->settings['header_layout'] );

			return $classes;
		}

		/**
		 * Render full header.
		 *
		 * @return void
		 */
		public function render_header() {
			do_action( 'rx_before_header' );

			if ( ! empty( $this->settings['enable_skip_link'] ) ) {
				$this->render_skip_link();
			}

			if ( ! empty( $this->settings['enable_top_bar'] ) ) {
				$this->render_top_bar();
			}

			$header_classes = $this->get_header_classes();

			?>
			<header id="masthead" class="<?php echo esc_attr( implode( ' ', $header_classes ) ); ?>" <?php $this->schema_attr( 'WPHeader' ); ?>>
				<?php do_action( 'rx_header_start' ); ?>

				<div class="<?php echo esc_attr( $this->settings['container_class'] ); ?>">
					<div class="rx-header-inner">

						<div class="rx-header-branding">
							<?php $this->render_branding(); ?>
						</div>

						<nav id="site-navigation" class="rx-primary-navigation" aria-label="<?php esc_attr_e( 'Primary Navigation', 'rx-theme' ); ?>">
							<?php $this->render_primary_menu(); ?>
						</nav>

						<div class="rx-header-actions">
							<?php
							if ( ! empty( $this->settings['enable_search'] ) ) {
								$this->render_search_button();
							}

							if ( ! empty( $this->settings['enable_social_links'] ) ) {
								$this->render_social_links();
							}

							if ( ! empty( $this->settings['enable_cta'] ) ) {
								$this->render_cta_button();
							}

							if ( ! empty( $this->settings['enable_mobile_header'] ) ) {
								$this->render_mobile_toggle();
							}
							?>
						</div>

					</div>
				</div>

				<?php
				if ( ! empty( $this->settings['enable_search'] ) ) {
					$this->render_search_overlay();
				}

				if ( ! empty( $this->settings['enable_mobile_header'] ) ) {
					$this->render_mobile_panel();
				}
				?>

				<?php do_action( 'rx_header_end' ); ?>
			</header>
			<?php

			do_action( 'rx_after_header' );
		}

		/**
		 * Render mobile header only.
		 *
		 * @return void
		 */
		public function render_mobile_header() {
			?>
			<div class="rx-mobile-only-header">
				<div class="<?php echo esc_attr( $this->settings['container_class'] ); ?>">
					<div class="rx-mobile-header-inner">
						<?php $this->render_branding(); ?>
						<?php $this->render_mobile_toggle(); ?>
					</div>
				</div>
			</div>
			<?php
		}

		/**
		 * Render skip link.
		 *
		 * @return void
		 */
		private function render_skip_link() {
			?>
			<a class="rx-skip-link screen-reader-text" href="#content">
				<?php esc_html_e( 'Skip to content', 'rx-theme' ); ?>
			</a>
			<?php
		}

		/**
		 * Render top bar.
		 *
		 * @return void
		 */
		private function render_top_bar() {
			$left_text  = $this->settings['top_bar_left_text'];
			$right_text = $this->settings['top_bar_right_text'];

			?>
			<div class="rx-top-bar">
				<div class="<?php echo esc_attr( $this->settings['container_class'] ); ?>">
					<div class="rx-top-bar-inner">

						<div class="rx-top-bar-left">
							<?php
							if ( ! empty( $left_text ) ) {
								echo wp_kses_post( $left_text );
							}

							if ( has_nav_menu( 'topbar' ) ) {
								wp_nav_menu(
									array(
										'theme_location' => 'topbar',
										'menu_class'     => 'rx-topbar-menu',
										'container'      => false,
										'depth'          => 1,
										'fallback_cb'    => false,
									)
								);
							}
							?>
						</div>

						<div class="rx-top-bar-right">
							<?php
							if ( ! empty( $right_text ) ) {
								echo wp_kses_post( $right_text );
							}

							if ( ! empty( $this->settings['enable_social_links'] ) ) {
								$this->render_social_links( 'topbar' );
							}
							?>
						</div>

					</div>
				</div>
			</div>
			<?php
		}

		/**
		 * Render branding area.
		 *
		 * @return void
		 */
		private function render_branding() {
			?>
			<div class="rx-site-branding" <?php $this->schema_attr( 'Organization' ); ?>>
				<?php
				if ( has_custom_logo() ) {
					the_custom_logo();
				} else {
					$this->render_text_logo();
				}
				?>

				<?php if ( ! has_custom_logo() ) : ?>
					<?php $this->render_site_description(); ?>
				<?php endif; ?>
			</div>
			<?php
		}

		/**
		 * Render text logo fallback.
		 *
		 * @return void
		 */
		private function render_text_logo() {
			$site_name = get_bloginfo( 'name' );

			if ( is_front_page() && is_home() ) {
				?>
				<h1 class="rx-site-title">
					<a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
						<?php echo esc_html( $site_name ); ?>
					</a>
				</h1>
				<?php
			} else {
				?>
				<p class="rx-site-title">
					<a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
						<?php echo esc_html( $site_name ); ?>
					</a>
				</p>
				<?php
			}
		}

		/**
		 * Render site description.
		 *
		 * @return void
		 */
		private function render_site_description() {
			if ( empty( $this->settings['enable_tagline'] ) ) {
				return;
			}

			$description = get_bloginfo( 'description', 'display' );

			if ( $description || is_customize_preview() ) {
				?>
				<p class="rx-site-description">
					<?php echo esc_html( $description ); ?>
				</p>
				<?php
			}
		}

		/**
		 * Render primary menu.
		 *
		 * @return void
		 */
		private function render_primary_menu() {
			if ( has_nav_menu( 'primary' ) ) {
				wp_nav_menu(
					array(
						'theme_location' => 'primary',
						'menu_id'        => 'primary-menu',
						'menu_class'     => 'rx-primary-menu',
						'container'      => false,
						'fallback_cb'    => false,
						'depth'          => 4,
					)
				);
			} else {
				$this->render_fallback_menu();
			}
		}

		/**
		 * Render fallback menu.
		 *
		 * @return void
		 */
		private function render_fallback_menu() {
			?>
			<ul id="primary-menu" class="rx-primary-menu rx-fallback-menu">
				<li>
					<a href="<?php echo esc_url( home_url( '/' ) ); ?>">
						<?php esc_html_e( 'Home', 'rx-theme' ); ?>
					</a>
				</li>

				<?php
				wp_list_pages(
					array(
						'title_li' => '',
						'depth'    => 1,
					)
				);
				?>
			</ul>
			<?php
		}

		/**
		 * Render mobile toggle.
		 *
		 * @return void
		 */
		private function render_mobile_toggle() {
			?>
			<button
				type="button"
				class="rx-mobile-menu-toggle"
				aria-controls="rx-mobile-panel"
				aria-expanded="false"
				aria-label="<?php esc_attr_e( 'Open mobile menu', 'rx-theme' ); ?>"
			>
				<span class="rx-toggle-line"></span>
				<span class="rx-toggle-line"></span>
				<span class="rx-toggle-line"></span>
			</button>
			<?php
		}

		/**
		 * Render mobile panel.
		 *
		 * @return void
		 */
		private function render_mobile_panel() {
			?>
			<div id="rx-mobile-panel" class="rx-mobile-panel" aria-hidden="true">
				<div class="rx-mobile-panel-overlay"></div>

				<div class="rx-mobile-panel-content" role="dialog" aria-modal="true" aria-label="<?php esc_attr_e( 'Mobile Menu', 'rx-theme' ); ?>">
					<div class="rx-mobile-panel-header">
						<?php $this->render_branding(); ?>

						<button type="button" class="rx-mobile-panel-close" aria-label="<?php esc_attr_e( 'Close mobile menu', 'rx-theme' ); ?>">
							<span aria-hidden="true">&times;</span>
						</button>
					</div>

					<nav class="rx-mobile-navigation" aria-label="<?php esc_attr_e( 'Mobile Navigation', 'rx-theme' ); ?>">
						<?php
						if ( has_nav_menu( 'mobile' ) ) {
							wp_nav_menu(
								array(
									'theme_location' => 'mobile',
									'menu_class'     => 'rx-mobile-menu',
									'container'      => false,
									'fallback_cb'    => false,
									'depth'          => 4,
								)
							);
						} else {
							wp_nav_menu(
								array(
									'theme_location' => 'primary',
									'menu_class'     => 'rx-mobile-menu',
									'container'      => false,
									'fallback_cb'    => array( $this, 'render_mobile_fallback_menu' ),
									'depth'          => 4,
								)
							);
						}
						?>
					</nav>

					<?php if ( ! empty( $this->settings['enable_search'] ) ) : ?>
						<div class="rx-mobile-search">
							<?php get_search_form(); ?>
						</div>
					<?php endif; ?>

					<?php if ( ! empty( $this->settings['enable_cta'] ) ) : ?>
						<div class="rx-mobile-cta">
							<?php $this->render_cta_button(); ?>
						</div>
					<?php endif; ?>

					<?php if ( ! empty( $this->settings['enable_social_links'] ) ) : ?>
						<div class="rx-mobile-social">
							<?php $this->render_social_links( 'mobile' ); ?>
						</div>
					<?php endif; ?>

				</div>
			</div>
			<?php
		}

		/**
		 * Mobile fallback menu.
		 *
		 * @return void
		 */
		public function render_mobile_fallback_menu() {
			?>
			<ul class="rx-mobile-menu rx-fallback-menu">
				<li>
					<a href="<?php echo esc_url( home_url( '/' ) ); ?>">
						<?php esc_html_e( 'Home', 'rx-theme' ); ?>
					</a>
				</li>
				<?php
				wp_list_pages(
					array(
						'title_li' => '',
						'depth'    => 2,
					)
				);
				?>
			</ul>
			<?php
		}

		/**
		 * Render search button.
		 *
		 * @return void
		 */
		private function render_search_button() {
			?>
			<button
				type="button"
				class="rx-header-search-toggle"
				aria-controls="rx-search-overlay"
				aria-expanded="false"
				aria-label="<?php esc_attr_e( 'Open search', 'rx-theme' ); ?>"
			>
				<span class="rx-search-icon" aria-hidden="true">
					<?php $this->icon_svg( 'search' ); ?>
				</span>
			</button>
			<?php
		}

		/**
		 * Render search overlay.
		 *
		 * @return void
		 */
		private function render_search_overlay() {
			?>
			<div id="rx-search-overlay" class="rx-search-overlay" aria-hidden="true">
				<div class="rx-search-overlay-inner">
					<button type="button" class="rx-search-close" aria-label="<?php esc_attr_e( 'Close search', 'rx-theme' ); ?>">
						<span aria-hidden="true">&times;</span>
					</button>

					<form role="search" method="get" class="rx-search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
						<label class="screen-reader-text" for="rx-search-field">
							<?php esc_html_e( 'Search for:', 'rx-theme' ); ?>
						</label>

						<input
							type="search"
							id="rx-search-field"
							class="rx-search-field"
							placeholder="<?php echo esc_attr( $this->settings['search_placeholder'] ); ?>"
							value="<?php echo esc_attr( get_search_query() ); ?>"
							name="s"
						/>

						<button type="submit" class="rx-search-submit">
							<?php esc_html_e( 'Search', 'rx-theme' ); ?>
						</button>
					</form>
				</div>
			</div>
			<?php
		}

		/**
		 * Render CTA button.
		 *
		 * @return void
		 */
		private function render_cta_button() {
			$cta_text   = $this->settings['cta_text'];
			$cta_url    = $this->settings['cta_url'];
			$cta_target = $this->settings['cta_target'];

			if ( empty( $cta_text ) || empty( $cta_url ) ) {
				return;
			}

			$rel = '_blank' === $cta_target ? 'noopener noreferrer' : '';

			?>
			<a
				class="rx-header-cta"
				href="<?php echo esc_url( $cta_url ); ?>"
				target="<?php echo esc_attr( $cta_target ); ?>"
				<?php if ( $rel ) : ?>
					rel="<?php echo esc_attr( $rel ); ?>"
				<?php endif; ?>
			>
				<?php echo esc_html( $cta_text ); ?>
			</a>
			<?php
		}

		/**
		 * Render social links.
		 *
		 * @param string $context Context.
		 * @return void
		 */
		private function render_social_links( $context = 'header' ) {
			$social_links = $this->settings['social_links'];

			if ( empty( $social_links ) || ! is_array( $social_links ) ) {
				return;
			}

			$has_link = false;

			foreach ( $social_links as $url ) {
				if ( ! empty( $url ) ) {
					$has_link = true;
					break;
				}
			}

			if ( ! $has_link ) {
				return;
			}

			?>
			<div class="rx-social-links rx-social-links-<?php echo esc_attr( $context ); ?>">
				<?php foreach ( $social_links as $network => $url ) : ?>
					<?php if ( empty( $url ) ) : ?>
						<?php continue; ?>
					<?php endif; ?>

					<a
						class="rx-social-link rx-social-<?php echo esc_attr( sanitize_html_class( $network ) ); ?>"
						href="<?php echo esc_url( $url ); ?>"
						target="_blank"
						rel="noopener noreferrer"
						aria-label="<?php echo esc_attr( ucfirst( $network ) ); ?>"
					>
						<?php $this->icon_svg( $network ); ?>
					</a>
				<?php endforeach; ?>
			</div>
			<?php
		}

		/**
		 * Get header classes.
		 *
		 * @return array
		 */
		private function get_header_classes() {
			$classes = array(
				'rx-site-header',
				'rx-header-builder',
				'rx-header-layout-' . sanitize_html_class( $this->settings['header_layout'] ),
				'rx-logo-position-' . sanitize_html_class( $this->settings['logo_position'] ),
				'rx-menu-position-' . sanitize_html_class( $this->settings['menu_position'] ),
			);

			if ( ! empty( $this->settings['enable_sticky_header'] ) ) {
				$classes[] = 'rx-sticky-header';
			}

			if ( ! empty( $this->settings['enable_transparent'] ) ) {
				$classes[] = 'rx-transparent-header';
			}

			return apply_filters( 'rx_header_classes', $classes );
		}

		/**
		 * Schema attribute.
		 *
		 * @param string $type Schema type.
		 * @return void
		 */
		private function schema_attr( $type = '' ) {
			if ( empty( $this->settings['enable_schema'] ) || empty( $type ) ) {
				return;
			}

			echo 'itemscope itemtype="https://schema.org/' . esc_attr( $type ) . '"';
		}

		/**
		 * Inline CSS fallback.
		 *
		 * You can move this CSS into:
		 * assets/css/header-builder.css
		 *
		 * @return void
		 */
		private function inline_header_css() {
			$css = '
				.rx-container {
					width: min(1200px, calc(100% - 32px));
					margin-left: auto;
					margin-right: auto;
				}

				.rx-skip-link {
					position: absolute;
					left: -9999px;
					top: 10px;
					background: #111;
					color: #fff;
					padding: 10px 16px;
					z-index: 999999;
				}

				.rx-skip-link:focus {
					left: 10px;
				}

				.rx-top-bar {
					background: #0f172a;
					color: #fff;
					font-size: 14px;
				}

				.rx-top-bar a {
					color: inherit;
					text-decoration: none;
				}

				.rx-top-bar-inner {
					display: flex;
					align-items: center;
					justify-content: space-between;
					gap: 20px;
					min-height: 38px;
				}

				.rx-site-header {
					background: #fff;
					border-bottom: 1px solid rgba(15, 23, 42, 0.08);
					position: relative;
					z-index: 999;
				}

				.rx-sticky-header {
					position: sticky;
					top: 0;
				}

				.admin-bar .rx-sticky-header {
					top: 32px;
				}

				.rx-transparent-header {
					background: transparent;
					position: absolute;
					left: 0;
					right: 0;
					top: 0;
				}

				.rx-header-inner {
					display: flex;
					align-items: center;
					justify-content: space-between;
					gap: 24px;
					min-height: 82px;
				}

				.rx-site-branding {
					display: flex;
					align-items: center;
					flex-direction: column;
					align-items: flex-start;
					min-width: 160px;
				}

				.rx-site-title {
					margin: 0;
					font-size: 28px;
					line-height: 1.1;
					font-weight: 800;
				}

				.rx-site-title a {
					color: #0f172a;
					text-decoration: none;
				}

				.rx-site-description {
					margin: 4px 0 0;
					font-size: 13px;
					color: #64748b;
				}

				.rx-primary-navigation {
					flex: 1;
				}

				.rx-primary-menu,
				.rx-primary-menu ul,
				.rx-mobile-menu,
				.rx-mobile-menu ul {
					list-style: none;
					margin: 0;
					padding: 0;
				}

				.rx-primary-menu {
					display: flex;
					align-items: center;
					justify-content: flex-end;
					gap: 6px;
				}

				.rx-primary-menu li {
					position: relative;
				}

				.rx-primary-menu a {
					display: block;
					padding: 14px 12px;
					color: #0f172a;
					text-decoration: none;
					font-weight: 600;
				}

				.rx-primary-menu a:hover,
				.rx-primary-menu a:focus {
					color: #2563eb;
				}

				.rx-primary-menu ul {
					position: absolute;
					top: 100%;
					left: 0;
					min-width: 220px;
					background: #fff;
					box-shadow: 0 14px 40px rgba(15, 23, 42, 0.14);
					opacity: 0;
					visibility: hidden;
					transform: translateY(10px);
					transition: all 0.2s ease;
					z-index: 9999;
				}

				.rx-primary-menu li:hover > ul,
				.rx-primary-menu li:focus-within > ul {
					opacity: 1;
					visibility: visible;
					transform: translateY(0);
				}

				.rx-primary-menu ul ul {
					top: 0;
					left: 100%;
				}

				.rx-primary-menu ul a {
					padding: 11px 14px;
					font-weight: 500;
					border-bottom: 1px solid rgba(15, 23, 42, 0.06);
				}

				.rx-header-actions {
					display: flex;
					align-items: center;
					gap: 10px;
				}

				.rx-header-search-toggle,
				.rx-mobile-menu-toggle,
				.rx-search-close,
				.rx-mobile-panel-close {
					border: 0;
					background: transparent;
					cursor: pointer;
					color: #0f172a;
				}

				.rx-header-search-toggle {
					width: 42px;
					height: 42px;
					display: inline-flex;
					align-items: center;
					justify-content: center;
					border-radius: 999px;
					background: #f1f5f9;
				}

				.rx-header-cta {
					display: inline-flex;
					align-items: center;
					justify-content: center;
					min-height: 42px;
					padding: 0 18px;
					background: #2563eb;
					color: #fff;
					text-decoration: none;
					font-weight: 700;
					border-radius: 999px;
				}

				.rx-header-cta:hover,
				.rx-header-cta:focus {
					background: #1d4ed8;
					color: #fff;
				}

				.rx-social-links {
					display: flex;
					align-items: center;
					gap: 8px;
				}

				.rx-social-link {
					display: inline-flex;
					align-items: center;
					justify-content: center;
					width: 34px;
					height: 34px;
					border-radius: 999px;
					background: #f1f5f9;
					color: #0f172a;
					text-decoration: none;
				}

				.rx-social-link svg,
				.rx-header-search-toggle svg {
					width: 18px;
					height: 18px;
					fill: currentColor;
				}

				.rx-mobile-menu-toggle {
					display: none;
					width: 44px;
					height: 44px;
					flex-direction: column;
					align-items: center;
					justify-content: center;
					gap: 5px;
					border-radius: 8px;
					background: #f1f5f9;
				}

				.rx-toggle-line {
					display: block;
					width: 22px;
					height: 2px;
					background: currentColor;
				}

				.rx-search-overlay {
					position: fixed;
					inset: 0;
					display: none;
					align-items: center;
					justify-content: center;
					background: rgba(15, 23, 42, 0.86);
					z-index: 99999;
				}

				.rx-search-overlay.is-active {
					display: flex;
				}

				.rx-search-overlay-inner {
					width: min(720px, calc(100% - 32px));
					position: relative;
				}

				.rx-search-close {
					position: absolute;
					right: 0;
					top: -60px;
					color: #fff;
					font-size: 42px;
				}

				.rx-search-form {
					display: flex;
					background: #fff;
					border-radius: 12px;
					overflow: hidden;
				}

				.rx-search-field {
					flex: 1;
					border: 0;
					padding: 20px;
					font-size: 18px;
					outline: none;
				}

				.rx-search-submit {
					border: 0;
					background: #2563eb;
					color: #fff;
					padding: 0 24px;
					font-weight: 700;
					cursor: pointer;
				}

				.rx-mobile-panel {
					position: fixed;
					inset: 0;
					display: none;
					z-index: 99999;
				}

				.rx-mobile-panel.is-active {
					display: block;
				}

				.rx-mobile-panel-overlay {
					position: absolute;
					inset: 0;
					background: rgba(15, 23, 42, 0.65);
				}

				.rx-mobile-panel-content {
					position: absolute;
					top: 0;
					right: 0;
					width: min(380px, 88vw);
					height: 100%;
					background: #fff;
					padding: 22px;
					overflow-y: auto;
					box-shadow: -20px 0 50px rgba(15, 23, 42, 0.18);
				}

				.rx-mobile-panel-header {
					display: flex;
					align-items: center;
					justify-content: space-between;
					gap: 16px;
					margin-bottom: 24px;
				}

				.rx-mobile-panel-close {
					font-size: 36px;
					line-height: 1;
				}

				.rx-mobile-menu a {
					display: block;
					padding: 13px 0;
					border-bottom: 1px solid rgba(15, 23, 42, 0.08);
					color: #0f172a;
					text-decoration: none;
					font-weight: 600;
				}

				.rx-mobile-menu ul {
					padding-left: 16px;
				}

				.rx-mobile-search,
				.rx-mobile-cta,
				.rx-mobile-social {
					margin-top: 22px;
				}

				@media (max-width: 992px) {
					.rx-primary-navigation,
					.rx-header-actions .rx-social-links,
					.rx-header-actions .rx-header-cta {
						display: none;
					}

					.rx-mobile-menu-toggle {
						display: inline-flex;
					}

					.rx-header-inner {
						min-height: 72px;
					}
				}

				@media (max-width: 782px) {
					.admin-bar .rx-sticky-header {
						top: 46px;
					}

					.rx-top-bar-inner {
						flex-direction: column;
						align-items: flex-start;
						padding: 8px 0;
					}
				}

				@media (max-width: 600px) {
					.admin-bar .rx-sticky-header {
						top: 0;
					}

					.rx-site-title {
						font-size: 23px;
					}
				}
			';

			wp_add_inline_style( 'rx-header-builder', $css );
		}

		/**
		 * SVG icons.
		 *
		 * @param string $icon Icon name.
		 * @return void
		 */
		private function icon_svg( $icon ) {
			$icon = sanitize_key( $icon );

			switch ( $icon ) {
				case 'search':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21.71 20.29l-4.39-4.39A8.46 8.46 0 0019 10.5C19 5.81 15.19 2 10.5 2S2 5.81 2 10.5 5.81 19 10.5 19a8.46 8.46 0 005.4-1.68l4.39 4.39a1 1 0 001.42-1.42zM4 10.5C4 6.91 6.91 4 10.5 4S17 6.91 17 10.5 14.09 17 10.5 17 4 14.09 4 10.5z"></path></svg>';
					break;

				case 'facebook':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M13.5 22v-8h2.7l.4-3h-3.1V9.1c0-.9.2-1.5 1.5-1.5h1.7V4.9c-.3 0-1.3-.1-2.4-.1-2.4 0-4.1 1.5-4.1 4.2V11H7.5v3h2.7v8h3.3z"></path></svg>';
					break;

				case 'twitter':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M22 5.9c-.7.3-1.5.6-2.4.7.9-.5 1.5-1.3 1.8-2.3-.8.5-1.7.8-2.6 1A4.1 4.1 0 0015.8 4c-2.3 0-4.1 1.8-4.1 4.1 0 .3 0 .6.1.9A11.7 11.7 0 013.4 4.7a4 4 0 001.3 5.4c-.7 0-1.3-.2-1.9-.5v.1c0 2 1.4 3.6 3.3 4-.3.1-.7.1-1.1.1-.3 0-.5 0-.8-.1.5 1.7 2.1 2.9 3.9 2.9A8.3 8.3 0 012 18.3 11.7 11.7 0 008.3 20c7.5 0 11.6-6.2 11.6-11.6v-.5c.8-.6 1.5-1.3 2.1-2z"></path></svg>';
					break;

				case 'linkedin':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6.9 21H3.6V9h3.3v12zM5.2 7.4A1.9 1.9 0 115.2 3.6a1.9 1.9 0 010 3.8zM21 21h-3.3v-5.8c0-1.4 0-3.2-1.9-3.2s-2.2 1.5-2.2 3.1V21h-3.3V9h3.1v1.6h.1c.4-.8 1.5-1.9 3.1-1.9 3.4 0 4 2.2 4 5.1V21z"></path></svg>';
					break;

				case 'youtube':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21.6 7.2s-.2-1.5-.8-2.1c-.8-.8-1.6-.8-2-.9C16 4 12 4 12 4h0s-4 0-6.8.2c-.4.1-1.3.1-2 .9-.6.6-.8 2.1-.8 2.1S2 9 2 10.8v1.7c0 1.8.2 3.6.2 3.6s.2 1.5.8 2.1c.8.8 1.8.8 2.3.9 1.7.2 6.7.2 6.7.2s4 0 6.8-.2c.4-.1 1.3-.1 2-.9.6-.6.8-2.1.8-2.1s.2-1.8.2-3.6v-1.7c0-1.8-.2-3.6-.2-3.6zM10 14.8V8.6l5.8 3.1L10 14.8z"></path></svg>';
					break;

				case 'instagram':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7.5 2h9A5.5 5.5 0 0122 7.5v9a5.5 5.5 0 01-5.5 5.5h-9A5.5 5.5 0 012 16.5v-9A5.5 5.5 0 017.5 2zm0 2A3.5 3.5 0 004 7.5v9A3.5 3.5 0 007.5 20h9a3.5 3.5 0 003.5-3.5v-9A3.5 3.5 0 0016.5 4h-9zM12 7a5 5 0 110 10 5 5 0 010-10zm0 2a3 3 0 100 6 3 3 0 000-6zm5.3-2.3a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z"></path></svg>';
					break;

				case 'github':
					echo '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2a10 10 0 00-3.2 19.5c.5.1.7-.2.7-.5v-1.8c-2.9.6-3.5-1.2-3.5-1.2-.5-1.1-1.1-1.4-1.1-1.4-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.5 2.3 1.1 2.9.8.1-.6.3-1.1.6-1.3-2.3-.3-4.7-1.2-4.7-5.1 0-1.1.4-2.1 1-2.8-.1-.3-.4-1.3.1-2.8 0 0 .8-.3 2.8 1a9.6 9.6 0 015.1 0c1.9-1.3 2.8-1 2.8-1 .5 1.5.2 2.5.1 2.8.6.7 1 1.6 1 2.8 0 4-2.4 4.9-4.7 5.1.4.3.7 1 .7 2V21c0 .3.2.6.7.5A10 10 0 0012 2z"></path></svg>';
					break;

				default:
					echo '<span aria-hidden="true">' . esc_html( strtoupper( substr( $icon, 0, 1 ) ) ) . '</span>';
					break;
			}
		}
	}

endif;

/**
 * Initialize RX Header Builder.
 *
 * @return RX_Header_Builder
 */
function rx_header_builder() {
	return RX_Header_Builder::instance();
}

rx_header_builder();

/**
 * Template function to render header.
 *
 * Use inside header.php:
 *
 * <?php rx_render_header(); ?>
 *
 * @return void
 */
function rx_render_header() {
	do_action( 'rx_theme_header' );
}

/**
 * Template function to render mobile header.
 *
 * @return void
 */
function rx_render_mobile_header() {
	do_action( 'rx_theme_mobile_header' );
}

Use it inside header.php

In your theme header.php, use:

<?php
/**
 * Theme Header
 *
 * @package RX_Theme
 */
?>
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

<?php
if ( function_exists( 'rx_render_header' ) ) {
	rx_render_header();
}
?>

<main id="content" class="site-content">

Optional JS file

Create:

assets/js/header-builder.js

Add this:

(function () {
	'use strict';

	const body = document.body;

	function toggleAttribute(element, attribute, trueValue, falseValue) {
		if (!element) return;

		const current = element.getAttribute(attribute);
		element.setAttribute(attribute, current === trueValue ? falseValue : trueValue);
	}

	function initMobileMenu() {
		const toggle = document.querySelector('.rx-mobile-menu-toggle');
		const panel = document.querySelector('#rx-mobile-panel');
		const close = document.querySelector('.rx-mobile-panel-close');
		const overlay = document.querySelector('.rx-mobile-panel-overlay');

		if (!toggle || !panel) return;

		function openMenu() {
			panel.classList.add('is-active');
			panel.setAttribute('aria-hidden', 'false');
			toggle.setAttribute('aria-expanded', 'true');
			body.classList.add('rx-mobile-menu-open');
		}

		function closeMenu() {
			panel.classList.remove('is-active');
			panel.setAttribute('aria-hidden', 'true');
			toggle.setAttribute('aria-expanded', 'false');
			body.classList.remove('rx-mobile-menu-open');
		}

		toggle.addEventListener('click', openMenu);

		if (close) {
			close.addEventListener('click', closeMenu);
		}

		if (overlay) {
			overlay.addEventListener('click', closeMenu);
		}

		document.addEventListener('keydown', function (event) {
			if (event.key === 'Escape') {
				closeMenu();
			}
		});
	}

	function initSearchOverlay() {
		const toggle = document.querySelector('.rx-header-search-toggle');
		const overlay = document.querySelector('#rx-search-overlay');
		const close = document.querySelector('.rx-search-close');
		const field = document.querySelector('#rx-search-field');

		if (!toggle || !overlay) return;

		function openSearch() {
			overlay.classList.add('is-active');
			overlay.setAttribute('aria-hidden', 'false');
			toggle.setAttribute('aria-expanded', 'true');

			setTimeout(function () {
				if (field) {
					field.focus();
				}
			}, 120);
		}

		function closeSearch() {
			overlay.classList.remove('is-active');
			overlay.setAttribute('aria-hidden', 'true');
			toggle.setAttribute('aria-expanded', 'false');
		}

		toggle.addEventListener('click', openSearch);

		if (close) {
			close.addEventListener('click', closeSearch);
		}

		overlay.addEventListener('click', function (event) {
			if (event.target === overlay) {
				closeSearch();
			}
		});

		document.addEventListener('keydown', function (event) {
			if (event.key === 'Escape') {
				closeSearch();
			}
		});
	}

	function initStickyShadow() {
		const header = document.querySelector('.rx-sticky-header');

		if (!header) return;

		function checkScroll() {
			if (window.scrollY > 20) {
				header.classList.add('rx-header-scrolled');
			} else {
				header.classList.remove('rx-header-scrolled');
			}
		}

		checkScroll();

		window.addEventListener('scroll', checkScroll, {
			passive: true
		});
	}

	document.addEventListener('DOMContentLoaded', function () {
		initMobileMenu();
		initSearchOverlay();
		initStickyShadow();
	});
})();

Optional extra CSS for sticky shadow

You can add this to style.css:

.rx-header-scrolled {
	box-shadow: 0 10px 35px rgba(15, 23, 42, 0.12);
}

.rx-mobile-menu-open {
	overflow: hidden;
}

How to customize header settings from functions.php

Example:

add_filter( 'rx_header_builder_settings', function( $settings ) {

	$settings['enable_top_bar']       = true;
	$settings['enable_sticky_header'] = true;
	$settings['enable_search']        = true;
	$settings['enable_cta']           = true;

	$settings['top_bar_left_text'] = 'Welcome to RX Harun Medical Knowledge Platform';

	$settings['cta_text'] = 'Contact Doctor';
	$settings['cta_url']  = home_url( '/contact/' );

	$settings['social_links']['facebook']  = 'https://facebook.com/';
	$settings['social_links']['linkedin']  = 'https://linkedin.com/';
	$settings['social_links']['youtube']   = 'https://youtube.com/';

	return $settings;

} );

This gives your RX Theme a powerful, expandable header builder system.

Leave a Reply

Your email address will not be published. Required fields are marked *