<?php
/**
* Child theme setup and helpers.
*/
function tents_singlepage_child_enqueue_assets() {
$theme_version = wp_get_theme( get_stylesheet() )->get( 'Version' );
$singlepage_css_path = get_stylesheet_directory() . '/assets/css/singlepage.css';
$singlepage_js_path = get_stylesheet_directory() . '/assets/js/singlepage.js';
// Assicura che lo stylesheet di Twenty Seventeen punti al tema padre, non al child.
wp_dequeue_style( 'twentyseventeen-style' );
wp_deregister_style( 'twentyseventeen-style' );
wp_enqueue_style(
'twentyseventeen-style',
get_template_directory_uri() . '/style.css',
array( 'twentyseventeen-fonts' ),
'20251202'
);
// Child theme main stylesheet (per override leggeri).
wp_enqueue_style(
'tents-singlepage-child-style',
get_stylesheet_directory_uri() . '/style.css',
array( 'twentyseventeen-style' ),
$theme_version
);
// Additional styles for single page layout.
wp_enqueue_style(
'tents-singlepage-child-singlepage',
get_stylesheet_directory_uri() . '/assets/css/singlepage.css',
array( 'tents-singlepage-child-style' ),
file_exists( $singlepage_css_path ) ? (string) filemtime( $singlepage_css_path ) : $theme_version
);
$fixed_header_settings = tents_singlepage_get_fixed_header_settings();
$fixed_header_css = sprintf(
':root{--tents-fixed-header-bg:%1$s;--tents-fixed-header-text:%2$s;--tents-fixed-header-primary-cta-bg:%3$s;--tents-fixed-header-primary-cta-text:%4$s;--tents-fixed-header-secondary-cta-bg:%5$s;--tents-fixed-header-secondary-cta-text:%6$s;--tents-fixed-header-logo-max-height:%7$spx;}',
esc_html( $fixed_header_settings['background_color'] ),
esc_html( $fixed_header_settings['text_color'] ),
esc_html( $fixed_header_settings['primary_cta_background_color'] ),
esc_html( $fixed_header_settings['primary_cta_text_color'] ),
esc_html( $fixed_header_settings['secondary_cta_background_color'] ),
esc_html( $fixed_header_settings['secondary_cta_text_color'] ),
(int) $fixed_header_settings['logo_max_height']
);
wp_add_inline_style( 'tents-singlepage-child-singlepage', $fixed_header_css );
// JS for smooth scrolling and menu behavior.
wp_enqueue_script(
'tents-singlepage-child-singlepage',
get_stylesheet_directory_uri() . '/assets/js/singlepage.js',
array( 'jquery' ),
file_exists( $singlepage_js_path ) ? (string) filemtime( $singlepage_js_path ) : $theme_version,
true
);
}
add_action( 'wp_enqueue_scripts', 'tents_singlepage_child_enqueue_assets', 20 );
/**
* Sanitize per impostazioni immagine del Customizer.
*
* WP_Customize_Image_Control può salvare un URL; supportiamo anche ID numerici.
*
* @param mixed $value Valore in input.
* @return string|int
*/
function tents_singlepage_sanitize_image_setting( $value ) {
if ( is_numeric( $value ) ) {
return absint( $value );
}
return esc_url_raw( (string) $value );
}
/**
* Sanitize opacity (0..1).
*
* @param mixed $value Opacity.
* @return string
*/
function tents_singlepage_sanitize_opacity( $value ) {
$float = floatval( $value );
if ( $float < 0 ) {
$float = 0;
}
if ( $float > 1 ) {
$float = 1;
}
// Keep a compact string representation.
return rtrim( rtrim( sprintf( '%.2f', $float ), '0' ), '.' );
}
/**
* Sanitize checkbox-like Customizer settings.
*
* @param mixed $value Input value.
* @return int
*/
function tents_singlepage_sanitize_checkbox( $value ) {
return $value ? 1 : 0;
}
/**
* Sanitize a link URL for header CTAs and similar settings.
*
* Accepts absolute URLs, relative paths, anchors, mailto and tel links.
*
* @param mixed $value URL value.
* @return string
*/
function tents_singlepage_sanitize_link_url( $value ) {
$value = trim( (string) $value );
if ( '' === $value ) {
return '';
}
if ( '#' === $value[0] || '/' === $value[0] ) {
return esc_url_raw( $value, array( 'http', 'https', 'mailto', 'tel' ) );
}
if ( 0 === stripos( $value, 'mailto:' ) || 0 === stripos( $value, 'tel:' ) ) {
return esc_url_raw( $value, array( 'http', 'https', 'mailto', 'tel' ) );
}
if ( ! preg_match( '#^https?://#i', $value ) ) {
$value = 'https://' . ltrim( $value, '/' );
}
return esc_url_raw( $value );
}
/**
* Normalize a fixed-header CTA from optional label and URL values.
*
* @param string $label CTA label.
* @param string $url CTA URL.
* @return array|null
*/
function tents_singlepage_normalize_header_cta( $label, $url ) {
$label = sanitize_text_field( $label );
$url = tents_singlepage_sanitize_link_url( $url );
if ( '' === $label && '' === $url ) {
return null;
}
return array(
'label' => '' !== $label ? $label : __( 'Scopri di più', 'tents-singlepage-child' ),
'url' => '' !== $url ? $url : '#',
);
}
/**
* Get a sanitized color theme mod with a safe fallback.
*
* @param string $setting_id Theme mod id.
* @param string $default Default color.
* @return string
*/
function tents_singlepage_get_color_theme_mod( $setting_id, $default ) {
$color = sanitize_hex_color( get_theme_mod( $setting_id, $default ) );
return $color ? $color : $default;
}
/**
* Sanitize an optional CTA background color (empty means transparent).
*
* @param mixed $value Color value.
* @return string
*/
function tents_singlepage_sanitize_cta_background_color( $value ) {
$value = strtolower( trim( (string) $value ) );
if ( '' === $value || 'transparent' === $value ) {
return '';
}
$color = sanitize_hex_color( $value );
return $color ? $color : '';
}
/**
* Get a CTA background color theme mod (transparent when unset).
*
* @param string $setting_id Theme mod id.
* @param string $default Default color.
* @return string
*/
function tents_singlepage_get_cta_background_theme_mod( $setting_id, $default = 'transparent' ) {
$color = tents_singlepage_sanitize_cta_background_color( get_theme_mod( $setting_id, '' ) );
return $color ? $color : $default;
}
/**
* Get configured stack buttons for a homepage section (max 3).
*
* @param string $slug Page slug for the section.
* @return array<int, array{label: string, url: string, text_color: string, bg_color: string}>
*/
function tents_singlepage_get_section_stack_buttons( $slug ) {
$slug = sanitize_title( $slug );
$buttons = array();
for ( $index = 1; $index <= 3; $index++ ) {
$label = sanitize_text_field( get_theme_mod( "section_{$slug}_button_{$index}_label", '' ) );
$url = tents_singlepage_sanitize_link_url( get_theme_mod( "section_{$slug}_button_{$index}_url", '' ) );
if ( '' === $label || '' === $url ) {
continue;
}
$buttons[] = array(
'label' => $label,
'url' => $url,
'text_color' => tents_singlepage_get_color_theme_mod( "section_{$slug}_button_{$index}_text_color", '#ffffff' ),
'bg_color' => tents_singlepage_get_color_theme_mod( "section_{$slug}_button_{$index}_bg_color", '#326a34' ),
);
}
return $buttons;
}
/**
* Register stack button settings for a homepage section in the Customizer.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @param string $section_id Customizer section id.
* @param string $slug Page slug.
*/
function tents_singlepage_register_section_stack_button_settings( $wp_customize, $section_id, $slug ) {
$slug = sanitize_title( $slug );
for ( $index = 1; $index <= 3; $index++ ) {
$label_setting = "section_{$slug}_button_{$index}_label";
$url_setting = "section_{$slug}_button_{$index}_url";
$text_color_setting = "section_{$slug}_button_{$index}_text_color";
$bg_color_setting = "section_{$slug}_button_{$index}_bg_color";
$wp_customize->add_setting(
$label_setting,
array(
'default' => '',
'sanitize_callback' => 'sanitize_text_field',
)
);
$wp_customize->add_control(
$label_setting,
array(
'label' => sprintf(
/* translators: %d: button number */
__( 'Pulsante %d — testo', 'tents-singlepage-child' ),
$index
),
'description' => 1 === $index
? __( 'Fino a 3 pulsanti in alto a destra nella striscia. Compila testo e URL per mostrarli.', 'tents-singlepage-child' )
: '',
'section' => $section_id,
'type' => 'text',
)
);
$wp_customize->add_setting(
$url_setting,
array(
'default' => '',
'sanitize_callback' => 'tents_singlepage_sanitize_link_url',
)
);
$wp_customize->add_control(
$url_setting,
array(
'label' => sprintf(
/* translators: %d: button number */
__( 'Pulsante %d — URL', 'tents-singlepage-child' ),
$index
),
'section' => $section_id,
'type' => 'text',
)
);
$wp_customize->add_setting(
$text_color_setting,
array(
'default' => '#ffffff',
'sanitize_callback' => 'sanitize_hex_color',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$text_color_setting,
array(
'label' => sprintf(
/* translators: %d: button number */
__( 'Pulsante %d — colore testo', 'tents-singlepage-child' ),
$index
),
'section' => $section_id,
'settings' => $text_color_setting,
)
)
);
$wp_customize->add_setting(
$bg_color_setting,
array(
'default' => '#326a34',
'sanitize_callback' => 'sanitize_hex_color',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$bg_color_setting,
array(
'label' => sprintf(
/* translators: %d: button number */
__( 'Pulsante %d — colore sfondo', 'tents-singlepage-child' ),
$index
),
'section' => $section_id,
'settings' => $bg_color_setting,
)
)
);
}
}
/**
* Normalize local asset URLs saved with an old local host/port.
*
* The imported database can contain values like http://localhost:8080/wp-content/uploads/...
* while the current local site runs on https://localhost:8443. Keep the DB untouched and
* rewrite only local WordPress asset URLs at render time.
*
* @param string $url Asset URL.
* @return string
*/
function tents_singlepage_normalize_local_asset_url( $url ) {
if ( empty( $url ) || ! is_string( $url ) ) {
return $url;
}
$parsed_url = wp_parse_url( $url );
$path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
if ( empty( $parsed_url['host'] ) || empty( $path ) ) {
return $url;
}
$is_wordpress_asset = strpos( $path, '/wp-content/uploads/' ) !== false
|| strpos( $path, '/wp-content/themes/' ) !== false;
if ( ! $is_wordpress_asset ) {
return $url;
}
$current_host = wp_parse_url( home_url(), PHP_URL_HOST );
$url_host = $parsed_url['host'];
$is_local_url = in_array( $url_host, array( 'localhost', '127.0.0.1' ), true )
|| $url_host === $current_host;
if ( ! $is_local_url ) {
return $url;
}
$normalized_url = home_url( $path );
if ( ! empty( $parsed_url['query'] ) ) {
$normalized_url .= '?' . $parsed_url['query'];
}
if ( ! empty( $parsed_url['fragment'] ) ) {
$normalized_url .= '#' . $parsed_url['fragment'];
}
return $normalized_url;
}
add_filter( 'theme_mod_header_image', 'tents_singlepage_normalize_local_asset_url' );
/**
* Normalize custom header image metadata URLs.
*
* @param mixed $header_image_data Header image data.
* @return mixed
*/
function tents_singlepage_normalize_header_image_data( $header_image_data ) {
if ( is_object( $header_image_data ) ) {
if ( ! empty( $header_image_data->url ) ) {
$header_image_data->url = tents_singlepage_normalize_local_asset_url( $header_image_data->url );
}
if ( ! empty( $header_image_data->thumbnail_url ) ) {
$header_image_data->thumbnail_url = tents_singlepage_normalize_local_asset_url( $header_image_data->thumbnail_url );
}
}
return $header_image_data;
}
add_filter( 'theme_mod_header_image_data', 'tents_singlepage_normalize_header_image_data' );
/**
* Normalize local WordPress asset URLs inside rendered content.
*
* @param string $content Rendered content.
* @return string
*/
function tents_singlepage_normalize_content_asset_urls( $content ) {
if ( empty( $content ) || ! is_string( $content ) ) {
return $content;
}
return preg_replace_callback(
'#https?://[^\\s"\\\']+/wp-content/(?:uploads|themes)/[^\\s"\\\'<>)]*#',
function ( $matches ) {
return esc_url( tents_singlepage_normalize_local_asset_url( $matches[0] ) );
},
$content
);
}
add_filter( 'the_content', 'tents_singlepage_normalize_content_asset_urls', 20 );
/**
* Sanitize logo max height in pixels.
*
* @param mixed $value Input value.
* @return int
*/
function tents_singlepage_sanitize_logo_max_height( $value ) {
$height = absint( $value );
if ( $height < 40 ) {
$height = 40;
}
if ( $height > 120 ) {
$height = 120;
}
return $height;
}
/**
* Resolve a fixed header logo setting to a full-size image URL.
*
* @param mixed $value Theme mod value (attachment ID or URL).
* @return string
*/
function tents_singlepage_get_fixed_header_logo_url( $value ) {
if ( empty( $value ) ) {
return '';
}
if ( is_numeric( $value ) ) {
$url = wp_get_attachment_image_url( (int) $value, 'full' );
return $url ? tents_singlepage_normalize_local_asset_url( $url ) : '';
}
return tents_singlepage_normalize_local_asset_url( (string) $value );
}
/**
* Get fixed header settings in one place.
*
* @return array
*/
function tents_singlepage_get_fixed_header_settings() {
$logo_value = get_theme_mod( 'tents_fixed_header_logo', '' );
$logo_alt = get_theme_mod( 'tents_fixed_header_logo_alt', '' );
$site_name = get_bloginfo( 'name', 'display' );
return array(
'enabled' => (bool) get_theme_mod( 'tents_fixed_header_enabled', 1 ),
'hide_hero_branding' => (bool) get_theme_mod( 'tents_fixed_header_hide_hero_branding', 1 ),
'show_social' => (bool) get_theme_mod( 'tents_fixed_header_show_social', 1 ),
'social_label' => sanitize_text_field( get_theme_mod( 'tents_fixed_header_social_label', '' ) ),
'facebook_url' => esc_url_raw( get_theme_mod( 'tents_social_facebook_url', '' ) ),
'instagram_url' => esc_url_raw( get_theme_mod( 'tents_social_instagram_url', '' ) ),
'youtube_url' => esc_url_raw( get_theme_mod( 'tents_social_youtube_url', '' ) ),
'primary_cta_label' => sanitize_text_field( get_theme_mod( 'tents_fixed_header_primary_cta_label', '' ) ),
'primary_cta_url' => tents_singlepage_sanitize_link_url( get_theme_mod( 'tents_fixed_header_primary_cta_url', '' ) ),
'secondary_cta_label' => sanitize_text_field( get_theme_mod( 'tents_fixed_header_secondary_cta_label', '' ) ),
'secondary_cta_url' => tents_singlepage_sanitize_link_url( get_theme_mod( 'tents_fixed_header_secondary_cta_url', '' ) ),
'primary_cta' => tents_singlepage_normalize_header_cta(
get_theme_mod( 'tents_fixed_header_primary_cta_label', '' ),
get_theme_mod( 'tents_fixed_header_primary_cta_url', '' )
),
'secondary_cta' => tents_singlepage_normalize_header_cta(
get_theme_mod( 'tents_fixed_header_secondary_cta_label', '' ),
get_theme_mod( 'tents_fixed_header_secondary_cta_url', '' )
),
'logo_url' => tents_singlepage_get_fixed_header_logo_url( $logo_value ),
'logo_alt' => $logo_alt ? sanitize_text_field( $logo_alt ) : sanitize_text_field( $site_name ),
'logo_max_height' => tents_singlepage_sanitize_logo_max_height( get_theme_mod( 'tents_fixed_header_logo_max_height', 58 ) ),
'background_color' => tents_singlepage_get_color_theme_mod( 'tents_fixed_header_background_color', '#ffffff' ),
'text_color' => tents_singlepage_get_color_theme_mod( 'tents_fixed_header_text_color', '#ffffff' ),
'primary_cta_background_color' => tents_singlepage_get_color_theme_mod( 'tents_fixed_header_primary_cta_background_color', '#4d963d' ),
'primary_cta_text_color' => tents_singlepage_get_color_theme_mod( 'tents_fixed_header_primary_cta_text_color', '#ffffff' ),
'secondary_cta_background_color' => tents_singlepage_get_cta_background_theme_mod( 'tents_fixed_header_secondary_cta_background_color', 'transparent' ),
'secondary_cta_text_color' => tents_singlepage_get_color_theme_mod( 'tents_fixed_header_secondary_cta_text_color', '#ffffff' ),
);
}
/**
* Register fixed header Customizer settings.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
*/
function tents_singlepage_customize_register_fixed_header( $wp_customize ) {
$wp_customize->add_section(
'tents_singlepage_fixed_header',
array(
'title' => __( 'Header fisso', 'tents-singlepage-child' ),
'description' => __( 'Logo e call to action della barra fissa.', 'tents-singlepage-child' ),
'priority' => 9,
)
);
$checkbox_settings = array(
'tents_fixed_header_enabled' => array(
'label' => __( 'Abilita header fisso', 'tents-singlepage-child' ),
'default' => 1,
),
'tents_fixed_header_hide_hero_branding' => array(
'label' => __( 'Nascondi branding nel hero', 'tents-singlepage-child' ),
'description' => __( 'Evita di mostrare due volte logo e nome sito quando la barra fissa è attiva.', 'tents-singlepage-child' ),
'default' => 1,
),
'tents_fixed_header_show_social' => array(
'label' => __( 'Mostra social', 'tents-singlepage-child' ),
'default' => 1,
),
);
foreach ( $checkbox_settings as $setting_id => $setting_args ) {
$wp_customize->add_setting(
$setting_id,
array(
'default' => $setting_args['default'],
'sanitize_callback' => 'tents_singlepage_sanitize_checkbox',
)
);
$wp_customize->add_control(
$setting_id,
array(
'label' => $setting_args['label'],
'description' => isset( $setting_args['description'] ) ? $setting_args['description'] : '',
'section' => 'tents_singlepage_fixed_header',
'type' => 'checkbox',
)
);
}
$wp_customize->add_setting(
'tents_fixed_header_logo',
array(
'default' => '',
'sanitize_callback' => 'tents_singlepage_sanitize_image_setting',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
'tents_fixed_header_logo',
array(
'label' => __( 'Logo header', 'tents-singlepage-child' ),
'description' => __( 'Logo rettangolare mostrato al centro della barra fissa. Non usa il ritaglio quadrato del logo del sito.', 'tents-singlepage-child' ),
'section' => 'tents_singlepage_fixed_header',
'settings' => 'tents_fixed_header_logo',
)
)
);
$wp_customize->add_setting(
'tents_fixed_header_logo_alt',
array(
'default' => '',
'sanitize_callback' => 'sanitize_text_field',
)
);
$wp_customize->add_control(
'tents_fixed_header_logo_alt',
array(
'label' => __( 'Testo alternativo logo', 'tents-singlepage-child' ),
'description' => __( 'Lasciare vuoto per usare il nome del sito.', 'tents-singlepage-child' ),
'section' => 'tents_singlepage_fixed_header',
'type' => 'text',
)
);
$wp_customize->add_setting(
'tents_fixed_header_logo_max_height',
array(
'default' => 58,
'sanitize_callback' => 'tents_singlepage_sanitize_logo_max_height',
)
);
$wp_customize->add_control(
'tents_fixed_header_logo_max_height',
array(
'label' => __( 'Altezza massima logo (px)', 'tents-singlepage-child' ),
'description' => __( 'Regola l’altezza del logo rettangolare mantenendo le proporzioni.', 'tents-singlepage-child' ),
'section' => 'tents_singlepage_fixed_header',
'type' => 'range',
'input_attrs' => array(
'min' => 40,
'max' => 120,
'step' => 1,
),
)
);
$text_settings = array(
'tents_fixed_header_social_label' => array(
'label' => __( 'Etichetta social', 'tents-singlepage-child' ),
'description' => __( 'Testo mostrato sopra le icone Facebook, Instagram e YouTube, nella colonna destra dell’header.', 'tents-singlepage-child' ),
'type' => 'text',
'sanitize_callback' => 'sanitize_text_field',
),
'tents_fixed_header_primary_cta_label' => array(
'label' => __( 'CTA principale — testo (colonna destra)', 'tents-singlepage-child' ),
'description' => __( 'Pulsante evidenziato a destra, accanto a social e menu hamburger. Es.: «Dona», «Contattaci». Basta il testo per mostrarlo; l’URL è consigliato.', 'tents-singlepage-child' ),
'type' => 'text',
'sanitize_callback' => 'sanitize_text_field',
),
'tents_fixed_header_primary_cta_url' => array(
'label' => __( 'CTA principale — URL (colonna destra)', 'tents-singlepage-child' ),
'description' => __( 'Destinazione del pulsante principale a destra. Accetta URL completo, percorso relativo (es. /statuto.pdf) o ancora (es. #donazioni).', 'tents-singlepage-child' ),
'type' => 'text',
'sanitize_callback' => 'tents_singlepage_sanitize_link_url',
),
'tents_fixed_header_secondary_cta_label' => array(
'label' => __( 'CTA sinistra — testo (colonna sinistra)', 'tents-singlepage-child' ),
'description' => __( 'Link testuale a sinistra dell’header, opposto al logo. Es.: «Statuto», «Documenti». Basta testo o URL per mostrarlo.', 'tents-singlepage-child' ),
'type' => 'text',
'sanitize_callback' => 'sanitize_text_field',
),
'tents_fixed_header_secondary_cta_url' => array(
'label' => __( 'CTA sinistra — URL (colonna sinistra)', 'tents-singlepage-child' ),
'description' => __( 'Destinazione del link a sinistra. Accetta URL completo, percorso relativo o ancora interna.', 'tents-singlepage-child' ),
'type' => 'text',
'sanitize_callback' => 'tents_singlepage_sanitize_link_url',
),
);
foreach ( $text_settings as $setting_id => $setting_args ) {
$wp_customize->add_setting(
$setting_id,
array(
'default' => '',
'sanitize_callback' => $setting_args['sanitize_callback'],
)
);
$wp_customize->add_control(
$setting_id,
array(
'label' => $setting_args['label'],
'description' => isset( $setting_args['description'] ) ? $setting_args['description'] : '',
'section' => 'tents_singlepage_fixed_header',
'type' => $setting_args['type'],
)
);
}
$color_settings = array(
'tents_fixed_header_background_color' => array(
'label' => __( 'Colore sfondo header', 'tents-singlepage-child' ),
'default' => '#ffffff',
),
'tents_fixed_header_text_color' => array(
'label' => __( 'Colore testo header', 'tents-singlepage-child' ),
'default' => '#ffffff',
),
'tents_fixed_header_primary_cta_background_color' => array(
'label' => __( 'Colore sfondo CTA principale (destra)', 'tents-singlepage-child' ),
'description' => __( 'Sfondo del pulsante evidenziato nella colonna destra.', 'tents-singlepage-child' ),
'default' => '#4d963d',
),
'tents_fixed_header_primary_cta_text_color' => array(
'label' => __( 'Colore testo CTA principale (destra)', 'tents-singlepage-child' ),
'description' => __( 'Colore del testo del pulsante evidenziato a destra.', 'tents-singlepage-child' ),
'default' => '#ffffff',
),
'tents_fixed_header_secondary_cta_background_color' => array(
'label' => __( 'Colore sfondo CTA sinistra', 'tents-singlepage-child' ),
'description' => __( 'Sfondo del link nella colonna sinistra. Lascia vuoto o trasparente per nessuno sfondo.', 'tents-singlepage-child' ),
'default' => '',
'sanitize_callback' => 'tents_singlepage_sanitize_cta_background_color',
),
'tents_fixed_header_secondary_cta_text_color' => array(
'label' => __( 'Colore testo CTA sinistra', 'tents-singlepage-child' ),
'description' => __( 'Colore del link testuale nella colonna sinistra dell’header.', 'tents-singlepage-child' ),
'default' => '#ffffff',
),
);
foreach ( $color_settings as $setting_id => $setting_args ) {
$wp_customize->add_setting(
$setting_id,
array(
'default' => $setting_args['default'],
'sanitize_callback' => isset( $setting_args['sanitize_callback'] ) ? $setting_args['sanitize_callback'] : 'sanitize_hex_color',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$setting_id,
array(
'label' => $setting_args['label'],
'description' => isset( $setting_args['description'] ) ? $setting_args['description'] : '',
'section' => 'tents_singlepage_fixed_header',
'settings' => $setting_id,
)
)
);
}
}
/**
* Add body classes that allow the fixed header to be enabled without parent edits.
*
* @param string[] $classes Body classes.
* @return string[]
*/
function tents_singlepage_body_classes( $classes ) {
$header_settings = tents_singlepage_get_fixed_header_settings();
if ( $header_settings['enabled'] ) {
$classes[] = 'has-tents-fixed-header';
// Avoid Twenty Seventeen hero/parallax header rules conflicting with the fixed bar.
$classes = array_diff(
$classes,
array(
'has-header-image',
'has-header-video',
)
);
}
if ( $header_settings['enabled'] && $header_settings['hide_hero_branding'] ) {
$classes[] = 'has-tents-fixed-header-hidden-branding';
}
return $classes;
}
add_filter( 'body_class', 'tents_singlepage_body_classes', 99 );
/**
* Register Customizer settings for section background images.
*
* One image field per top-level primary menu item (page).
*
* @param WP_Customize_Manager $wp_customize Customizer object.
*/
function tents_singlepage_customize_register( $wp_customize ) {
tents_singlepage_customize_register_fixed_header( $wp_customize );
$locations = get_nav_menu_locations();
if ( empty( $locations['top'] ) ) {
return;
}
$menu = wp_get_nav_menu_object( $locations['top'] );
$menu_items = wp_get_nav_menu_items( $menu->term_id );
if ( empty( $menu_items ) ) {
return;
}
// Panel for homepage sections + social.
$wp_customize->add_panel(
'tents_singlepage_sections_panel',
array(
'title' => __( 'Homepage Sections', 'tents-singlepage-child' ),
'description' => __( 'Impostazioni per le sezioni della homepage single page.', 'tents-singlepage-child' ),
'priority' => 160,
)
);
foreach ( $menu_items as $item ) {
if ( (int) $item->menu_item_parent !== 0 ) {
continue;
}
if ( $item->object !== 'page' || empty( $item->object_id ) ) {
continue;
}
$page = get_post( $item->object_id );
if ( ! $page ) {
continue;
}
$slug = $page->post_name;
$section_id = 'tents_section_' . sanitize_title( $slug );
$bg_setting = 'section_' . sanitize_title( $slug ) . '_bg_image';
$bg_color_setting = 'section_' . sanitize_title( $slug ) . '_bg_color';
$text_color_setting = 'section_' . sanitize_title( $slug ) . '_text_color';
$overlay_color_setting = 'section_' . sanitize_title( $slug ) . '_overlay_color';
$overlay_opacity_setting = 'section_' . sanitize_title( $slug ) . '_overlay_opacity';
$banner_text_setting = 'section_' . sanitize_title( $slug ) . '_banner_text';
$hide_title_setting = 'section_' . sanitize_title( $slug ) . '_hide_title';
// Customizer section for this menu item.
$wp_customize->add_section(
$section_id,
array(
'title' => sprintf(
/* translators: %s: menu item title */
__( 'Sezione: %s', 'tents-singlepage-child' ),
$item->title
),
'panel' => 'tents_singlepage_sections_panel',
)
);
// Background image setting.
$wp_customize->add_setting(
$bg_setting,
array(
'default' => '',
// WP_Customize_Image_Control salva tipicamente l'URL dell'immagine.
// Accettiamo sia URL che ID (per retro-compatibilità).
'sanitize_callback' => 'tents_singlepage_sanitize_image_setting',
)
);
$wp_customize->add_control(
new WP_Customize_Image_Control(
$wp_customize,
$bg_setting,
array(
'label' => __( 'Immagine di sfondo', 'tents-singlepage-child' ),
'section' => $section_id,
'settings' => $bg_setting,
)
)
);
// Background color setting.
$wp_customize->add_setting(
$bg_color_setting,
array(
'default' => '',
'sanitize_callback' => 'sanitize_hex_color',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$bg_color_setting,
array(
'label' => __( 'Colore di sfondo', 'tents-singlepage-child' ),
'section' => $section_id,
'settings' => $bg_color_setting,
)
)
);
// Text color setting.
$wp_customize->add_setting(
$text_color_setting,
array(
'default' => '',
'sanitize_callback' => 'sanitize_hex_color',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$text_color_setting,
array(
'label' => __( 'Colore testo sezione', 'tents-singlepage-child' ),
'section' => $section_id,
'settings' => $text_color_setting,
)
)
);
// Overlay color + opacity (for background images).
$wp_customize->add_setting(
$overlay_color_setting,
array(
'default' => '#000000',
'sanitize_callback' => 'sanitize_hex_color',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
$overlay_color_setting,
array(
'label' => __( 'Colore overlay immagine', 'tents-singlepage-child' ),
'description' => __( 'Usato solo se la sezione ha un’immagine di sfondo.', 'tents-singlepage-child' ),
'section' => $section_id,
'settings' => $overlay_color_setting,
)
)
);
$wp_customize->add_setting(
$overlay_opacity_setting,
array(
'default' => '0.4',
'sanitize_callback' => 'tents_singlepage_sanitize_opacity',
)
);
$wp_customize->add_control(
$overlay_opacity_setting,
array(
'label' => __( 'Opacità overlay', 'tents-singlepage-child' ),
'description' => __( '0 = trasparente, 1 = completamente coprente.', 'tents-singlepage-child' ),
'section' => $section_id,
'type' => 'range',
'input_attrs' => array(
'min' => 0,
'max' => 1,
'step' => 0.05,
),
)
);
$wp_customize->add_setting(
$banner_text_setting,
array(
'default' => '',
'sanitize_callback' => 'sanitize_text_field',
)
);
$wp_customize->add_control(
$banner_text_setting,
array(
'label' => __( 'Striscia in basso — testo', 'tents-singlepage-child' ),
'description' => __( 'Se compilato, mostra in fondo alla sezione una striscia verde con testo bianco centrato (es. «CI RIFIUTIAMO DI ESSERE NEMICI»).', 'tents-singlepage-child' ),
'section' => $section_id,
'type' => 'text',
)
);
$wp_customize->add_setting(
$hide_title_setting,
array(
'default' => 0,
'sanitize_callback' => 'tents_singlepage_sanitize_checkbox',
)
);
$wp_customize->add_control(
$hide_title_setting,
array(
'label' => __( 'Nascondi titolo sezione', 'tents-singlepage-child' ),
'description' => __( 'Non mostra il titolo della pagina in questa striscia.', 'tents-singlepage-child' ),
'section' => $section_id,
'type' => 'checkbox',
)
);
tents_singlepage_register_section_stack_button_settings( $wp_customize, $section_id, $slug );
}
// Sezione Social (Facebook, Instagram, YouTube) nel Customizer.
$wp_customize->add_section(
'tents_singlepage_social',
array(
'title' => __( 'Link Social header', 'tents-singlepage-child' ),
'priority' => 10,
)
);
// Facebook URL.
$wp_customize->add_setting(
'tents_social_facebook_url',
array(
'default' => '',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
'tents_social_facebook_url',
array(
'label' => __( 'URL pagina Facebook', 'tents-singlepage-child' ),
'description' => __( 'Es: https://www.facebook.com/tua-pagina', 'tents-singlepage-child' ),
'section' => 'tents_singlepage_social',
'type' => 'url',
)
);
// Instagram URL.
$wp_customize->add_setting(
'tents_social_instagram_url',
array(
'default' => '',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
'tents_social_instagram_url',
array(
'label' => __( 'URL profilo Instagram', 'tents-singlepage-child' ),
'description' => __( 'Es: https://www.instagram.com/tuo-profilo', 'tents-singlepage-child' ),
'section' => 'tents_singlepage_social',
'type' => 'url',
)
);
// YouTube URL.
$wp_customize->add_setting(
'tents_social_youtube_url',
array(
'default' => '',
'sanitize_callback' => 'esc_url_raw',
)
);
$wp_customize->add_control(
'tents_social_youtube_url',
array(
'label' => __( 'URL canale YouTube', 'tents-singlepage-child' ),
'description' => __( 'Es: https://www.youtube.com/@tuo-canale', 'tents-singlepage-child' ),
'section' => 'tents_singlepage_social',
'type' => 'url',
)
);
}
add_action( 'customize_register', 'tents_singlepage_customize_register' );
/**
* Get primary menu sections based on top-level menu items.
*
* Each section corresponds to a top-level item in the primary menu that points to a page.
*
* @return array
*/
function tents_singlepage_get_sections() {
$sections = array();
$locations = get_nav_menu_locations();
if ( empty( $locations['top'] ) ) {
return $sections;
}
$menu = wp_get_nav_menu_object( $locations['top'] );
$menu_items = wp_get_nav_menu_items( $menu->term_id );
if ( empty( $menu_items ) ) {
return $sections;
}
foreach ( $menu_items as $item ) {
// Consider only top-level items that point to pages.
if ( (int) $item->menu_item_parent !== 0 ) {
continue;
}
if ( $item->object !== 'page' || empty( $item->object_id ) ) {
continue;
}
$page = get_post( $item->object_id );
if ( ! $page ) {
continue;
}
$slug = $page->post_name;
// Build section data.
$sections[] = array(
'id' => 'section-' . sanitize_title( $slug ),
'slug' => $slug,
'menu_title' => $item->title,
'page_id' => $page->ID,
'title' => get_the_title( $page ),
'content' => apply_filters( 'the_content', $page->post_content ),
);
}
return $sections;
}
/**
* Build the homepage URL for a section anchor.
*
* @param string $slug Page slug.
* @return string
*/
function tents_singlepage_get_section_url( $slug ) {
return home_url( '/' ) . '#section-' . sanitize_title( $slug );
}
/**
* Rewrite primary menu links: top-level → homepage section anchors; nested → page URLs.
*
* First-level items always point to `/#section-{slug}` (from any page on the site).
* Second level and deeper keep their normal permalinks.
*/
function tents_singlepage_filter_nav_menu_link_attributes( $atts, $item, $args ) {
if ( empty( $args->theme_location ) || 'top' !== $args->theme_location ) {
return $atts;
}
if ( (int) $item->menu_item_parent !== 0 ) {
if ( 'page' === $item->object && ! empty( $item->object_id ) ) {
$atts['href'] = get_permalink( (int) $item->object_id );
}
return $atts;
}
if ( 'page' === $item->object && ! empty( $item->object_id ) ) {
$page = get_post( $item->object_id );
if ( $page ) {
$atts['href'] = tents_singlepage_get_section_url( $page->post_name );
}
}
return $atts;
}
add_filter( 'nav_menu_link_attributes', 'tents_singlepage_filter_nav_menu_link_attributes', 10, 3 );