Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions components/footer/variation-default.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@
<?php do_action( 'memberlite_before_site_info' ); ?>

<div class="site-info">

<?php get_template_part( 'components/footer/footer', 'site-info' ); ?>

<?php get_template_part( 'components/footer/footer', 'back-to-top' ); ?>

</div><!-- .site-info -->

<?php do_action( 'memberlite_after_site_info' ); ?>
18 changes: 15 additions & 3 deletions footer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,23 @@

<?php
if ( ! memberlite_hide_page_footer() ) {
$footer_variation = sanitize_key( memberlite_get_variation( 'footer' ) );
$footer_class = 'site-footer site-footer-' . $footer_variation;
//New Footer Pattern Method
$footer_post_name = memberlite_get_current_footer_post_name();
$footer_class = 'site-footer';
if ( $footer_post_name && '0' !== $footer_post_name ) {
$footer_class .= ' site-footer-' . sanitize_html_class( $footer_post_name );
} else {
Comment on lines +20 to +24
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$footer_post_name is taken from theme mods/meta and later used for the footer CPT lookup. Sanitize/normalize it once up-front (e.g., sanitize_key()/sanitize_title()) and treat invalid/empty values as “legacy footer”, instead of passing the raw value through.

Copilot uses AI. Check for mistakes.
$footer_class .= ' site-footer-default'; //legacy footer
}
?>
<footer id="colophon" class="<?php echo esc_attr( $footer_class ); ?>" role="contentinfo">
<?php get_template_part( 'components/footer/variation', $footer_variation ); ?>
<?php
if ( ! empty( $footer_post_name ) && '0' !== $footer_post_name ) {
memberlite_render_footer_variation( $footer_post_name );
} else {
get_template_part( 'components/footer/variation', 'default' ); //legacy footer
}
?>
</footer><!-- #colophon -->
<?php
}
Expand Down
51 changes: 51 additions & 0 deletions inc/customizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -409,12 +409,63 @@ public static function set_customizer_header_settings( WP_Customize_Manager $wp_
* @return void
*/
public static function set_customizer_footer_settings( WP_Customize_Manager $wp_customize ) {
// FOOTER: Legacy Footer Heading ========
self::add_memberlite_heading( $wp_customize, 'memberlite_legacy_footer_heading', __( 'Legacy Settings', 'memberlite' ), 'memberlite_footer_options' );

// FOOTER: Footer Widgets ===============
self::add_memberlite_setting_control( $wp_customize, 'memberlite_footerwidgets', __( 'Footer Widget Columns', 'memberlite' ), 'memberlite_footer_options', array(
'sanitize_callback' => 'absint',
'choices' => array( '2' => '2', '3' => '3', '4' => '4', '6' => '6' ),
) );

// FOOTER: Copyright Text ===============
self::add_memberlite_setting_control( $wp_customize, 'copyright_textbox', __( 'Copyright Text', 'memberlite' ), 'memberlite_footer_options', array(
'transport' => 'postMessage',
'sanitize_callback' => array( 'Memberlite_Customize', 'sanitize_text_with_links' ),
'sanitize_js_callback' => array( 'Memberlite_Customize', 'sanitize_js_text_with_links' ),
) );

// FOOTER: Pattern Footer Heading ========
self::add_memberlite_heading( $wp_customize, 'memberlite_pattern_footer_heading', __( 'Variation Settings', 'memberlite' ), 'memberlite_footer_options' );

// FOOTER: Footer CPT ===================
$footer_choices = memberlite_get_footer_variations();

// FOOTER: Variations, Global ===============
self::add_memberlite_setting_control( $wp_customize, 'memberlite_default_footer_slug', __( 'Default Footer', 'memberlite' ), 'memberlite_footer_options', array(
'type' => 'select',
'sanitize_callback' => 'sanitize_key',
'choices' => $footer_choices,
'default' => '0',
'description' => __( 'Choose which footer pattern to display all across the site.', 'memberlite' ),
) );

// FOOTER: Variations, Blog & Archives ===============
self::add_memberlite_setting_control( $wp_customize, 'memberlite_archives_footer_slug', __( 'Blog & Archives Footer', 'memberlite' ), 'memberlite_footer_options', array(
'type' => 'select',
'sanitize_callback' => 'sanitize_key',
'choices' => $footer_choices,
'default' => '0',
'description' => __( 'Choose which footer pattern to display on your blog and post archives.', 'memberlite' ),
) );

// FOOTER: Variations, Single Post ===============
self::add_memberlite_setting_control( $wp_customize, 'memberlite_post_footer_slug', __( 'Single Post Footer', 'memberlite' ), 'memberlite_footer_options', array(
'type' => 'select',
'sanitize_callback' => 'sanitize_key',
'choices' => $footer_choices,
'default' => '0',
'description' => __( 'Choose which footer pattern to display on the single post view.', 'memberlite' ),
) );

// FOOTER: Variations, Pages ===============
self::add_memberlite_setting_control( $wp_customize, 'memberlite_page_footer_slug', __( 'Pages Footer', 'memberlite' ), 'memberlite_footer_options', array(
'type' => 'select',
'sanitize_callback' => 'sanitize_key',
'choices' => $footer_choices,
'default' => '0',
'description' => __( 'Choose which footer pattern to display on your pages.', 'memberlite' ),
) );
}

/**
Expand Down
25 changes: 21 additions & 4 deletions inc/editor-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ function memberlite_register_editor_settings_post_meta(): void {
}
) );

register_post_meta( 'page', '_memberlite_footer_override', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'default' => '',
'label' => __( 'Select Footer', 'memberlite' ),
'sanitize_callback' => 'sanitize_key',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
}
) );

register_post_meta( 'page', '_memberlite_hide_page_nav', array(
'show_in_rest' => true,
'single' => true,
Expand Down Expand Up @@ -76,10 +88,15 @@ function memberlite_enqueue_custom_editor_assets(): void {
true
);

// Get existing theme mods that we're moving into the settings
wp_localize_script( 'memberlite-custom-settings', 'memberlite_theme_mod_settings', array(
'showPrevNextSinglePages' => get_theme_mod( 'memberlite_page_nav', true )
) );
// Get existing theme mods, and get footer variations to populate the footer override setting
wp_localize_script(
'memberlite-custom-settings',
'memberliteEditorData',
array(
'showPrevNextSinglePages' => get_theme_mod( 'memberlite_page_nav', true ),
'footerVariations' => memberlite_get_footer_variations(),
)
);
}
add_action( 'enqueue_block_editor_assets', 'memberlite_enqueue_custom_editor_assets' );

Expand Down
85 changes: 78 additions & 7 deletions inc/variations.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,86 @@
* @since 7.0
*/

/*
* Checks location-specific theme_mods first (single post, page, archives),
* then falls back to the global default footer setting.
*
* @since TBD
*
* @return string post_name of the memberlite_footer post, or '0' if none is set.
*/
function memberlite_get_current_footer_post_name() {
// Per-page override takes priority over all Customizer settings.
if ( is_singular() ) {
$override = get_post_meta( get_the_ID(), '_memberlite_footer_override', true );
if ( '' !== $override ) {
return $override;
Comment on lines +22 to +23
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The footer override value from post meta is returned/used without sanitization. Since it’s used as a path slug in get_page_by_path(), it should be normalized (e.g., sanitize_key()/sanitize_title()) and ideally constrained to known memberlite_footer slugs (or treated as unset when invalid).

Suggested change
if ( '' !== $override ) {
return $override;
if ( '' !== $override ) {
$override_slug = sanitize_title( $override );
$footer_variations = get_footer_variations();
if ( isset( $footer_variations[ $override_slug ] ) ) {
return $override_slug;
}

Copilot uses AI. Check for mistakes.
}
}

$post_name = '0';

if ( is_singular( 'post' ) ) {
$post_name = get_theme_mod( 'memberlite_post_footer_slug', '0' );
} elseif ( is_page() ) {
$post_name = get_theme_mod( 'memberlite_page_footer_slug', '0' );
} elseif ( is_archive() || is_home() ) {
$post_name = get_theme_mod( 'memberlite_archives_footer_slug', '0' );
}

// Fall back to the global default if the context-specific setting is unset.
if ( empty( $post_name ) || '0' === $post_name ) {
$post_name = get_theme_mod( 'memberlite_default_footer_slug', '0' );
}

return $post_name;
}

/**
* Get the current variation for a given slug.
* Render a footer variation.
*
* @since 7.0
* Looks up the memberlite_footer CPT post by post_name (as stored in the
* theme_mod) and renders its block content. Does nothing if the post is not
* found; the legacy footer fallback is handled upstream in footer.php.
*
* @param string $slug The slug for the variation type (e.g., 'footer').
* @return string The current variation slug, or 'default' if not set.
* @since TBD
* @param string $post_name The post_name of the memberlite_footer post to render.
*/
function memberlite_get_variation( $slug ) {
$variation = get_theme_mod( "memberlite_{$slug}_variation", 'default' );
return ( empty( $variation ) ) ? 'default' : $variation;
function memberlite_render_footer_variation( $post_name ) {
if ( ! empty( $post_name ) && '0' !== $post_name ) {
$footer_post = get_page_by_path( $post_name, OBJECT, 'memberlite_footer' );

if ( $footer_post ) {
echo do_blocks( $footer_post->post_content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
}

/**
* Get memberlite_footer posts for our variation options
*
* @since TBD
*
* @return array
*/
function memberlite_get_footer_variations(): array {
$footer_posts = get_posts( array(
'post_type' => 'memberlite_footer',
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
) );

$footer_choices = array(
'0' => __( '— Use legacy footer —', 'memberlite' ),
);

if ( ! empty( $footer_posts ) ) {
foreach ( $footer_posts as $footer_post ) {
$footer_choices[ $footer_post->post_name ] = $footer_post->post_title;
}
}

return $footer_choices;
}
19 changes: 10 additions & 9 deletions patterns/footer-01.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@
* Description: Footer with two rows, 4 columns on top of 2.
* Categories: memberlite-footer, footer
* Keywords: footer, variation
* Post Types: memberlite_footer
* @package WordPress
* @subpackage Memberlite
* @since TBD
*/
?>
<!-- wp:group {"align":"full","className":"footer-variation-01","style":{"spacing":{"padding":{"top":"var:preset|spacing|50","right":"var:preset|spacing|50","bottom":"var:preset|spacing|50","left":"var:preset|spacing|50"}},"elements":{"link":{"color":{"text":"var:preset|color|page-masthead"}}}},"backgroundColor":"color-primary","textColor":"page-masthead","layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull footer-variation-01 has-page-masthead-color has-color-primary-background-color has-text-color has-background has-link-color" style="padding-top:var(--wp--preset--spacing--50);padding-right:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--50);padding-left:var(--wp--preset--spacing--50)"><!-- wp:columns {"align":"wide","style":{"spacing":{"blockGap":{"top":"var:preset|spacing|40","left":"var:preset|spacing|40"}}}} -->
<!-- wp:group {"align":"full","className":"footer-variation-01","style":{"spacing":{"padding":{"top":"var:preset|spacing|50","right":"var:preset|spacing|50","bottom":"var:preset|spacing|50","left":"var:preset|spacing|50"}},"elements":{"link":{"color":{"text":"var:preset|color|site-navigation-background"}}}},"backgroundColor":"color-primary","textColor":"site-navigation-background","layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull footer-variation-01 has-site-navigation-background-color has-color-primary-background-color has-text-color has-background has-link-color" style="padding-top:var(--wp--preset--spacing--50);padding-right:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--50);padding-left:var(--wp--preset--spacing--50)"><!-- wp:columns {"align":"wide","style":{"spacing":{"blockGap":{"top":"var:preset|spacing|40","left":"var:preset|spacing|40"}}}} -->
<div class="wp-block-columns alignwide"><!-- wp:column {"width":"33%"} -->
<div class="wp-block-column" style="flex-basis:33%"><!-- wp:site-logo /-->

<!-- wp:site-title {"fontSize":"18"} /-->
<!-- wp:site-title {"isLink":false,"fontSize":"18"} /-->

<!-- wp:paragraph {"fontSize":"14"} -->
<p class="has-14-font-size">123 Example Street<br>Cityville, AA, 99999<br>(555) 555-5555</p>
Expand Down Expand Up @@ -59,22 +60,22 @@

<!-- wp:columns {"align":"wide","style":{"spacing":{"blockGap":{"top":"var:preset|spacing|40","left":"var:preset|spacing|40"}}}} -->
<div class="wp-block-columns alignwide"><!-- wp:column {"width":"33%"} -->
<div class="wp-block-column" style="flex-basis:33%"><!-- wp:paragraph {"style":{"typography":{"fontSize":"0.75rem"}},"textColor":"white"} -->
<p class="has-white-color has-text-color" style="font-size:0.75rem">Banking services provided by a South African bank and regulated by the South African Reserve Bank.</p>
<div class="wp-block-column" style="flex-basis:33%"><!-- wp:paragraph {"style":{"typography":{"fontSize":"0.75rem"}}} -->
<p style="font-size:0.75rem">Banking services provided by a South African bank and regulated by the South African Reserve Bank.</p>
<!-- /wp:paragraph --></div>
<!-- /wp:column -->

<!-- wp:column {"style":{"spacing":{"blockGap":"var:preset|spacing|40"}}} -->
<div class="wp-block-column"><!-- wp:group {"style":{"spacing":{"padding":{"top":"0","right":"0","bottom":"0","left":"0"},"margin":{"top":"0","bottom":"0"},"blockGap":"0"},"elements":{"link":{"color":{"text":"var:preset|color|site-navigation-background"}}}},"textColor":"site-navigation-background","layout":{"type":"flex","justifyContent":"right","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group has-site-navigation-background-color has-text-color has-link-color" style="margin-top:0;margin-bottom:0;padding-top:0;padding-right:0;padding-bottom:0;padding-left:0"><!-- wp:paragraph {"style":{"typography":{"fontSize":"0.75rem"}}} -->
<div class="wp-block-column"><!-- wp:group {"style":{"spacing":{"padding":{"top":"0","right":"0","bottom":"0","left":"0"},"margin":{"top":"0","bottom":"0"},"blockGap":"0"}},"layout":{"type":"flex","justifyContent":"right","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group" style="margin-top:0;margin-bottom:0;padding-top:0;padding-right:0;padding-bottom:0;padding-left:0"><!-- wp:paragraph {"style":{"typography":{"fontSize":"0.75rem"}}} -->
<p style="font-size:0.75rem">©</p>
<!-- /wp:paragraph -->

<!-- wp:post-date {"datetime":"2026-03-25T15:34:02.436Z","format":"Y","style":{"typography":{"fontSize":"0.75rem"}}} /-->

<!-- wp:site-title {"level":0,"style":{"typography":{"fontStyle":"normal","fontWeight":"400","fontSize":"0.75rem"},"spacing":{"padding":{"left":"0.5rem"}}}} /-->
<!-- wp:site-title {"level":0,"isLink":false,"style":{"typography":{"fontStyle":"normal","fontWeight":"400","fontSize":"0.75rem"},"spacing":{"padding":{"left":"0.5rem"}}}} /-->

<!-- wp:paragraph {"style":{"typography":{"fontSize":"0.75rem"},"spacing":{"padding":{"left":"0.5rem"}}}} -->
<!-- wp:paragraph {"style":{"typography":{"fontSize":"0.75rem"},"spacing":{"padding":{"left":"0.5rem"}},"layout":{"selfStretch":"fit","flexSize":null}}} -->
<p style="padding-left:0.5rem;font-size:0.75rem"> All rights reserved.</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group --></div>
Expand Down
4 changes: 2 additions & 2 deletions patterns/footer-02.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
* @since TBD
*/
?>
<!-- wp:group {"metadata":{"categories":["memberlite-footer"],"patternName":"memberlite/footer-02","name":"Footer Variation 2"},"align":"full","className":"footer-variation-02","style":{"spacing":{"padding":{"right":"var:preset|spacing|50","bottom":"var:preset|spacing|30","left":"var:preset|spacing|50","top":"var:preset|spacing|30"},"blockGap":"var:preset|spacing|20","margin":{"top":"0","bottom":"0"}},"dimensions":{"minHeight":"40vh"},"color":{"background":"#f3f3f3"},"border":{"top":{"color":"var:preset|color|borders","width":"1px"},"right":[],"bottom":[],"left":[]}},"layout":{"type":"flex","orientation":"vertical","justifyContent":"center","verticalAlignment":"center"}} -->
<div class="wp-block-group alignfull footer-variation-02 has-background" style="border-top-color:var(--wp--preset--color--borders);border-top-width:1px;background-color:#f3f3f3;min-height:40vh;margin-top:0;margin-bottom:0;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--50)"><!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<!-- wp:group {"metadata":{"categories":["memberlite-footer"],"patternName":"memberlite/footer-02","name":"Footer Variation 2"},"align":"full","className":"footer-variation-02","style":{"spacing":{"padding":{"right":"var:preset|spacing|50","bottom":"var:preset|spacing|30","left":"var:preset|spacing|50","top":"var:preset|spacing|30"},"blockGap":"var:preset|spacing|20","margin":{"top":"0","bottom":"0"}},"dimensions":{"minHeight":"40vh"},"border":{"top":{"color":"var:preset|color|borders","width":"1px"},"right":[],"bottom":[],"left":[]},"elements":{"link":{"color":{"text":"var:preset|color|site-navigation-background"}}}},"backgroundColor":"site-navigation-link","textColor":"site-navigation-background","layout":{"type":"flex","orientation":"vertical","justifyContent":"center","verticalAlignment":"center"}} -->
<div class="wp-block-group alignfull footer-variation-02 has-site-navigation-background-color has-site-navigation-link-background-color has-text-color has-background has-link-color" style="border-top-color:var(--wp--preset--color--borders);border-top-width:1px;min-height:40vh;margin-top:0;margin-bottom:0;padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--50)"><!-- wp:group {"style":{"spacing":{"blockGap":"var:preset|spacing|10"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group"><!-- wp:group {"style":{"spacing":{"padding":{"top":"0","right":"0","bottom":"0","left":"0"},"margin":{"top":"0","bottom":"0"},"blockGap":"0"}},"fontSize":"14","layout":{"type":"flex","justifyContent":"right","flexWrap":"nowrap","verticalAlignment":"center"}} -->
<div class="wp-block-group has-14-font-size" style="margin-top:0;margin-bottom:0;padding-top:0;padding-right:0;padding-bottom:0;padding-left:0"><!-- wp:paragraph {"fontSize":"14"} -->
<p class="has-14-font-size">©</p>
Expand Down
Loading