diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d1516b3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+Thumbs.db
+*.log
+.idea/
+.vscode/
+*.swp
+*~
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..534f851
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# Tents Single Page (Child Theme)
+
+Child theme di **Twenty Seventeen** per il sito Tents of Nations / TON Italia: layout single-page con sezioni ancorate dal menu.
+
+## Requisiti
+
+- WordPress 6.0+
+- Tema parent **Twenty Seventeen** installato e attivo
+
+## Installazione
+
+1. Copia la cartella `tents-singlepage-child` in `wp-content/themes/`
+2. In **Aspetto → Temi** attiva **Tents Single Page (Twenty Seventeen Child)**
+
+## Repository
+
+- GitBucket: `https://niphredil.duckdns.org/git/fabio/tonitalia-theme.git`
+
+## Struttura
+
+- `front-page.php` — homepage a sezioni
+- `functions.php` — menu ancore, Customizer, asset
+- `assets/` — CSS e JS del child theme
diff --git a/assets/css/singlepage.css b/assets/css/singlepage.css
new file mode 100644
index 0000000..088cfb0
--- /dev/null
+++ b/assets/css/singlepage.css
@@ -0,0 +1,602 @@
+/* Titoli homepage: tipografia esplicita (colori da Customizer / tema). */
+.singlepage-section__title,
+body.page:not(.twentyseventeen-front-page) .entry-header .entry-title.tents-home-title-typography {
+ font-family: "Libre Franklin", "Helvetica Neue", helvetica, arial, sans-serif;
+ font-size: 1.25rem;
+ font-weight: 300;
+ letter-spacing: normal;
+ line-height: 1.4;
+ text-transform: none;
+}
+
+@media screen and (min-width: 48em) {
+ .singlepage-section__title,
+ body.page:not(.twentyseventeen-front-page) .entry-header .entry-title.tents-home-title-typography {
+ font-size: 1.625rem;
+ }
+}
+
+body.page:not(.twentyseventeen-front-page) .tents-page-header {
+ margin-bottom: 1.5em;
+}
+
+.singlepage-section {
+ position: relative;
+ padding: 80px 0;
+}
+
+.singlepage-section--no-content {
+ min-height: 650px;
+}
+
+.singlepage-section--has-bg {
+ color: #fff;
+}
+
+/* Se l'utente sceglie un colore testo, forziamo anche i link a ereditarlo */
+.singlepage-section--has-text-color a {
+ color: inherit;
+}
+
+/* Twenty Seventeen imposta colori espliciti sugli heading: forza l'ereditarietà */
+.singlepage-section--has-text-color .singlepage-section__title,
+.singlepage-section--has-text-color h1,
+.singlepage-section--has-text-color h2,
+.singlepage-section--has-text-color h3,
+.singlepage-section--has-text-color h4,
+.singlepage-section--has-text-color h5,
+.singlepage-section--has-text-color h6 {
+ color: inherit;
+}
+
+/* Override specifico per regole del tema padre tipo `.home.blog .entry-title` */
+.home.blog .singlepage-section--has-text-color .entry-title,
+.home.blog .singlepage-section--has-text-color .entry-title a,
+.singlepage-section--has-text-color .entry-title,
+.singlepage-section--has-text-color .entry-title a {
+ color: inherit !important;
+}
+
+.singlepage-section__inner {
+ max-width: 1140px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+.singlepage-section__bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-size: cover;
+ background-position: center center;
+ opacity: 1 !important;
+ filter: none !important;
+ mix-blend-mode: normal !important;
+ z-index: 0;
+}
+
+.singlepage-section__overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: #000;
+ opacity: 1;
+ z-index: 0;
+}
+
+.singlepage-section__content {
+ position: relative;
+ z-index: 1;
+}
+
+.singlepage-section--has-banner {
+ padding-bottom: 60px;
+}
+
+.singlepage-section__banner {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 60px;
+ z-index: 2;
+ width: 100%;
+ background: var(--tents-fixed-header-bg, #326a34);
+ color: #ffffff;
+ padding: 24px 20px;
+ text-align: center;
+}
+
+.singlepage-section__banner-text {
+ margin: 0;
+ font-weight: 700;
+ font-size: clamp(1.67rem, 1.33rem + 2vw, 2.67rem);
+ text-transform: uppercase;
+ line-height: 1.3;
+}
+
+.singlepage-section__buttons {
+ margin-top: 20px;
+}
+
+.singlepage-section__buttons .button {
+ display: inline-block;
+ margin-right: 12px;
+ margin-bottom: 12px;
+}
+
+.singlepage-section__stack-buttons {
+ position: absolute;
+ top: 44px;
+ right: max(20px, calc((100% - 1180px) / 2 + 20px));
+ z-index: 3;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 14px;
+ width: max-content;
+ max-width: min(300px, 42vw);
+}
+
+.singlepage-section__stack-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ width: 100%;
+ height: 44px;
+ min-height: 44px;
+ padding: 0 20px;
+ border-radius: 2px;
+ background-color: var(--section-button-bg);
+ color: var(--section-button-text);
+ font-size: 0.9375rem;
+ font-weight: 700;
+ line-height: 1.2;
+ text-align: center;
+ text-decoration: none;
+ text-transform: uppercase;
+ white-space: nowrap;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.singlepage-section--has-text-color .singlepage-section__stack-button {
+ color: var(--section-button-text);
+}
+
+.singlepage-section__stack-button:hover,
+.singlepage-section__stack-button:focus {
+ background-color: color-mix(in srgb, var(--section-button-bg) 70%, #ffffff 30%);
+ color: var(--section-button-text);
+}
+
+/* Hamburger menu: always collapsed until toggled */
+/* Header navigation / hamburger */
+.singlepage-nav {
+ text-align: right;
+}
+
+/* Bottone custom sempre visibile (non influisce sulla logica JS del tema padre) */
+.singlepage-menu-toggle {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ background: none;
+ border: 0;
+ padding: 0.75em 1em;
+}
+
+/* Contenitore menù: visibile di default (evitiamo di nasconderlo lato CSS
+ * per non rischiare di perdere il menù se lo script non gira).
+ * Si può comunque aggiungere una leggera transizione di opacità.
+ */
+.singlepage-menu-container {
+ opacity: 1;
+ visibility: visible;
+ max-height: none;
+ overflow: visible;
+ transform: none;
+ transition: opacity 180ms ease-out;
+ display: flex;
+ align-items: center; /* allinea verticalmente menu e icone */
+ justify-content: space-between;
+}
+
+.singlepage-social-links {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.75em;
+ margin-left: 1em;
+}
+
+.singlepage-social-link .icon {
+ width: 20px;
+ height: 20px;
+ fill: currentColor;
+}
+
+.singlepage-social-link--facebook {
+ color: #1877f2;
+}
+
+.singlepage-social-link--instagram {
+ color: #e4405f;
+}
+
+.singlepage-social-link--youtube {
+ color: #ff0000;
+}
+
+/* Sticky: usiamo la classe nativa site-navigation-fixed applicata dallo script di Twenty Seventeen */
+.navigation-top.site-navigation-fixed {
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: 0;
+ z-index: 1000;
+}
+
+body.has-tents-fixed-header #masthead {
+ margin: 0;
+ padding: 0;
+ background: transparent;
+}
+
+body.has-tents-fixed-header-hidden-branding .site-branding {
+ display: none;
+}
+
+body.has-tents-fixed-header .site-content-contain {
+ position: relative;
+ z-index: 5;
+ padding-top: var(--tents-fixed-header-height, 120px);
+ background-color: #fff;
+}
+
+body.has-tents-fixed-header #content,
+body.has-tents-fixed-header #primary,
+body.has-tents-fixed-header #main {
+ position: relative;
+ z-index: 1;
+ float: none;
+ width: 100%;
+ max-width: none;
+}
+
+body.has-tents-fixed-header .singlepage-section {
+ position: relative;
+ z-index: 1;
+ color: #222;
+}
+
+body.has-tents-fixed-header .navigation-top,
+body.has-tents-fixed-header .navigation-top.site-navigation-fixed {
+ position: fixed;
+ top: 0;
+ bottom: auto;
+ left: 0;
+ right: 0;
+ height: auto;
+ z-index: 1000;
+ width: 100%;
+ background: var(--tents-fixed-header-bg, #fff);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.12);
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+}
+
+body.admin-bar.has-tents-fixed-header .navigation-top,
+body.admin-bar.has-tents-fixed-header .navigation-top.site-navigation-fixed {
+ top: 32px;
+}
+
+body.has-tents-fixed-header .navigation-top .wrap {
+ max-width: none;
+ padding-left: 0;
+ padding-right: 0;
+}
+
+body.has-tents-fixed-header .singlepage-nav {
+ text-align: left;
+}
+
+body.has-tents-fixed-header .singlepage-nav > .menu-toggle {
+ display: none !important;
+}
+
+.singlepage-menu-toggle .icon-close {
+ display: none;
+}
+
+.singlepage-nav.is-open .singlepage-menu-toggle .icon-bars {
+ display: none;
+}
+
+.singlepage-nav.is-open .singlepage-menu-toggle .icon-close {
+ display: inline-block;
+}
+
+.tents-fixed-header {
+ background: var(--tents-fixed-header-bg, #fff);
+ color: var(--tents-fixed-header-text, #ffffff);
+}
+
+.tents-fixed-header__inner {
+ display: grid;
+ grid-template-columns: 1fr auto 1fr;
+ align-items: start;
+ gap: 18px;
+ max-width: 1180px;
+ margin: 0 auto;
+ padding: 10px 20px;
+}
+
+.tents-fixed-header__left,
+.tents-fixed-header__right {
+ display: flex;
+ min-width: 0;
+}
+
+.tents-fixed-header__left {
+ align-self: start;
+ justify-self: start;
+ align-items: flex-start;
+ justify-content: flex-start;
+}
+
+.tents-fixed-header__right {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: stretch;
+ align-self: start;
+ justify-self: end;
+ gap: 8px;
+ min-width: 0;
+ width: max-content;
+}
+
+.tents-fixed-header__cta-row {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ min-height: 36px;
+}
+
+.tents-fixed-header__brand {
+ display: flex;
+ align-self: center;
+ justify-self: center;
+ justify-content: center;
+ align-items: center;
+ min-width: 0;
+}
+
+.tents-fixed-header__logo-link {
+ display: inline-flex;
+ align-items: center;
+ line-height: 0;
+}
+
+.tents-fixed-header__logo {
+ display: block;
+ width: auto;
+ height: auto;
+ max-width: min(420px, 70vw);
+ max-height: var(--tents-fixed-header-logo-max-height, 58px);
+}
+
+.tents-fixed-header .tents-fixed-header__site-title {
+ color: var(--tents-fixed-header-text, #ffffff);
+ font-size: 1.1rem;
+ font-weight: 700;
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+.tents-fixed-header__actions {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+}
+
+.tents-fixed-header__social {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ width: 100%;
+ gap: 4px;
+}
+
+.tents-fixed-header__social-icons {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ gap: 4px;
+}
+
+.tents-fixed-header__social-label {
+ font-size: 0.8125rem;
+ font-weight: 600;
+ line-height: 1.2;
+ text-align: center;
+ white-space: nowrap;
+}
+
+.tents-fixed-header .singlepage-social-link,
+.tents-fixed-header .singlepage-social-link--facebook,
+.tents-fixed-header .singlepage-social-link--instagram,
+.tents-fixed-header .singlepage-social-link--youtube {
+ color: inherit;
+}
+
+.tents-fixed-header .singlepage-social-link .icon {
+ fill: currentColor;
+ width: 18px;
+ height: 18px;
+}
+
+.tents-fixed-header__cta {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 36px;
+ padding: 8px 14px;
+ border-radius: 2px;
+ font-size: 0.8125rem;
+ font-weight: 700;
+ line-height: 1.2;
+ text-decoration: none;
+ text-transform: uppercase;
+ white-space: nowrap;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.tents-fixed-header .tents-fixed-header__cta--primary,
+body.has-tents-fixed-header .navigation-top .tents-fixed-header .tents-fixed-header__cta--primary {
+ background-color: var(--tents-fixed-header-primary-cta-bg, #4d963d);
+ color: var(--tents-fixed-header-primary-cta-text, #fff);
+}
+
+.tents-fixed-header .tents-fixed-header__cta--primary:hover,
+body.has-tents-fixed-header .navigation-top .tents-fixed-header .tents-fixed-header__cta--primary:hover,
+.tents-fixed-header .tents-fixed-header__cta--primary:focus,
+body.has-tents-fixed-header .navigation-top .tents-fixed-header .tents-fixed-header__cta--primary:focus {
+ background-color: color-mix(in srgb, var(--tents-fixed-header-primary-cta-bg, #4d963d) 70%, #ffffff 30%);
+ color: var(--tents-fixed-header-primary-cta-text, #fff);
+}
+
+.tents-fixed-header .tents-fixed-header__cta--secondary,
+body.has-tents-fixed-header .navigation-top .tents-fixed-header .tents-fixed-header__cta--secondary {
+ background-color: var(--tents-fixed-header-secondary-cta-bg, transparent);
+ border: none;
+ color: var(--tents-fixed-header-secondary-cta-text, #ffffff);
+}
+
+.tents-fixed-header .tents-fixed-header__cta--secondary:hover,
+body.has-tents-fixed-header .navigation-top .tents-fixed-header .tents-fixed-header__cta--secondary:hover,
+.tents-fixed-header .tents-fixed-header__cta--secondary:focus,
+body.has-tents-fixed-header .navigation-top .tents-fixed-header .tents-fixed-header__cta--secondary:focus {
+ background-color: color-mix(in srgb, var(--tents-fixed-header-secondary-cta-bg, transparent) 70%, #ffffff 30%);
+ border: none;
+ color: var(--tents-fixed-header-secondary-cta-text, #ffffff);
+}
+
+body.has-tents-fixed-header .singlepage-menu-container {
+ max-width: 1180px;
+ margin: 0 auto;
+ padding: 0 20px 10px;
+ border-top: 1px solid rgba(0, 0, 0, 0.08);
+ justify-content: center;
+}
+
+body.has-tents-fixed-header .singlepage-menu-container .menu {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+
+body.has-tents-fixed-header .singlepage-menu-container .menu > li > a,
+body.has-tents-fixed-header .navigation-top .singlepage-menu-container .menu > li > a {
+ color: var(--tents-fixed-header-text, #ffffff);
+}
+
+body.has-tents-fixed-header .singlepage-menu-container .sub-menu a,
+body.has-tents-fixed-header .navigation-top .singlepage-menu-container .sub-menu a {
+ color: #222222;
+}
+
+body.has-tents-fixed-header .singlepage-menu-container .sub-menu li:hover > a,
+body.has-tents-fixed-header .singlepage-menu-container .sub-menu li.focus > a,
+body.has-tents-fixed-header .singlepage-menu-container .sub-menu a:hover,
+body.has-tents-fixed-header .singlepage-menu-container .sub-menu a:focus {
+ color: #ffffff;
+}
+
+@media (max-width: 600px) {
+ .singlepage-section {
+ padding: 60px 0;
+ }
+
+ .singlepage-section__stack-buttons {
+ right: max(16px, calc((100% - 1180px) / 2 + 20px));
+ max-width: min(240px, 58vw);
+ }
+
+ .singlepage-section__stack-button {
+ height: 40px;
+ min-height: 40px;
+ padding: 0 14px;
+ font-size: 0.875rem;
+ }
+}
+
+@media (max-width: 782px) {
+ body.admin-bar.has-tents-fixed-header .navigation-top,
+ body.admin-bar.has-tents-fixed-header .navigation-top.site-navigation-fixed {
+ top: 46px;
+ }
+}
+
+@media (max-width: 900px) {
+ .tents-fixed-header__inner {
+ grid-template-columns: 1fr;
+ grid-template-areas:
+ "brand"
+ "left"
+ "right";
+ gap: 10px 14px;
+ }
+
+ .tents-fixed-header__brand {
+ grid-area: brand;
+ }
+
+ .tents-fixed-header__left {
+ grid-area: left;
+ justify-self: center;
+ }
+
+ .tents-fixed-header__right {
+ grid-area: right;
+ justify-self: center;
+ align-items: center;
+ }
+}
+
+@media (max-width: 767px) {
+ .tents-fixed-header__inner {
+ padding: 8px 16px;
+ }
+
+ .tents-fixed-header__logo {
+ max-width: min(320px, 82vw);
+ }
+
+ .tents-fixed-header__right {
+ gap: 8px;
+ }
+
+ .tents-fixed-header__social-label,
+ .tents-fixed-header__cta--secondary {
+ display: none;
+ }
+
+ body.has-tents-fixed-header .singlepage-menu-container {
+ display: none;
+ padding: 0 16px 14px;
+ }
+
+ body.has-tents-fixed-header .singlepage-nav.is-open .singlepage-menu-container {
+ display: block;
+ }
+
+ body.has-tents-fixed-header .singlepage-menu-container .menu {
+ display: block;
+ }
+}
+
diff --git a/assets/js/singlepage.js b/assets/js/singlepage.js
new file mode 100644
index 0000000..53a2bc3
--- /dev/null
+++ b/assets/js/singlepage.js
@@ -0,0 +1,111 @@
+(function ($) {
+ $(function () {
+ // Hamburger menu toggle (works on all breakpoints) per il menu ad ancore.
+ var $nav = $('.singlepage-nav');
+ var $toggle = $('.singlepage-menu-toggle');
+
+ function updateFixedHeaderHeight() {
+ if (!$('body').hasClass('has-tents-fixed-header')) {
+ document.documentElement.style.removeProperty('--tents-fixed-header-height');
+ return;
+ }
+
+ var $fixedNavigation = $('.navigation-top');
+ var height = $fixedNavigation.length ? $fixedNavigation.outerHeight() : 0;
+
+ document.documentElement.style.setProperty('--tents-fixed-header-height', height + 'px');
+ }
+
+ updateFixedHeaderHeight();
+ $(window).on('load resize orientationchange', updateFixedHeaderHeight);
+
+ if ($('body').hasClass('has-tents-fixed-header')) {
+ $('.navigation-top').addClass('site-navigation-fixed');
+ }
+
+ $toggle.on('click', function () {
+ var expanded = $(this).attr('aria-expanded') === 'true';
+ $(this).attr('aria-expanded', expanded ? 'false' : 'true');
+ $nav.toggleClass('is-open');
+ updateFixedHeaderHeight();
+ });
+
+ function getSectionHashFromHref(href) {
+ if (!href) {
+ return '';
+ }
+
+ var hashIndex = href.indexOf('#');
+
+ if (hashIndex === -1) {
+ return '';
+ }
+
+ var hash = href.slice(hashIndex);
+
+ return hash.indexOf('#section-') === 0 ? hash : '';
+ }
+
+ function scrollToSection(hash, animate) {
+ var $target = $(hash);
+
+ if (!$target.length) {
+ return false;
+ }
+
+ updateFixedHeaderHeight();
+
+ var navHeight = $('.navigation-top').outerHeight() || 0;
+ var offset = navHeight + 20;
+ var targetTop = $target.offset().top - offset;
+ var $scrollEl = $('html, body');
+
+ if (animate) {
+ $scrollEl.animate({ scrollTop: targetTop }, 500);
+ } else {
+ $scrollEl.scrollTop(targetTop);
+ }
+
+ return true;
+ }
+
+ // Primo livello: sempre ancore sezione in homepage (href assoluto o relativo #section-*).
+ $('#top-menu > li > a').on('click', function (e) {
+ var sectionHash = getSectionHashFromHref(this.getAttribute('href'));
+
+ if (!sectionHash) {
+ return;
+ }
+
+ // Su pagine interne: lascia navigare a /#section-* (scroll dopo il load).
+ if (!$('body').hasClass('home')) {
+ return;
+ }
+
+ if (scrollToSection(sectionHash, true)) {
+ e.preventDefault();
+
+ if (window.history && window.history.replaceState) {
+ window.history.replaceState(null, '', sectionHash);
+ }
+ }
+ });
+
+ // Arrivo dalla home con hash (es. da una pagina interna) o refresh con #section-*.
+ function scrollToSectionHashOnLoad() {
+ var sectionHash = getSectionHashFromHref(window.location.hash);
+
+ if (!sectionHash || !$('body').hasClass('home')) {
+ return;
+ }
+
+ window.setTimeout(function () {
+ scrollToSection(sectionHash, false);
+ }, 0);
+ }
+
+ scrollToSectionHashOnLoad();
+ $(window).on('load', scrollToSectionHashOnLoad);
+ });
+})(jQuery);
+
diff --git a/front-page.php b/front-page.php
new file mode 100644
index 0000000..2c7df5c
--- /dev/null
+++ b/front-page.php
@@ -0,0 +1,56 @@
+
+
+
+
+ $section['id'],
+ 'slug' => $section['slug'],
+ 'title' => $section['title'],
+ 'content' => $section['content'],
+ 'page_id' => $section['page_id'],
+ 'index' => $index,
+ )
+ );
+
+ get_template_part( 'template-parts/section', 'generic' );
+ }
+
+ // Reset global post if it was altered.
+ wp_reset_postdata();
+ } else {
+ // Fallback: show default page content if no menu sections are available.
+ if ( have_posts() ) {
+ while ( have_posts() ) {
+ the_post();
+ get_template_part( 'template-parts/page/content', 'front-page' );
+ }
+ }
+ }
+ ?>
+
+
+
+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
+ */
+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 );
+
diff --git a/page.php b/page.php
new file mode 100644
index 0000000..4f5c6e3
--- /dev/null
+++ b/page.php
@@ -0,0 +1,33 @@
+
+
+
+
+ false );
+
+if ( ! empty( $fixed_header['enabled'] ) ) {
+ return;
+}
+
+require get_template_directory() . '/template-parts/header/header-image.php';
diff --git a/template-parts/navigation/navigation-top.php b/template-parts/navigation/navigation-top.php
new file mode 100644
index 0000000..28f5055
--- /dev/null
+++ b/template-parts/navigation/navigation-top.php
@@ -0,0 +1,185 @@
+ false );
+
+$facebook_url = get_theme_mod( 'tents_social_facebook_url' );
+$instagram_url = get_theme_mod( 'tents_social_instagram_url' );
+$youtube_url = get_theme_mod( 'tents_social_youtube_url' );
+$has_social = $facebook_url || $instagram_url || $youtube_url;
+
+?>
+
+
diff --git a/template-parts/page/content-page.php b/template-parts/page/content-page.php
new file mode 100644
index 0000000..f875f55
--- /dev/null
+++ b/template-parts/page/content-page.php
@@ -0,0 +1,35 @@
+
+
+>
+
+
+
+ '
' . esc_html__( 'Pages:', 'tents-singlepage-child' ),
+ 'after' => '
',
+ )
+ );
+ ?>
+
+
diff --git a/template-parts/section-generic.php b/template-parts/section-generic.php
new file mode 100644
index 0000000..773b088
--- /dev/null
+++ b/template-parts/section-generic.php
@@ -0,0 +1,137 @@
+ 1 ) {
+ $overlay_opacity_float = 1;
+}
+
+$overlay_rgb = array( 0, 0, 0 );
+if ( is_string( $overlay_color ) && preg_match( '/^#([0-9a-fA-F]{6})$/', $overlay_color, $m ) ) {
+ $hex = $m[1];
+ $overlay_rgb = array(
+ hexdec( substr( $hex, 0, 2 ) ),
+ hexdec( substr( $hex, 2, 2 ) ),
+ hexdec( substr( $hex, 4, 2 ) ),
+ );
+}
+$overlay_rgba = sprintf( 'rgba(%d,%d,%d,%.3f)', $overlay_rgb[0], $overlay_rgb[1], $overlay_rgb[2], $overlay_opacity_float );
+
+$style_parts = array();
+if ( $has_color ) {
+ $style_parts[] = 'background-color: ' . $bg_color;
+}
+if ( $has_text_color ) {
+ $style_parts[] = 'color: ' . $text_color;
+}
+$section_style_attr = ! empty( $style_parts ) ? ' style="' . esc_attr( implode( '; ', $style_parts ) ) . ';"' : '';
+?>
+
+>
+
+
+ 0 ) : ?>
+
+
+
+
+
+
+
+
+
+
+
+
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+