fix: Astra style conflicts, full-width, responsive hero images, header search
Plugin (viator-collector 1.8.1): - is_vc_page() now matches any Viator shortcode, so shortcode Pages (home) get the full-width no-sidebar canvas - load vc-design.css after Astra + inline overrides: strip Astra page-builder article padding (removes extra gap above hero), full-bleed containers, enforce design font inside .vc-app - vc_hero_img_html(): render hero from the WP media library with responsive srcset when the image is an attachment; used in listing + [viator_hero] ([viator_hero image_id=".."]) Theme (astra child): - remove the user/profile header item - working header search (expands, submits to the tours archive ?vc_q=) - load chrome.css after Astra + enforce design font inside .hoho - rebuild installable ZIP Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J4hNL1PSHxXbu94SCenpKj
This commit is contained in:
Binary file not shown.
@@ -63,6 +63,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- header search: expand, then submit ---------- */
|
||||||
|
var search = document.querySelector(".header__search");
|
||||||
|
if (search) {
|
||||||
|
var searchInput = search.querySelector(".header__search-input");
|
||||||
|
var searchBtn = search.querySelector(".header__search-btn");
|
||||||
|
if (searchInput && searchBtn) {
|
||||||
|
searchBtn.addEventListener("click", function (e) {
|
||||||
|
if (!search.classList.contains("is-open")) {
|
||||||
|
e.preventDefault();
|
||||||
|
search.classList.add("is-open");
|
||||||
|
searchInput.focus();
|
||||||
|
} else if (!searchInput.value.trim()) {
|
||||||
|
e.preventDefault();
|
||||||
|
search.classList.remove("is-open"); /* empty → collapse instead of submit */
|
||||||
|
}
|
||||||
|
/* open + has text → let the form submit to the tours archive (?vc_q=) */
|
||||||
|
});
|
||||||
|
document.addEventListener("click", function (e) {
|
||||||
|
if (!search.contains(e.target) && !searchInput.value.trim()) {
|
||||||
|
search.classList.remove("is-open");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- footer: back to top ---------- */
|
/* ---------- footer: back to top ---------- */
|
||||||
var toTop = document.querySelector(".ring-badge--top");
|
var toTop = document.querySelector(".ring-badge--top");
|
||||||
if (toTop) {
|
if (toTop) {
|
||||||
|
|||||||
@@ -17,19 +17,34 @@ add_action( 'wp_enqueue_scripts', function () {
|
|||||||
// Design typeface (same as the plugin's pages).
|
// Design typeface (same as the plugin's pages).
|
||||||
wp_enqueue_style( 'hoho-fonts', 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap', array(), null );
|
wp_enqueue_style( 'hoho-fonts', 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap', array(), null );
|
||||||
|
|
||||||
// Header/footer design, scoped to .hoho so it can't fight Astra.
|
// Header/footer design, scoped to .hoho so it can't fight Astra. Depend on
|
||||||
wp_enqueue_style( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.css', array( 'astra-parent' ), '1.0.0' );
|
// the Astra stylesheet (when present) so our rules load AFTER it and win ties.
|
||||||
|
$deps = array( 'astra-parent' );
|
||||||
|
if ( wp_style_is( 'astra-theme-css', 'registered' ) ) {
|
||||||
|
$deps[] = 'astra-theme-css';
|
||||||
|
}
|
||||||
|
wp_enqueue_style( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.css', $deps, '1.0.1' );
|
||||||
|
|
||||||
// Header interactions: burger, submenu, sticky, back-to-top.
|
// Header interactions: burger, submenu, sticky, back-to-top, search toggle.
|
||||||
wp_enqueue_script( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.js', array(), '1.0.0', true );
|
wp_enqueue_script( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.js', array(), '1.0.1', true );
|
||||||
|
|
||||||
// On pages without a full-bleed hero to overlay, the header renders solid and
|
|
||||||
// sticky (added by chrome.js as .is-solid) so it stays readable and doesn't
|
|
||||||
// cover content. Hero pages keep the transparent overlay + is-stuck on scroll.
|
|
||||||
wp_add_inline_style(
|
wp_add_inline_style(
|
||||||
'hoho-chrome',
|
'hoho-chrome',
|
||||||
'.hoho .site-header.is-solid{position:sticky;inset-block-start:0;padding-block:var(--sp-2);'
|
implode(
|
||||||
. 'background:rgba(0,0,0,.85);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);}'
|
'',
|
||||||
|
array(
|
||||||
|
// Solid, sticky header on pages without a hero to overlay (added by
|
||||||
|
// chrome.js as .is-solid) so it stays readable and doesn't cover content.
|
||||||
|
'.hoho .site-header.is-solid{position:sticky;inset-block-start:0;padding-block:var(--sp-2);background:rgba(0,0,0,.85);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);}',
|
||||||
|
// Force the design font over Astra inside the header/footer.
|
||||||
|
'.hoho,.hoho h1,.hoho h2,.hoho h3,.hoho p,.hoho a,.hoho span,.hoho li,.hoho button,.hoho input{font-family:"Plus Jakarta Sans",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}',
|
||||||
|
// Expanding header search field.
|
||||||
|
'.hoho .header__search{display:flex;align-items:center;gap:.25rem;}',
|
||||||
|
'.hoho .header__search-input{width:0;min-width:0;padding:0;border:0;outline:0;opacity:0;height:var(--control-h);border-radius:var(--r-pill);background:rgba(255,255,255,.15);color:#fff;transition:width .25s var(--ease),opacity .2s var(--ease),padding .25s var(--ease);}',
|
||||||
|
'.hoho .header__search.is-open .header__search-input{width:min(52vw,15rem);padding:0 1rem;opacity:1;}',
|
||||||
|
'.hoho .header__search-input::placeholder{color:rgba(255,255,255,.7);}',
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}, 20 );
|
}, 20 );
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ $hoho_archive = $hoho_archive ? $hoho_archive : home_url( '/' );
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="header__actions">
|
<div class="header__actions">
|
||||||
<button class="icon-btn" type="button" aria-label="<?php echo esc_attr__( 'Search', 'hoponhopoff' ); ?>">
|
<form class="header__search" role="search" method="get" action="<?php echo esc_url( $hoho_archive ); ?>">
|
||||||
<?php echo hoho_icon( 'search', 'icon--24' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<input class="header__search-input" type="search" name="vc_q" placeholder="<?php echo esc_attr__( 'Search tours…', 'hoponhopoff' ); ?>" aria-label="<?php echo esc_attr__( 'Search tours', 'hoponhopoff' ); ?>">
|
||||||
</button>
|
<button class="icon-btn header__search-btn" type="submit" aria-label="<?php echo esc_attr__( 'Search', 'hoponhopoff' ); ?>">
|
||||||
<a class="icon-btn" href="<?php echo esc_url( wp_login_url() ); ?>" aria-label="<?php echo esc_attr__( 'Account', 'hoponhopoff' ); ?>">
|
<?php echo hoho_icon( 'search', 'icon--24' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
<?php echo hoho_icon( 'user', 'icon--24' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
</button>
|
||||||
</a>
|
</form>
|
||||||
<a class="btn btn--accent header__cta" href="<?php echo esc_url( $hoho_archive ); ?>">
|
<a class="btn btn--accent header__cta" href="<?php echo esc_url( $hoho_archive ); ?>">
|
||||||
<span><?php echo esc_html__( 'Book now', 'hoponhopoff' ); ?></span>
|
<span><?php echo esc_html__( 'Book now', 'hoponhopoff' ); ?></span>
|
||||||
<?php echo hoho_icon( 'arrow-right' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo hoho_icon( 'arrow-right' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
|
|||||||
@@ -62,9 +62,18 @@ class VC_Display {
|
|||||||
|| is_tax( array( 'viator_destination', 'viator_tag', 'viator_category' ) ) ) {
|
|| is_tax( array( 'viator_destination', 'viator_tag', 'viator_category' ) ) ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// A Page hosting the full-listing shortcode also wants full width.
|
// Any Page hosting a Viator shortcode (hero, sections, listing, …) also
|
||||||
|
// wants the full-width, no-sidebar canvas.
|
||||||
$post = ( is_singular() ) ? get_post() : null;
|
$post = ( is_singular() ) ? get_post() : null;
|
||||||
return $post && has_shortcode( $post->post_content, 'viator_listing' );
|
if ( ! $post ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ( self::SHORTCODES as $shortcode ) {
|
||||||
|
if ( has_shortcode( $post->post_content, $shortcode ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,9 +143,15 @@ class VC_Display {
|
|||||||
// Design typeface.
|
// Design typeface.
|
||||||
wp_enqueue_style( 'vc-fonts', 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap', array(), null );
|
wp_enqueue_style( 'vc-fonts', 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap', array(), null );
|
||||||
|
|
||||||
// One scoped stylesheet (#vc-app) covers listing, single, and homepage
|
// One scoped stylesheet (.vc-app) covers listing, single, and homepage
|
||||||
// sections — ported from the "Hop On Hop Off" design.
|
// sections — ported from the "Hop On Hop Off" design. Depend on the Astra
|
||||||
wp_enqueue_style( 'vc-design', VC_PLUGIN_URL . 'assets/css/vc-design.css', array( 'vc-fonts' ), VC_VERSION );
|
// theme stylesheet (when present) so our rules load AFTER it and win ties.
|
||||||
|
$deps = array( 'vc-fonts' );
|
||||||
|
if ( wp_style_is( 'astra-theme-css', 'registered' ) ) {
|
||||||
|
$deps[] = 'astra-theme-css';
|
||||||
|
}
|
||||||
|
wp_enqueue_style( 'vc-design', VC_PLUGIN_URL . 'assets/css/vc-design.css', $deps, VC_VERSION );
|
||||||
|
wp_add_inline_style( 'vc-design', self::astra_overrides() );
|
||||||
|
|
||||||
// Front-end interactions: card rails, FAQ accordion, testimonials
|
// Front-end interactions: card rails, FAQ accordion, testimonials
|
||||||
// marquee, date field, and auto-submit on quick filter toggles.
|
// marquee, date field, and auto-submit on quick filter toggles.
|
||||||
@@ -146,6 +161,32 @@ class VC_Display {
|
|||||||
add_action( 'wp_footer', 'vc_print_icon_sprite' );
|
add_action( 'wp_footer', 'vc_print_icon_sprite' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS that neutralises Astra's content spacing/width on Viator pages and
|
||||||
|
* makes the design typography win over the theme. Injected after vc-design.css.
|
||||||
|
*/
|
||||||
|
private static function astra_overrides() {
|
||||||
|
return implode(
|
||||||
|
'',
|
||||||
|
array(
|
||||||
|
// Full-bleed: strip Astra's page-builder article padding/width so
|
||||||
|
// the hero and sections reach the viewport edges (fixes the extra
|
||||||
|
// top gap above the hero and the non-full-width sections).
|
||||||
|
'.vc-fullwidth .site-main>article,.vc-fullwidth .ast-page-builder-template .site-main>article{padding:0;margin:0;border:0;}',
|
||||||
|
'.vc-fullwidth #primary{margin:0;padding:0;}',
|
||||||
|
'.vc-fullwidth .site-content .ast-container{max-width:none;padding-inline:0;}',
|
||||||
|
'.vc-fullwidth .ast-container{max-width:none;}',
|
||||||
|
'.vc-fullwidth .entry-content{margin-block:0;}',
|
||||||
|
'.vc-fullwidth .site-content{padding:0;}',
|
||||||
|
// Typography: force the design font over Astra inside our scopes.
|
||||||
|
'.vc-app,.vc-app h1,.vc-app h2,.vc-app h3,.vc-app h4,.vc-app h5,.vc-app h6,'
|
||||||
|
. '.vc-app p,.vc-app a,.vc-app span,.vc-app li,.vc-app button,.vc-app input,'
|
||||||
|
. '.vc-app select,.vc-app textarea,.vc-app blockquote'
|
||||||
|
. '{font-family:"Plus Jakarta Sans",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read + sanitize the current filter state from the query string. Shared by
|
* Read + sanitize the current filter state from the query string. Shared by
|
||||||
* the query builder and the archive template so both stay in sync.
|
* the query builder and the archive template so both stay in sync.
|
||||||
|
|||||||
@@ -41,16 +41,25 @@ class VC_Sections {
|
|||||||
public static function hero( $atts ) {
|
public static function hero( $atts ) {
|
||||||
$atts = shortcode_atts(
|
$atts = shortcode_atts(
|
||||||
array(
|
array(
|
||||||
'title' => __( 'Set out on the journey.', 'viator-collector' ),
|
'title' => __( 'Set out on the journey.', 'viator-collector' ),
|
||||||
'eyebrow' => __( 'Tour & Travel', 'viator-collector' ),
|
'eyebrow' => __( 'Tour & Travel', 'viator-collector' ),
|
||||||
'image' => '',
|
'image' => '',
|
||||||
|
'image_id' => '', // WordPress media attachment ID (responsive).
|
||||||
),
|
),
|
||||||
$atts,
|
$atts,
|
||||||
self::HERO
|
self::HERO
|
||||||
);
|
);
|
||||||
|
|
||||||
$img = $atts['image'] ? $atts['image'] : vc_hero_image_url();
|
// Prefer a media-library image (responsive srcset); fall back to a URL,
|
||||||
if ( ! $img ) {
|
// the plugin's Hero image setting, then the bundled image.
|
||||||
|
$img = '';
|
||||||
|
if ( '' !== $atts['image_id'] ) {
|
||||||
|
$img = absint( $atts['image_id'] );
|
||||||
|
} elseif ( '' !== $atts['image'] ) {
|
||||||
|
$img = $atts['image'];
|
||||||
|
} elseif ( vc_hero_image_url() ) {
|
||||||
|
$img = vc_hero_image_url();
|
||||||
|
} else {
|
||||||
$img = vc_asset_url( 'img/hero.png' );
|
$img = vc_asset_url( 'img/hero.png' );
|
||||||
}
|
}
|
||||||
$archive = get_post_type_archive_link( 'viator_tour' );
|
$archive = get_post_type_archive_link( 'viator_tour' );
|
||||||
@@ -64,7 +73,7 @@ class VC_Sections {
|
|||||||
<div class="vc-app vc-sections">
|
<div class="vc-app vc-sections">
|
||||||
<section class="hero">
|
<section class="hero">
|
||||||
<div class="hero__media">
|
<div class="hero__media">
|
||||||
<img class="hero__img" src="<?php echo esc_url( $img ); ?>" alt="" fetchpriority="high">
|
<?php echo vc_hero_img_html( $img, 'hero__img', true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
<div class="hero__scrim" aria-hidden="true"></div>
|
<div class="hero__scrim" aria-hidden="true"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container hero__content">
|
<div class="container hero__content">
|
||||||
|
|||||||
@@ -506,6 +506,45 @@ function vc_asset_url( $rel ) {
|
|||||||
return VC_PLUGIN_URL . 'assets/' . ltrim( (string) $rel, '/' );
|
return VC_PLUGIN_URL . 'assets/' . ltrim( (string) $rel, '/' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hero <img> markup. When the source is a WordPress media item (an attachment
|
||||||
|
* ID, or a URL that resolves to one), it is rendered with wp_get_attachment_image
|
||||||
|
* so the browser gets responsive `srcset`/`sizes` and device-appropriate files.
|
||||||
|
* Anything else (external URLs, bundled fallbacks) falls back to a plain <img>.
|
||||||
|
*
|
||||||
|
* @param int|string $src Attachment ID or image URL.
|
||||||
|
* @param string $class CSS class.
|
||||||
|
* @param bool $eager Prioritise loading (above-the-fold hero).
|
||||||
|
*/
|
||||||
|
function vc_hero_img_html( $src, $class = 'hero__img', $eager = true ) {
|
||||||
|
$loading = $eager ? 'eager' : 'lazy';
|
||||||
|
|
||||||
|
$id = is_numeric( $src ) ? (int) $src : (int) attachment_url_to_postid( (string) $src );
|
||||||
|
if ( $id ) {
|
||||||
|
$img = wp_get_attachment_image(
|
||||||
|
$id,
|
||||||
|
'full',
|
||||||
|
false,
|
||||||
|
array(
|
||||||
|
'class' => $class,
|
||||||
|
'loading' => $loading,
|
||||||
|
'alt' => '',
|
||||||
|
'sizes' => '100vw',
|
||||||
|
'fetchpriority' => $eager ? 'high' : 'auto',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if ( $img ) {
|
||||||
|
return $img;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $src ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$fetch = $eager ? ' fetchpriority="high"' : '';
|
||||||
|
return '<img class="' . esc_attr( $class ) . '" src="' . esc_url( $src ) . '" alt="" loading="' . esc_attr( $loading ) . '"' . $fetch . '>';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print the "Hop On Hop Off" SVG icon sprite once per request. The sprite
|
* Print the "Hop On Hop Off" SVG icon sprite once per request. The sprite
|
||||||
* holds every <symbol id="i-…"> plus the #ringPathScroll circular text path
|
* holds every <symbol id="i-…"> plus the #ringPathScroll circular text path
|
||||||
|
|||||||
BIN
viator-collector/templates.zip
Normal file
BIN
viator-collector/templates.zip
Normal file
Binary file not shown.
@@ -82,7 +82,7 @@ if ( ! $vc_hero_img ) {
|
|||||||
?>
|
?>
|
||||||
<section class="hero hero--archive">
|
<section class="hero hero--archive">
|
||||||
<div class="hero__media">
|
<div class="hero__media">
|
||||||
<img class="hero__img" src="<?php echo esc_url( $vc_hero_img ); ?>" alt="" fetchpriority="high">
|
<?php echo vc_hero_img_html( $vc_hero_img, 'hero__img', true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
<div class="hero__scrim" aria-hidden="true"></div>
|
<div class="hero__scrim" aria-hidden="true"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ defined('ABSPATH') || exit;
|
|||||||
/**
|
/**
|
||||||
* Plugin Name: Viator Collector
|
* Plugin Name: Viator Collector
|
||||||
* Description: Import Viator tours using the Viator Partner API and display them with native WordPress post types, templates, and shortcodes.
|
* Description: Import Viator tours using the Viator Partner API and display them with native WordPress post types, templates, and shortcodes.
|
||||||
* Version: 1.8.0
|
* Version: 1.8.1
|
||||||
* Author: Amir Bagheri
|
* Author: Amir Bagheri
|
||||||
* License: GPL-2.0-or-later
|
* License: GPL-2.0-or-later
|
||||||
* Text Domain: viator-collector
|
* Text Domain: viator-collector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
define('VC_VERSION', '1.8.0');
|
define('VC_VERSION', '1.8.1');
|
||||||
define('VC_PLUGIN_FILE', __FILE__);
|
define('VC_PLUGIN_FILE', __FILE__);
|
||||||
define('VC_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
define('VC_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||||
define('VC_PLUGIN_URL', plugin_dir_url(__FILE__));
|
define('VC_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||||
|
|||||||
Reference in New Issue
Block a user