I’ll build this as a powerful footer-builder.php module for your RX theme: hooks, widget areas, footer columns, copyright, menus, social links, back-to-top, schema, customizer settings, sanitization, and frontend output in one place.
My dear friend, below is an advanced inc/builders/footer-builder.php file for your RX WordPress theme. It includes many footer functions: footer columns, widgets, menus, copyright, social icons, back-to-top button, footer CTA, contact info, schema markup, Customizer settings, sanitization, accessibility, hooks, and performance-friendly output.
Create this file:
rx-theme/inc/builders/footer-builder.php
Then include it in your functions.php:
require_once get_template_directory() . '/inc/builders/footer-builder.php';
inc/builders/footer-builder.php
<?php
/**
* RX Theme Footer Builder
*
* Advanced footer builder for RX Theme.
*
* Features:
* - Footer widget areas
* - Footer menu locations
* - Dynamic footer columns
* - Copyright text
* - Social links
* - Back to top button
* - Footer CTA
* - Contact info section
* - Schema.org organization markup
* - Accessibility friendly footer
* - Customizer controls
* - Safe sanitization
*
* @package RX_Theme
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'RX_Footer_Builder' ) ) :
final class RX_Footer_Builder {
/**
* Instance.
*
* @var RX_Footer_Builder|null
*/
private static $instance = null;
/**
* Get instance.
*
* @return RX_Footer_Builder
*/
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
private function __construct() {
add_action( 'after_setup_theme', array( $this, 'register_footer_menus' ) );
add_action( 'widgets_init', array( $this, 'register_footer_widgets' ) );
add_action( 'customize_register', array( $this, 'register_customizer_options' ) );
add_action( 'wp_footer', array( $this, 'render_back_to_top' ), 20 );
add_action( 'wp_footer', array( $this, 'render_footer_schema' ), 30 );
add_action( 'rx_theme_footer', array( $this, 'render_footer' ) );
add_filter( 'body_class', array( $this, 'footer_body_classes' ) );
}
/**
* Default option values.
*
* @return array
*/
public static function defaults() {
return array(
'rx_footer_enable' => true,
'rx_footer_layout' => 'layout-1',
'rx_footer_width' => 'contained',
'rx_footer_columns' => 4,
'rx_footer_show_widgets' => true,
'rx_footer_show_menu' => true,
'rx_footer_show_social' => true,
'rx_footer_show_contact' => true,
'rx_footer_show_cta' => false,
'rx_footer_show_bottom_bar' => true,
'rx_footer_show_back_to_top' => true,
'rx_footer_bg_color' => '#101827',
'rx_footer_text_color' => '#e5e7eb',
'rx_footer_link_color' => '#ffffff',
'rx_footer_link_hover_color' => '#38bdf8',
'rx_footer_border_color' => '#1f2937',
'rx_footer_cta_title' => 'Ready to improve your health knowledge?',
'rx_footer_cta_text' => 'Explore trusted, simple, and evidence-based health articles.',
'rx_footer_cta_button_text' => 'Explore Articles',
'rx_footer_cta_button_url' => home_url( '/' ),
'rx_footer_contact_title' => 'Contact',
'rx_footer_contact_address' => '',
'rx_footer_contact_phone' => '',
'rx_footer_contact_email' => get_option( 'admin_email' ),
'rx_footer_facebook' => '',
'rx_footer_twitter' => '',
'rx_footer_linkedin' => '',
'rx_footer_youtube' => '',
'rx_footer_instagram' => '',
'rx_footer_pinterest' => '',
'rx_footer_github' => '',
'rx_footer_whatsapp' => '',
'rx_footer_telegram' => '',
'rx_footer_copyright' => '© {year} {site_name}. All rights reserved.',
'rx_footer_credit_enable' => true,
'rx_footer_credit_text' => 'Built with RX Theme',
'rx_footer_schema_enable' => true,
'rx_footer_org_name' => get_bloginfo( 'name' ),
'rx_footer_org_logo' => '',
'rx_footer_org_url' => home_url( '/' ),
);
}
/**
* Get option with default fallback.
*
* @param string $key Option key.
* @return mixed
*/
public static function get_option( $key ) {
$defaults = self::defaults();
$default = isset( $defaults[ $key ] ) ? $defaults[ $key ] : '';
return get_theme_mod( $key, $default );
}
/**
* Register footer menus.
*
* @return void
*/
public function register_footer_menus() {
register_nav_menus(
array(
'rx_footer_menu' => esc_html__( 'RX Footer Menu', 'rx-theme' ),
'rx_footer_bottom_menu' => esc_html__( 'RX Footer Bottom Menu', 'rx-theme' ),
'rx_footer_legal_menu' => esc_html__( 'RX Footer Legal Menu', 'rx-theme' ),
)
);
}
/**
* Register footer widget areas.
*
* @return void
*/
public function register_footer_widgets() {
$columns = 6;
for ( $i = 1; $i <= $columns; $i++ ) {
register_sidebar(
array(
'name' => sprintf( esc_html__( 'RX Footer Column %d', 'rx-theme' ), $i ),
'id' => 'rx-footer-' . $i,
'description' => sprintf( esc_html__( 'Add widgets for footer column %d.', 'rx-theme' ), $i ),
'before_widget' => '<section id="%1$s" class="rx-footer-widget widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="rx-footer-widget-title">',
'after_title' => '</h2>',
)
);
}
}
/**
* Add body classes.
*
* @param array $classes Body classes.
* @return array
*/
public function footer_body_classes( $classes ) {
$layout = sanitize_html_class( self::get_option( 'rx_footer_layout' ) );
$width = sanitize_html_class( self::get_option( 'rx_footer_width' ) );
$columns = absint( self::get_option( 'rx_footer_columns' ) );
$classes[] = 'rx-footer-' . $layout;
$classes[] = 'rx-footer-width-' . $width;
$classes[] = 'rx-footer-columns-' . $columns;
return $classes;
}
/**
* Register customizer options.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
public function register_customizer_options( $wp_customize ) {
$wp_customize->add_panel(
'rx_footer_panel',
array(
'title' => esc_html__( 'RX Footer Builder', 'rx-theme' ),
'description' => esc_html__( 'Advanced footer builder options for RX Theme.', 'rx-theme' ),
'priority' => 160,
)
);
$this->customizer_general_section( $wp_customize );
$this->customizer_style_section( $wp_customize );
$this->customizer_cta_section( $wp_customize );
$this->customizer_contact_section( $wp_customize );
$this->customizer_social_section( $wp_customize );
$this->customizer_bottom_section( $wp_customize );
$this->customizer_schema_section( $wp_customize );
}
/**
* General customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_general_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_general_section',
array(
'title' => esc_html__( 'Footer General', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$this->add_checkbox_control(
$wp_customize,
'rx_footer_enable',
esc_html__( 'Enable Footer', 'rx-theme' ),
'rx_footer_general_section'
);
$this->add_select_control(
$wp_customize,
'rx_footer_layout',
esc_html__( 'Footer Layout', 'rx-theme' ),
'rx_footer_general_section',
array(
'layout-1' => esc_html__( 'Layout 1 - Classic', 'rx-theme' ),
'layout-2' => esc_html__( 'Layout 2 - Centered', 'rx-theme' ),
'layout-3' => esc_html__( 'Layout 3 - Minimal', 'rx-theme' ),
'layout-4' => esc_html__( 'Layout 4 - CTA First', 'rx-theme' ),
)
);
$this->add_select_control(
$wp_customize,
'rx_footer_width',
esc_html__( 'Footer Width', 'rx-theme' ),
'rx_footer_general_section',
array(
'contained' => esc_html__( 'Contained', 'rx-theme' ),
'full' => esc_html__( 'Full Width', 'rx-theme' ),
)
);
$this->add_select_control(
$wp_customize,
'rx_footer_columns',
esc_html__( 'Footer Columns', 'rx-theme' ),
'rx_footer_general_section',
array(
1 => esc_html__( '1 Column', 'rx-theme' ),
2 => esc_html__( '2 Columns', 'rx-theme' ),
3 => esc_html__( '3 Columns', 'rx-theme' ),
4 => esc_html__( '4 Columns', 'rx-theme' ),
5 => esc_html__( '5 Columns', 'rx-theme' ),
6 => esc_html__( '6 Columns', 'rx-theme' ),
)
);
$checks = array(
'rx_footer_show_widgets' => esc_html__( 'Show Footer Widgets', 'rx-theme' ),
'rx_footer_show_menu' => esc_html__( 'Show Footer Menu', 'rx-theme' ),
'rx_footer_show_social' => esc_html__( 'Show Social Links', 'rx-theme' ),
'rx_footer_show_contact' => esc_html__( 'Show Contact Info', 'rx-theme' ),
'rx_footer_show_cta' => esc_html__( 'Show Footer CTA', 'rx-theme' ),
'rx_footer_show_bottom_bar' => esc_html__( 'Show Bottom Bar', 'rx-theme' ),
'rx_footer_show_back_to_top' => esc_html__( 'Show Back To Top Button', 'rx-theme' ),
);
foreach ( $checks as $key => $label ) {
$this->add_checkbox_control( $wp_customize, $key, $label, 'rx_footer_general_section' );
}
}
/**
* Style customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_style_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_style_section',
array(
'title' => esc_html__( 'Footer Style', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$colors = array(
'rx_footer_bg_color' => esc_html__( 'Background Color', 'rx-theme' ),
'rx_footer_text_color' => esc_html__( 'Text Color', 'rx-theme' ),
'rx_footer_link_color' => esc_html__( 'Link Color', 'rx-theme' ),
'rx_footer_link_hover_color' => esc_html__( 'Link Hover Color', 'rx-theme' ),
'rx_footer_border_color' => esc_html__( 'Border Color', 'rx-theme' ),
);
foreach ( $colors as $key => $label ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => 'sanitize_hex_color',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$key,
array(
'label' => $label,
'section' => 'rx_footer_style_section',
)
)
);
}
}
/**
* CTA customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_cta_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_cta_section',
array(
'title' => esc_html__( 'Footer CTA', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$this->add_text_control( $wp_customize, 'rx_footer_cta_title', esc_html__( 'CTA Title', 'rx-theme' ), 'rx_footer_cta_section' );
$this->add_textarea_control( $wp_customize, 'rx_footer_cta_text', esc_html__( 'CTA Text', 'rx-theme' ), 'rx_footer_cta_section' );
$this->add_text_control( $wp_customize, 'rx_footer_cta_button_text', esc_html__( 'CTA Button Text', 'rx-theme' ), 'rx_footer_cta_section' );
$this->add_url_control( $wp_customize, 'rx_footer_cta_button_url', esc_html__( 'CTA Button URL', 'rx-theme' ), 'rx_footer_cta_section' );
}
/**
* Contact customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_contact_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_contact_section',
array(
'title' => esc_html__( 'Footer Contact', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$this->add_text_control( $wp_customize, 'rx_footer_contact_title', esc_html__( 'Contact Title', 'rx-theme' ), 'rx_footer_contact_section' );
$this->add_textarea_control( $wp_customize, 'rx_footer_contact_address', esc_html__( 'Address', 'rx-theme' ), 'rx_footer_contact_section' );
$this->add_text_control( $wp_customize, 'rx_footer_contact_phone', esc_html__( 'Phone', 'rx-theme' ), 'rx_footer_contact_section' );
$this->add_email_control( $wp_customize, 'rx_footer_contact_email', esc_html__( 'Email', 'rx-theme' ), 'rx_footer_contact_section' );
}
/**
* Social customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_social_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_social_section',
array(
'title' => esc_html__( 'Footer Social Links', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$socials = $this->social_platforms();
foreach ( $socials as $key => $data ) {
$this->add_url_control(
$wp_customize,
$key,
$data['label'],
'rx_footer_social_section'
);
}
}
/**
* Bottom bar customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_bottom_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_bottom_section',
array(
'title' => esc_html__( 'Footer Bottom Bar', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$this->add_textarea_control( $wp_customize, 'rx_footer_copyright', esc_html__( 'Copyright Text', 'rx-theme' ), 'rx_footer_bottom_section' );
$this->add_checkbox_control( $wp_customize, 'rx_footer_credit_enable', esc_html__( 'Show Theme Credit', 'rx-theme' ), 'rx_footer_bottom_section' );
$this->add_text_control( $wp_customize, 'rx_footer_credit_text', esc_html__( 'Credit Text', 'rx-theme' ), 'rx_footer_bottom_section' );
}
/**
* Schema customizer section.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
private function customizer_schema_section( $wp_customize ) {
$wp_customize->add_section(
'rx_footer_schema_section',
array(
'title' => esc_html__( 'Footer Schema', 'rx-theme' ),
'panel' => 'rx_footer_panel',
)
);
$this->add_checkbox_control( $wp_customize, 'rx_footer_schema_enable', esc_html__( 'Enable Organization Schema', 'rx-theme' ), 'rx_footer_schema_section' );
$this->add_text_control( $wp_customize, 'rx_footer_org_name', esc_html__( 'Organization Name', 'rx-theme' ), 'rx_footer_schema_section' );
$this->add_url_control( $wp_customize, 'rx_footer_org_logo', esc_html__( 'Organization Logo URL', 'rx-theme' ), 'rx_footer_schema_section' );
$this->add_url_control( $wp_customize, 'rx_footer_org_url', esc_html__( 'Organization URL', 'rx-theme' ), 'rx_footer_schema_section' );
}
/**
* Add checkbox control.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $key Key.
* @param string $label Label.
* @param string $section Section.
* @return void
*/
private function add_checkbox_control( $wp_customize, $key, $label, $section ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
'transport' => 'refresh',
)
);
$wp_customize->add_control(
$key,
array(
'type' => 'checkbox',
'label' => $label,
'section' => $section,
)
);
}
/**
* Add select control.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $key Key.
* @param string $label Label.
* @param string $section Section.
* @param array $choices Choices.
* @return void
*/
private function add_select_control( $wp_customize, $key, $label, $section, $choices ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => array( $this, 'sanitize_select' ),
'transport' => 'refresh',
)
);
$wp_customize->add_control(
$key,
array(
'type' => 'select',
'label' => $label,
'section' => $section,
'choices' => $choices,
)
);
}
/**
* Add text control.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $key Key.
* @param string $label Label.
* @param string $section Section.
* @return void
*/
private function add_text_control( $wp_customize, $key, $label, $section ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => 'sanitize_text_field',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
$key,
array(
'type' => 'text',
'label' => $label,
'section' => $section,
)
);
}
/**
* Add textarea control.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $key Key.
* @param string $label Label.
* @param string $section Section.
* @return void
*/
private function add_textarea_control( $wp_customize, $key, $label, $section ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => 'wp_kses_post',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
$key,
array(
'type' => 'textarea',
'label' => $label,
'section' => $section,
)
);
}
/**
* Add URL control.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $key Key.
* @param string $label Label.
* @param string $section Section.
* @return void
*/
private function add_url_control( $wp_customize, $key, $label, $section ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => 'esc_url_raw',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
$key,
array(
'type' => 'url',
'label' => $label,
'section' => $section,
)
);
}
/**
* Add email control.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $key Key.
* @param string $label Label.
* @param string $section Section.
* @return void
*/
private function add_email_control( $wp_customize, $key, $label, $section ) {
$wp_customize->add_setting(
$key,
array(
'default' => self::defaults()[ $key ],
'sanitize_callback' => 'sanitize_email',
'transport' => 'refresh',
)
);
$wp_customize->add_control(
$key,
array(
'type' => 'email',
'label' => $label,
'section' => $section,
)
);
}
/**
* Sanitize checkbox.
*
* @param mixed $checked Value.
* @return bool
*/
public function sanitize_checkbox( $checked ) {
return ( isset( $checked ) && true === (bool) $checked );
}
/**
* Sanitize select.
*
* @param mixed $input Input.
* @param mixed $setting Setting.
* @return mixed
*/
public function sanitize_select( $input, $setting ) {
$control = $setting->manager->get_control( $setting->id );
if ( ! $control ) {
return $setting->default;
}
$choices = $control->choices;
return array_key_exists( $input, $choices ) ? $input : $setting->default;
}
/**
* Social platforms.
*
* @return array
*/
private function social_platforms() {
return array(
'rx_footer_facebook' => array(
'label' => esc_html__( 'Facebook URL', 'rx-theme' ),
'name' => 'Facebook',
),
'rx_footer_twitter' => array(
'label' => esc_html__( 'X / Twitter URL', 'rx-theme' ),
'name' => 'X',
),
'rx_footer_linkedin' => array(
'label' => esc_html__( 'LinkedIn URL', 'rx-theme' ),
'name' => 'LinkedIn',
),
'rx_footer_youtube' => array(
'label' => esc_html__( 'YouTube URL', 'rx-theme' ),
'name' => 'YouTube',
),
'rx_footer_instagram' => array(
'label' => esc_html__( 'Instagram URL', 'rx-theme' ),
'name' => 'Instagram',
),
'rx_footer_pinterest' => array(
'label' => esc_html__( 'Pinterest URL', 'rx-theme' ),
'name' => 'Pinterest',
),
'rx_footer_github' => array(
'label' => esc_html__( 'GitHub URL', 'rx-theme' ),
'name' => 'GitHub',
),
'rx_footer_whatsapp' => array(
'label' => esc_html__( 'WhatsApp URL', 'rx-theme' ),
'name' => 'WhatsApp',
),
'rx_footer_telegram' => array(
'label' => esc_html__( 'Telegram URL', 'rx-theme' ),
'name' => 'Telegram',
),
);
}
/**
* Render footer.
*
* Use this hook in footer.php:
* do_action( 'rx_theme_footer' );
*
* @return void
*/
public function render_footer() {
if ( ! self::get_option( 'rx_footer_enable' ) ) {
return;
}
$layout = sanitize_html_class( self::get_option( 'rx_footer_layout' ) );
$width = sanitize_html_class( self::get_option( 'rx_footer_width' ) );
$columns = absint( self::get_option( 'rx_footer_columns' ) );
if ( $columns < 1 || $columns > 6 ) {
$columns = 4;
}
$style = $this->footer_inline_style();
?>
<footer id="colophon"
class="rx-site-footer rx-footer-builder rx-footer-<?php echo esc_attr( $layout ); ?> rx-footer-width-<?php echo esc_attr( $width ); ?> rx-footer-cols-<?php echo esc_attr( $columns ); ?>"
role="contentinfo"
<?php echo $style; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
>
<?php do_action( 'rx_before_footer_inner' ); ?>
<div class="<?php echo esc_attr( $this->container_class() ); ?>">
<?php
if ( self::get_option( 'rx_footer_show_cta' ) ) {
$this->render_cta();
}
if ( self::get_option( 'rx_footer_show_widgets' ) ) {
$this->render_widget_columns( $columns );
}
if ( self::get_option( 'rx_footer_show_contact' ) || self::get_option( 'rx_footer_show_social' ) || self::get_option( 'rx_footer_show_menu' ) ) {
$this->render_middle_area();
}
if ( self::get_option( 'rx_footer_show_bottom_bar' ) ) {
$this->render_bottom_bar();
}
?>
</div>
<?php do_action( 'rx_after_footer_inner' ); ?>
</footer>
<?php
}
/**
* Container class.
*
* @return string
*/
private function container_class() {
$width = self::get_option( 'rx_footer_width' );
if ( 'full' === $width ) {
return 'rx-footer-container rx-footer-container-full';
}
return 'rx-footer-container rx-footer-container-contained';
}
/**
* Footer inline style.
*
* @return string
*/
private function footer_inline_style() {
$bg = sanitize_hex_color( self::get_option( 'rx_footer_bg_color' ) );
$text = sanitize_hex_color( self::get_option( 'rx_footer_text_color' ) );
$link = sanitize_hex_color( self::get_option( 'rx_footer_link_color' ) );
$hover = sanitize_hex_color( self::get_option( 'rx_footer_link_hover_color' ) );
$border = sanitize_hex_color( self::get_option( 'rx_footer_border_color' ) );
$style = sprintf(
'--rx-footer-bg:%1$s;--rx-footer-text:%2$s;--rx-footer-link:%3$s;--rx-footer-link-hover:%4$s;--rx-footer-border:%5$s;',
esc_attr( $bg ),
esc_attr( $text ),
esc_attr( $link ),
esc_attr( $hover ),
esc_attr( $border )
);
return 'style="' . esc_attr( $style ) . '"';
}
/**
* Render CTA.
*
* @return void
*/
private function render_cta() {
$title = self::get_option( 'rx_footer_cta_title' );
$text = self::get_option( 'rx_footer_cta_text' );
$button_text = self::get_option( 'rx_footer_cta_button_text' );
$button_url = self::get_option( 'rx_footer_cta_button_url' );
if ( empty( $title ) && empty( $text ) && empty( $button_text ) ) {
return;
}
?>
<section class="rx-footer-cta" aria-label="<?php esc_attr_e( 'Footer call to action', 'rx-theme' ); ?>">
<div class="rx-footer-cta-content">
<?php if ( ! empty( $title ) ) : ?>
<h2 class="rx-footer-cta-title"><?php echo esc_html( $title ); ?></h2>
<?php endif; ?>
<?php if ( ! empty( $text ) ) : ?>
<div class="rx-footer-cta-text"><?php echo wp_kses_post( wpautop( $text ) ); ?></div>
<?php endif; ?>
</div>
<?php if ( ! empty( $button_text ) && ! empty( $button_url ) ) : ?>
<div class="rx-footer-cta-action">
<a class="rx-footer-cta-button" href="<?php echo esc_url( $button_url ); ?>">
<?php echo esc_html( $button_text ); ?>
</a>
</div>
<?php endif; ?>
</section>
<?php
}
/**
* Render widget columns.
*
* @param int $columns Columns.
* @return void
*/
private function render_widget_columns( $columns ) {
$has_widgets = false;
for ( $i = 1; $i <= $columns; $i++ ) {
if ( is_active_sidebar( 'rx-footer-' . $i ) ) {
$has_widgets = true;
break;
}
}
if ( ! $has_widgets ) {
return;
}
?>
<div class="rx-footer-widgets rx-footer-widget-grid rx-footer-widget-grid-<?php echo esc_attr( $columns ); ?>">
<?php for ( $i = 1; $i <= $columns; $i++ ) : ?>
<?php if ( is_active_sidebar( 'rx-footer-' . $i ) ) : ?>
<div class="rx-footer-column rx-footer-column-<?php echo esc_attr( $i ); ?>">
<?php dynamic_sidebar( 'rx-footer-' . $i ); ?>
</div>
<?php endif; ?>
<?php endfor; ?>
</div>
<?php
}
/**
* Render middle area.
*
* @return void
*/
private function render_middle_area() {
?>
<div class="rx-footer-middle">
<?php
if ( self::get_option( 'rx_footer_show_contact' ) ) {
$this->render_contact_info();
}
if ( self::get_option( 'rx_footer_show_menu' ) ) {
$this->render_footer_menu();
}
if ( self::get_option( 'rx_footer_show_social' ) ) {
$this->render_social_links();
}
?>
</div>
<?php
}
/**
* Render contact info.
*
* @return void
*/
private function render_contact_info() {
$title = self::get_option( 'rx_footer_contact_title' );
$address = self::get_option( 'rx_footer_contact_address' );
$phone = self::get_option( 'rx_footer_contact_phone' );
$email = self::get_option( 'rx_footer_contact_email' );
if ( empty( $address ) && empty( $phone ) && empty( $email ) ) {
return;
}
?>
<section class="rx-footer-contact" aria-label="<?php esc_attr_e( 'Footer contact information', 'rx-theme' ); ?>">
<?php if ( ! empty( $title ) ) : ?>
<h2 class="rx-footer-section-title"><?php echo esc_html( $title ); ?></h2>
<?php endif; ?>
<ul class="rx-footer-contact-list">
<?php if ( ! empty( $address ) ) : ?>
<li class="rx-footer-contact-item rx-footer-contact-address">
<span class="rx-footer-contact-icon" aria-hidden="true">📍</span>
<span><?php echo wp_kses_post( nl2br( $address ) ); ?></span>
</li>
<?php endif; ?>
<?php if ( ! empty( $phone ) ) : ?>
<li class="rx-footer-contact-item rx-footer-contact-phone">
<span class="rx-footer-contact-icon" aria-hidden="true">☎</span>
<a href="tel:<?php echo esc_attr( preg_replace( '/[^0-9+]/', '', $phone ) ); ?>">
<?php echo esc_html( $phone ); ?>
</a>
</li>
<?php endif; ?>
<?php if ( ! empty( $email ) && is_email( $email ) ) : ?>
<li class="rx-footer-contact-item rx-footer-contact-email">
<span class="rx-footer-contact-icon" aria-hidden="true">✉</span>
<a href="mailto:<?php echo esc_attr( antispambot( $email ) ); ?>">
<?php echo esc_html( antispambot( $email ) ); ?>
</a>
</li>
<?php endif; ?>
</ul>
</section>
<?php
}
/**
* Render footer menu.
*
* @return void
*/
private function render_footer_menu() {
if ( ! has_nav_menu( 'rx_footer_menu' ) ) {
return;
}
?>
<nav class="rx-footer-navigation" aria-label="<?php esc_attr_e( 'Footer Menu', 'rx-theme' ); ?>">
<?php
wp_nav_menu(
array(
'theme_location' => 'rx_footer_menu',
'menu_class' => 'rx-footer-menu',
'container' => false,
'depth' => 2,
'fallback_cb' => false,
)
);
?>
</nav>
<?php
}
/**
* Render social links.
*
* @return void
*/
private function render_social_links() {
$socials = $this->social_platforms();
$items = array();
foreach ( $socials as $key => $data ) {
$url = self::get_option( $key );
if ( ! empty( $url ) ) {
$items[] = array(
'name' => $data['name'],
'url' => esc_url( $url ),
);
}
}
if ( empty( $items ) ) {
return;
}
?>
<nav class="rx-footer-social" aria-label="<?php esc_attr_e( 'Social links', 'rx-theme' ); ?>">
<ul class="rx-footer-social-list">
<?php foreach ( $items as $item ) : ?>
<li class="rx-footer-social-item">
<a class="rx-footer-social-link"
href="<?php echo esc_url( $item['url'] ); ?>"
target="_blank"
rel="noopener noreferrer"
aria-label="<?php echo esc_attr( $item['name'] ); ?>">
<span aria-hidden="true"><?php echo esc_html( $this->social_icon_text( $item['name'] ) ); ?></span>
<span class="screen-reader-text"><?php echo esc_html( $item['name'] ); ?></span>
</a>
</li>
<?php endforeach; ?>
</ul>
</nav>
<?php
}
/**
* Simple text/icon for social platform.
*
* @param string $name Platform.
* @return string
*/
private function social_icon_text( $name ) {
$icons = array(
'Facebook' => 'f',
'X' => '𝕏',
'LinkedIn' => 'in',
'YouTube' => '▶',
'Instagram' => '◎',
'Pinterest' => 'P',
'GitHub' => 'GH',
'WhatsApp' => 'WA',
'Telegram' => 'TG',
);
return isset( $icons[ $name ] ) ? $icons[ $name ] : $name;
}
/**
* Render bottom bar.
*
* @return void
*/
private function render_bottom_bar() {
?>
<div class="rx-footer-bottom">
<div class="rx-footer-bottom-left">
<?php $this->render_copyright(); ?>
</div>
<div class="rx-footer-bottom-right">
<?php $this->render_bottom_menu(); ?>
<?php $this->render_credit(); ?>
</div>
</div>
<?php
}
/**
* Render copyright.
*
* @return void
*/
private function render_copyright() {
$text = self::get_option( 'rx_footer_copyright' );
if ( empty( $text ) ) {
return;
}
$replace = array(
'{year}' => date_i18n( 'Y' ),
'{site_name}' => get_bloginfo( 'name' ),
'{site_url}' => home_url( '/' ),
);
$text = strtr( $text, $replace );
?>
<div class="rx-footer-copyright">
<?php echo wp_kses_post( $text ); ?>
</div>
<?php
}
/**
* Render bottom menu.
*
* @return void
*/
private function render_bottom_menu() {
if ( has_nav_menu( 'rx_footer_bottom_menu' ) ) {
wp_nav_menu(
array(
'theme_location' => 'rx_footer_bottom_menu',
'menu_class' => 'rx-footer-bottom-menu',
'container' => 'nav',
'container_class'=> 'rx-footer-bottom-navigation',
'depth' => 1,
'fallback_cb' => false,
)
);
}
if ( has_nav_menu( 'rx_footer_legal_menu' ) ) {
wp_nav_menu(
array(
'theme_location' => 'rx_footer_legal_menu',
'menu_class' => 'rx-footer-legal-menu',
'container' => 'nav',
'container_class'=> 'rx-footer-legal-navigation',
'depth' => 1,
'fallback_cb' => false,
)
);
}
}
/**
* Render credit.
*
* @return void
*/
private function render_credit() {
if ( ! self::get_option( 'rx_footer_credit_enable' ) ) {
return;
}
$credit = self::get_option( 'rx_footer_credit_text' );
if ( empty( $credit ) ) {
return;
}
?>
<div class="rx-footer-credit">
<?php echo esc_html( $credit ); ?>
</div>
<?php
}
/**
* Render back to top button.
*
* @return void
*/
public function render_back_to_top() {
if ( ! self::get_option( 'rx_footer_show_back_to_top' ) ) {
return;
}
?>
<button type="button" class="rx-back-to-top" id="rxBackToTop" aria-label="<?php esc_attr_e( 'Back to top', 'rx-theme' ); ?>">
<span aria-hidden="true">↑</span>
</button>
<script>
(function () {
'use strict';
var button = document.getElementById('rxBackToTop');
if (!button) {
return;
}
function toggleButton() {
if (window.scrollY > 350) {
button.classList.add('is-visible');
} else {
button.classList.remove('is-visible');
}
}
button.addEventListener('click', function () {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
window.addEventListener('scroll', toggleButton, { passive: true });
toggleButton();
})();
</script>
<?php
}
/**
* Render schema.
*
* @return void
*/
public function render_footer_schema() {
if ( ! self::get_option( 'rx_footer_schema_enable' ) ) {
return;
}
$name = self::get_option( 'rx_footer_org_name' );
$url = self::get_option( 'rx_footer_org_url' );
$logo = self::get_option( 'rx_footer_org_logo' );
if ( empty( $name ) || empty( $url ) ) {
return;
}
$same_as = array();
$socials = $this->social_platforms();
foreach ( $socials as $key => $data ) {
$social_url = self::get_option( $key );
if ( ! empty( $social_url ) ) {
$same_as[] = esc_url_raw( $social_url );
}
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'Organization',
'name' => wp_strip_all_tags( $name ),
'url' => esc_url_raw( $url ),
);
if ( ! empty( $logo ) ) {
$schema['logo'] = esc_url_raw( $logo );
}
if ( ! empty( $same_as ) ) {
$schema['sameAs'] = $same_as;
}
?>
<script type="application/ld+json">
<?php echo wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT ); ?>
</script>
<?php
}
}
endif;
/**
* Initialize footer builder.
*/
RX_Footer_Builder::instance();
/**
* Helper function for footer output.
*
* You can call this in footer.php:
* rx_theme_footer();
*
* @return void
*/
if ( ! function_exists( 'rx_theme_footer' ) ) {
function rx_theme_footer() {
do_action( 'rx_theme_footer' );
}
}
/**
* Optional footer CSS.
*
* Better: move this CSS into your main theme stylesheet.
*/
add_action(
'wp_head',
function () {
?>
<style id="rx-footer-builder-css">
.rx-site-footer {
background: var(--rx-footer-bg);
color: var(--rx-footer-text);
border-top: 1px solid var(--rx-footer-border);
font-size: 16px;
line-height: 1.7;
}
.rx-site-footer a {
color: var(--rx-footer-link);
text-decoration: none;
}
.rx-site-footer a:hover,
.rx-site-footer a:focus {
color: var(--rx-footer-link-hover);
text-decoration: underline;
}
.rx-footer-container-contained {
max-width: 1200px;
margin: 0 auto;
padding: 48px 20px 24px;
}
.rx-footer-container-full {
width: 100%;
padding: 48px 32px 24px;
}
.rx-footer-cta {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 28px;
margin-bottom: 40px;
border: 1px solid var(--rx-footer-border);
border-radius: 18px;
background: rgba(255,255,255,0.04);
}
.rx-footer-cta-title {
margin: 0 0 8px;
font-size: 28px;
line-height: 1.25;
}
.rx-footer-cta-text p {
margin: 0;
}
.rx-footer-cta-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 22px;
border-radius: 999px;
background: var(--rx-footer-link-hover);
color: #ffffff !important;
font-weight: 700;
text-decoration: none !important;
white-space: nowrap;
}
.rx-footer-widget-grid {
display: grid;
gap: 32px;
margin-bottom: 40px;
}
.rx-footer-widget-grid-1 {
grid-template-columns: 1fr;
}
.rx-footer-widget-grid-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.rx-footer-widget-grid-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.rx-footer-widget-grid-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.rx-footer-widget-grid-5 {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.rx-footer-widget-grid-6 {
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.rx-footer-widget-title,
.rx-footer-section-title {
margin: 0 0 16px;
font-size: 18px;
line-height: 1.3;
color: var(--rx-footer-link);
}
.rx-footer-widget ul,
.rx-footer-menu,
.rx-footer-bottom-menu,
.rx-footer-legal-menu,
.rx-footer-contact-list,
.rx-footer-social-list {
margin: 0;
padding: 0;
list-style: none;
}
.rx-footer-widget li,
.rx-footer-menu li,
.rx-footer-bottom-menu li,
.rx-footer-legal-menu li {
margin-bottom: 8px;
}
.rx-footer-middle {
display: grid;
grid-template-columns: 1.2fr 1fr 1fr;
gap: 32px;
padding: 32px 0;
border-top: 1px solid var(--rx-footer-border);
}
.rx-footer-contact-item {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
.rx-footer-contact-icon {
flex: 0 0 auto;
}
.rx-footer-social-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.rx-footer-social-link {
display: inline-flex;
width: 40px;
height: 40px;
align-items: center;
justify-content: center;
border-radius: 999px;
border: 1px solid var(--rx-footer-border);
background: rgba(255,255,255,0.04);
font-weight: 700;
text-decoration: none !important;
}
.rx-footer-bottom {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
padding-top: 24px;
border-top: 1px solid var(--rx-footer-border);
font-size: 14px;
}
.rx-footer-bottom-right {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 16px;
}
.rx-footer-bottom-menu,
.rx-footer-legal-menu {
display: flex;
flex-wrap: wrap;
gap: 14px;
}
.rx-footer-bottom-menu li,
.rx-footer-legal-menu li {
margin-bottom: 0;
}
.rx-back-to-top {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 999;
width: 46px;
height: 46px;
border: 0;
border-radius: 999px;
background: #111827;
color: #ffffff;
cursor: pointer;
opacity: 0;
visibility: hidden;
transform: translateY(12px);
transition: opacity .2s ease, transform .2s ease, visibility .2s ease;
box-shadow: 0 10px 24px rgba(0,0,0,.22);
}
.rx-back-to-top.is-visible {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.rx-footer-layout-2 .rx-footer-middle,
.rx-footer-layout-2 .rx-footer-bottom {
text-align: center;
justify-content: center;
}
.rx-footer-layout-2 .rx-footer-social-list,
.rx-footer-layout-2 .rx-footer-bottom-right {
justify-content: center;
}
.rx-footer-layout-3 .rx-footer-widgets,
.rx-footer-layout-3 .rx-footer-middle {
display: none;
}
.screen-reader-text {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
white-space: nowrap;
border: 0;
}
@media (max-width: 1024px) {
.rx-footer-widget-grid-4,
.rx-footer-widget-grid-5,
.rx-footer-widget-grid-6 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.rx-footer-middle {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 700px) {
.rx-footer-container-contained,
.rx-footer-container-full {
padding: 36px 16px 20px;
}
.rx-footer-cta,
.rx-footer-bottom {
flex-direction: column;
align-items: flex-start;
}
.rx-footer-widget-grid,
.rx-footer-widget-grid-2,
.rx-footer-widget-grid-3,
.rx-footer-widget-grid-4,
.rx-footer-widget-grid-5,
.rx-footer-widget-grid-6,
.rx-footer-middle {
grid-template-columns: 1fr;
}
.rx-footer-bottom-right {
justify-content: flex-start;
}
}
</style>
<?php
},
20
);
Update your footer.php
Inside your theme footer.php, add this where the footer should show:
<?php
if ( function_exists( 'rx_theme_footer' ) ) {
rx_theme_footer();
}
?>
<?php wp_footer(); ?>
</body>
</html>
What this file gives your RX theme
This one file adds:
- Footer Customizer panel
- Footer enable/disable option
- Footer layout switcher
- Contained/full-width footer
- 1 to 6 footer widget columns
- Footer widget areas
- Footer menu
- Footer bottom menu
- Footer legal menu
- Contact info section
- Social links section
- Footer CTA section
- Dynamic copyright text
{year}shortcode support{site_name}shortcode support- Back-to-top button
- Organization schema JSON-LD
- Responsive footer CSS
- Safe sanitization
- Accessibility labels
- Hook support with
rx_before_footer_innerandrx_after_footer_inner
After adding it, go to:
WordPress Dashboard → Appearance → Customize → RX Footer Builder
and you will see the footer controls.