Initial commit: Weedops WordPress theme
Includes front-page, strain archive/single templates, header/footer, functions.php with custom post types, and base styles.
This commit is contained in:
commit
8eddfee34b
10 changed files with 1986 additions and 0 deletions
307
archive-strain.php
Normal file
307
archive-strain.php
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
<?php
|
||||
/**
|
||||
* Archive Strain Template
|
||||
* Strain catalog page — grid layout with filters.
|
||||
*
|
||||
* @package Weedops
|
||||
*/
|
||||
|
||||
get_header(); ?>
|
||||
|
||||
<main id="main" class="weedops-main">
|
||||
|
||||
<div class="strain-archive-wrap">
|
||||
|
||||
<!-- Page Header -->
|
||||
<header class="strain-archive-header">
|
||||
<h1 class="strain-archive-title">Strain Catalog</h1>
|
||||
<p class="strain-archive-subtitle">Browse our curated database of cannabis strains. Filter by type, potency, and effects.</p>
|
||||
</header>
|
||||
|
||||
<!-- Filter Bar -->
|
||||
<div class="strain-filters" id="strainFilters">
|
||||
<button class="strain-filter-btn active" data-filter="all">All Strains</button>
|
||||
<button class="strain-filter-btn" data-filter="indica">Indica</button>
|
||||
<button class="strain-filter-btn" data-filter="sativa">Sativa</button>
|
||||
<button class="strain-filter-btn" data-filter="hybrid">Hybrid</button>
|
||||
</div>
|
||||
|
||||
<!-- Results Count -->
|
||||
<div class="strain-results-meta">
|
||||
<?php
|
||||
global $wp_query;
|
||||
$total = $wp_query->found_posts;
|
||||
?>
|
||||
<span class="strain-results-count">
|
||||
<?php echo esc_html( $total ); ?> strain<?php echo $total !== 1 ? 's' : ''; ?> found
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Strain Grid -->
|
||||
<?php if ( have_posts() ) : ?>
|
||||
|
||||
<div class="strain-grid" id="strainGrid">
|
||||
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<?php
|
||||
$strain_type = get_post_meta( get_the_ID(), '_strain_type', true );
|
||||
$thc = get_post_meta( get_the_ID(), '_strain_thc', true );
|
||||
$cbd = get_post_meta( get_the_ID(), '_strain_cbd', true );
|
||||
$effects_raw = get_post_meta( get_the_ID(), '_strain_effects', true );
|
||||
$effects = array_filter( array_map( 'trim', explode( ',', $effects_raw ) ) );
|
||||
?>
|
||||
|
||||
<article
|
||||
id="strain-<?php the_ID(); ?>"
|
||||
class="strain-card"
|
||||
data-type="<?php echo esc_attr( $strain_type ); ?>"
|
||||
>
|
||||
<a href="<?php the_permalink(); ?>" class="strain-card__link" tabindex="-1" aria-hidden="true">
|
||||
<div class="strain-card__image">
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<?php the_post_thumbnail( 'medium', [ 'class' => 'strain-card__img' ] ); ?>
|
||||
<?php else : ?>
|
||||
<div class="strain-card__placeholder">
|
||||
<span class="strain-card__placeholder-icon">🌿</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="strain-card__badge strain-card__badge--<?php echo esc_attr( $strain_type ); ?>">
|
||||
<?php echo esc_html( ucfirst( $strain_type ? $strain_type : 'Unknown' ) ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="strain-card__body">
|
||||
<h2 class="strain-card__title">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h2>
|
||||
|
||||
<div class="strain-card__potency">
|
||||
<?php if ( $thc !== '' ) : ?>
|
||||
<div class="strain-card__stat strain-card__stat--thc">
|
||||
<span class="strain-card__stat-label">THC</span>
|
||||
<span class="strain-card__stat-value"><?php echo esc_html( $thc ); ?>%</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( $cbd !== '' ) : ?>
|
||||
<div class="strain-card__stat strain-card__stat--cbd">
|
||||
<span class="strain-card__stat-label">CBD</span>
|
||||
<span class="strain-card__stat-value"><?php echo esc_html( $cbd ); ?>%</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $effects ) ) : ?>
|
||||
<div class="strain-card__effects">
|
||||
<?php foreach ( array_slice( $effects, 0, 3 ) as $effect ) : ?>
|
||||
<span class="strain-card__effect-tag"><?php echo esc_html( $effect ); ?></span>
|
||||
<?php endforeach; ?>
|
||||
<?php if ( count( $effects ) > 3 ) : ?>
|
||||
<span class="strain-card__effect-more">+<?php echo count( $effects ) - 3; ?> more</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( get_the_excerpt() ) : ?>
|
||||
<p class="strain-card__excerpt"><?php echo esc_html( wp_trim_words( get_the_excerpt(), 15, '…' ) ); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?php the_permalink(); ?>" class="strain-card__cta">View Strain →</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<?php endwhile; ?>
|
||||
|
||||
</div><!-- .strain-grid -->
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="strain-pagination">
|
||||
<?php
|
||||
echo paginate_links( [
|
||||
'prev_text' => '← Previous',
|
||||
'next_text' => 'Next →',
|
||||
'before_page_number' => '<span class="screen-reader-text">Page </span>',
|
||||
] );
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<div class="strain-no-results">
|
||||
<span class="strain-no-results__icon">🔍</span>
|
||||
<h2>No strains found</h2>
|
||||
<p>Check back soon — we're always adding to the catalog.</p>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div><!-- .strain-archive-wrap -->
|
||||
|
||||
</main>
|
||||
|
||||
<style>
|
||||
/* ── Strain Archive / Catalog Styles ─────────────────── */
|
||||
|
||||
.strain-archive-wrap { max-width: 1200px; margin: 0 auto; padding: 2rem 1.5rem; }
|
||||
|
||||
/* Header */
|
||||
.strain-archive-header { text-align: center; margin-bottom: 2.5rem; }
|
||||
.strain-archive-title {
|
||||
font-size: 2.8rem; font-weight: 900; color: #1a3a1a;
|
||||
margin: 0 0 .5rem;
|
||||
background: linear-gradient(135deg, #2e7d32, #66bb6a);
|
||||
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.strain-archive-subtitle { color: #555; font-size: 1.1rem; margin: 0; }
|
||||
|
||||
/* Filter Bar */
|
||||
.strain-filters {
|
||||
display: flex; gap: .5rem; justify-content: center;
|
||||
flex-wrap: wrap; margin-bottom: 1.5rem;
|
||||
}
|
||||
.strain-filter-btn {
|
||||
padding: .5rem 1.4rem; border-radius: 999px;
|
||||
border: 2px solid #a5d6a7; background: #fff;
|
||||
color: #2e7d32; font-weight: 600; font-size: .9rem;
|
||||
cursor: pointer; transition: all .2s;
|
||||
}
|
||||
.strain-filter-btn:hover,
|
||||
.strain-filter-btn.active { background: #2e7d32; color: #fff; border-color: #2e7d32; }
|
||||
|
||||
/* Results meta */
|
||||
.strain-results-meta { text-align: right; font-size: .85rem; color: #777; margin-bottom: 1rem; }
|
||||
|
||||
/* Grid */
|
||||
.strain-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
/* Card */
|
||||
.strain-card {
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,.07);
|
||||
border: 1px solid #e8f5e9;
|
||||
transition: transform .2s, box-shadow .2s;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.strain-card:hover { transform: translateY(-4px); box-shadow: 0 8px 28px rgba(46,125,50,.15); }
|
||||
|
||||
/* Card Image */
|
||||
.strain-card__link { display: block; position: relative; }
|
||||
.strain-card__img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
|
||||
.strain-card__placeholder {
|
||||
width: 100%; aspect-ratio: 4/3;
|
||||
background: linear-gradient(135deg, #1a3a1a 0%, #2d5a2d 100%);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.strain-card__placeholder-icon { font-size: 3rem; }
|
||||
|
||||
/* Type Badge on card image */
|
||||
.strain-card__badge {
|
||||
position: absolute; top: .8rem; right: .8rem;
|
||||
padding: .25rem .75rem; border-radius: 999px;
|
||||
font-size: .7rem; font-weight: 700;
|
||||
text-transform: uppercase; letter-spacing: .08em;
|
||||
}
|
||||
.strain-card__badge--indica { background: #4a148c; color: #e1bee7; }
|
||||
.strain-card__badge--sativa { background: #e65100; color: #ffe0b2; }
|
||||
.strain-card__badge--hybrid { background: #1b5e20; color: #c8e6c9; }
|
||||
|
||||
/* Card Body */
|
||||
.strain-card__body { padding: 1.2rem; display: flex; flex-direction: column; flex: 1; }
|
||||
.strain-card__title { font-size: 1.25rem; font-weight: 800; margin: 0 0 .8rem; }
|
||||
.strain-card__title a { color: #1a3a1a; text-decoration: none; }
|
||||
.strain-card__title a:hover { color: #2e7d32; }
|
||||
|
||||
/* Potency stats */
|
||||
.strain-card__potency { display: flex; gap: .8rem; margin-bottom: .8rem; }
|
||||
.strain-card__stat {
|
||||
flex: 1; padding: .5rem .7rem; border-radius: 8px;
|
||||
display: flex; flex-direction: column; align-items: center;
|
||||
}
|
||||
.strain-card__stat--thc { background: #e8f5e9; }
|
||||
.strain-card__stat--cbd { background: #e3f2fd; }
|
||||
.strain-card__stat-label { font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: #666; }
|
||||
.strain-card__stat-value { font-size: 1.4rem; font-weight: 900; color: #1a3a1a; line-height: 1.1; }
|
||||
.strain-card__stat--thc .strain-card__stat-value { color: #2e7d32; }
|
||||
.strain-card__stat--cbd .strain-card__stat-value { color: #0277bd; }
|
||||
|
||||
/* Effect tags */
|
||||
.strain-card__effects { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .8rem; }
|
||||
.strain-card__effect-tag {
|
||||
background: #f1f8e9; color: #388e3c;
|
||||
border: 1px solid #c5e1a5;
|
||||
border-radius: 999px; padding: .15rem .6rem;
|
||||
font-size: .75rem; font-weight: 500;
|
||||
}
|
||||
.strain-card__effect-more { font-size: .75rem; color: #999; padding: .15rem .4rem; }
|
||||
|
||||
/* Excerpt */
|
||||
.strain-card__excerpt { font-size: .85rem; color: #666; line-height: 1.5; margin: 0 0 1rem; flex: 1; }
|
||||
|
||||
/* CTA */
|
||||
.strain-card__cta {
|
||||
display: inline-block; margin-top: auto;
|
||||
color: #2e7d32; font-weight: 700; font-size: .9rem;
|
||||
text-decoration: none; border-top: 1px solid #e8f5e9;
|
||||
padding-top: .8rem; transition: color .2s;
|
||||
}
|
||||
.strain-card__cta:hover { color: #1b5e20; }
|
||||
|
||||
/* Pagination */
|
||||
.strain-pagination { display: flex; justify-content: center; gap: .5rem; flex-wrap: wrap; }
|
||||
.strain-pagination .page-numbers {
|
||||
padding: .5rem 1rem; border-radius: 6px;
|
||||
border: 1px solid #a5d6a7; color: #2e7d32;
|
||||
text-decoration: none; font-weight: 600; transition: all .2s;
|
||||
}
|
||||
.strain-pagination .page-numbers.current,
|
||||
.strain-pagination .page-numbers:hover { background: #2e7d32; color: #fff; border-color: #2e7d32; }
|
||||
|
||||
/* No Results */
|
||||
.strain-no-results { text-align: center; padding: 4rem 2rem; color: #777; }
|
||||
.strain-no-results__icon { font-size: 3rem; display: block; margin-bottom: 1rem; }
|
||||
.strain-no-results h2 { color: #1a3a1a; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Simple client-side filter — filters visible cards by strain type without a page reload
|
||||
(function() {
|
||||
const btns = document.querySelectorAll('.strain-filter-btn');
|
||||
const cards = document.querySelectorAll('.strain-card');
|
||||
const meta = document.querySelector('.strain-results-count');
|
||||
|
||||
btns.forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
btns.forEach(function(b) { b.classList.remove('active'); });
|
||||
btn.classList.add('active');
|
||||
|
||||
const filter = btn.dataset.filter;
|
||||
let visible = 0;
|
||||
|
||||
cards.forEach(function(card) {
|
||||
if (filter === 'all' || card.dataset.type === filter) {
|
||||
card.style.display = '';
|
||||
visible++;
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
if (meta) {
|
||||
meta.textContent = visible + ' strain' + (visible !== 1 ? 's' : '') + ' found';
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
BIN
assets/img/hero-cannabis.jpg
Normal file
BIN
assets/img/hero-cannabis.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 382 KiB |
91
footer.php
Normal file
91
footer.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
</div><!-- .wo-container (opened in header.php) -->
|
||||
</main><!-- #main-content -->
|
||||
|
||||
<?php // ── Site Footer ───────────────────────────────────────── ?>
|
||||
<footer class="wo-footer" role="contentinfo">
|
||||
<div class="wo-container">
|
||||
|
||||
<div class="wo-footer__grid">
|
||||
|
||||
<?php // Brand column ?>
|
||||
<div class="wo-footer__brand">
|
||||
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" class="wo-logo" rel="home">
|
||||
<svg width="22" height="22" viewBox="0 0 28 28" fill="none" aria-hidden="true" focusable="false">
|
||||
<path d="M14 2C8.5 2 4 6.5 4 12c0 3.5 2 6.5 5 8.5L14 26l5-5.5c3-2 5-5 5-8.5C24 6.5 19.5 2 14 2z" fill="#4a9e68"/>
|
||||
<path d="M14 6c-3.3 0-6 2.7-6 6 0 2 1 3.8 2.5 4.8L14 20l3.5-3.2c1.5-1 2.5-2.8 2.5-4.8 0-3.3-2.7-6-6-6z" fill="#c8a951"/>
|
||||
</svg>
|
||||
Weed<span>ops</span>
|
||||
</a>
|
||||
<p class="wo-mt-2" style="color:rgba(255,255,255,0.6);font-size:0.85rem;max-width:220px;">
|
||||
<?php echo esc_html( get_bloginfo( 'description' ) ?: __( 'Cannabis industry product management and compliance platform.', 'weedops' ) ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php // Platform column ?>
|
||||
<div>
|
||||
<h4><?php esc_html_e( 'Platform', 'weedops' ); ?></h4>
|
||||
<ul>
|
||||
<li><a href="<?php echo esc_url( home_url( '/strains' ) ); ?>"><?php esc_html_e( 'Strain Database', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/products' ) ); ?>"><?php esc_html_e( 'Product Catalog', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/dispensaries' ) ); ?>"><?php esc_html_e( 'Dispensaries', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/compliance' ) ); ?>"><?php esc_html_e( 'Compliance', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/inventory' ) ); ?>"><?php esc_html_e( 'Inventory', 'weedops' ); ?></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php // Footer nav widget area or fallback links ?>
|
||||
<div>
|
||||
<h4><?php esc_html_e( 'Company', 'weedops' ); ?></h4>
|
||||
<?php if ( is_active_sidebar( 'footer-col-2' ) ) : ?>
|
||||
<?php dynamic_sidebar( 'footer-col-2' ); ?>
|
||||
<?php else : ?>
|
||||
<ul>
|
||||
<li><a href="<?php echo esc_url( home_url( '/about' ) ); ?>"><?php esc_html_e( 'About', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/blog' ) ); ?>"><?php esc_html_e( 'Blog', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/contact' ) ); ?>"><?php esc_html_e( 'Contact', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/careers' ) ); ?>"><?php esc_html_e( 'Careers', 'weedops' ); ?></a></li>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php // Legal column ?>
|
||||
<div>
|
||||
<h4><?php esc_html_e( 'Legal', 'weedops' ); ?></h4>
|
||||
<ul>
|
||||
<li><a href="<?php echo esc_url( home_url( '/privacy-policy' ) ); ?>"><?php esc_html_e( 'Privacy Policy', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/terms' ) ); ?>"><?php esc_html_e( 'Terms of Service', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/age-verification' ) ); ?>"><?php esc_html_e( 'Age Verification', 'weedops' ); ?></a></li>
|
||||
<li><a href="<?php echo esc_url( home_url( '/compliance-disclosure' ) ); ?>"><?php esc_html_e( 'Compliance Disclosure', 'weedops' ); ?></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div><!-- .wo-footer__grid -->
|
||||
|
||||
<div class="wo-footer__bottom">
|
||||
<span>
|
||||
© <?php echo esc_html( gmdate( 'Y' ) ); ?>
|
||||
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" style="color:rgba(255,255,255,0.7);">Weedops</a>.
|
||||
<?php esc_html_e( 'All rights reserved.', 'weedops' ); ?>
|
||||
</span>
|
||||
<span style="color:rgba(255,255,255,0.4);font-size:0.75rem;">
|
||||
<?php esc_html_e( 'For use in jurisdictions where cannabis is legal. Must be 21+.', 'weedops' ); ?>
|
||||
</span>
|
||||
<?php
|
||||
// Optional: footer nav
|
||||
wp_nav_menu( [
|
||||
'theme_location' => 'footer',
|
||||
'container' => false,
|
||||
'depth' => 1,
|
||||
'fallback_cb' => false,
|
||||
'menu_class' => 'wo-footer__nav',
|
||||
] );
|
||||
?>
|
||||
</div><!-- .wo-footer__bottom -->
|
||||
|
||||
</div><!-- .wo-container -->
|
||||
</footer>
|
||||
|
||||
<?php wp_footer(); ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
153
front-page.php
Normal file
153
front-page.php
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
/**
|
||||
* Weedops — Front Page Template
|
||||
*
|
||||
* Full-width hero with photography-style imagery,
|
||||
* followed by featured sections.
|
||||
*
|
||||
* @package Weedops
|
||||
*/
|
||||
|
||||
get_header();
|
||||
?>
|
||||
|
||||
</div><!-- close .wo-container from header -->
|
||||
</main><!-- close .wo-main from header — we'll reopen after hero -->
|
||||
|
||||
<?php // ── Hero Section ──────────────────────────────────────── ?>
|
||||
<section class="wo-hero" role="banner" aria-label="<?php esc_attr_e( 'Welcome to Weedops', 'weedops' ); ?>">
|
||||
<div class="wo-hero__overlay"></div>
|
||||
<div class="wo-hero__content">
|
||||
<span class="wo-hero__eyebrow"><?php esc_html_e( 'Cannabis Intelligence Platform', 'weedops' ); ?></span>
|
||||
<h1 class="wo-hero__title">
|
||||
<?php esc_html_e( 'Smarter Product Management for the Cannabis Industry', 'weedops' ); ?>
|
||||
</h1>
|
||||
<p class="wo-hero__subtitle">
|
||||
<?php esc_html_e( 'Compliance tracking, strain databases, and inventory tools built for dispensaries, growers, and brands.', 'weedops' ); ?>
|
||||
</p>
|
||||
<div class="wo-hero__actions">
|
||||
<a href="<?php echo esc_url( home_url( '/strains' ) ); ?>" class="wo-btn wo-btn--primary wo-btn--lg">
|
||||
<?php esc_html_e( 'Browse Strains', 'weedops' ); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( home_url( '/products' ) ); ?>" class="wo-btn wo-btn--ghost wo-btn--lg">
|
||||
<?php esc_html_e( 'View Products', 'weedops' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php // ── Features Grid ─────────────────────────────────────── ?>
|
||||
<main class="wo-main" id="main-content" role="main">
|
||||
<div class="wo-container">
|
||||
|
||||
<section class="wo-section wo-mt-3">
|
||||
<div class="wo-text-center wo-mb-3">
|
||||
<h2><?php esc_html_e( 'Built for Cannabis Professionals', 'weedops' ); ?></h2>
|
||||
<p class="wo-text-muted" style="max-width:600px;margin:0.75rem auto 0;">
|
||||
<?php esc_html_e( 'Everything you need to manage products, stay compliant, and grow your operation.', 'weedops' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="wo-grid wo-grid--3">
|
||||
|
||||
<div class="wo-card wo-text-center" style="padding:2rem;">
|
||||
<div class="wo-feature-icon" style="font-size:2.4rem;margin-bottom:1rem;">🌿</div>
|
||||
<h3 style="font-size:1.15rem;margin-bottom:0.5rem;">
|
||||
<?php esc_html_e( 'Strain Database', 'weedops' ); ?>
|
||||
</h3>
|
||||
<p class="wo-text-muted" style="font-size:0.9rem;">
|
||||
<?php esc_html_e( 'Comprehensive profiles with THC/CBD levels, terpenes, effects, and grow data.', 'weedops' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="wo-card wo-text-center" style="padding:2rem;">
|
||||
<div class="wo-feature-icon" style="font-size:2.4rem;margin-bottom:1rem;">📋</div>
|
||||
<h3 style="font-size:1.15rem;margin-bottom:0.5rem;">
|
||||
<?php esc_html_e( 'Compliance Tracking', 'weedops' ); ?>
|
||||
</h3>
|
||||
<p class="wo-text-muted" style="font-size:0.9rem;">
|
||||
<?php esc_html_e( 'Lab results, COA management, and regulatory status for every product in your catalog.', 'weedops' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="wo-card wo-text-center" style="padding:2rem;">
|
||||
<div class="wo-feature-icon" style="font-size:2.4rem;margin-bottom:1rem;">📦</div>
|
||||
<h3 style="font-size:1.15rem;margin-bottom:0.5rem;">
|
||||
<?php esc_html_e( 'Inventory Management', 'weedops' ); ?>
|
||||
</h3>
|
||||
<p class="wo-text-muted" style="font-size:0.9rem;">
|
||||
<?php esc_html_e( 'Real-time stock levels, batch tracking, and automated low-stock alerts.', 'weedops' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php // ── Latest Strains ────────────────────────────────────── ?>
|
||||
<?php
|
||||
$strains = new WP_Query( [
|
||||
'post_type' => 'wo_strain',
|
||||
'posts_per_page' => 6,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
] );
|
||||
|
||||
if ( $strains->have_posts() ) :
|
||||
?>
|
||||
<section class="wo-section wo-mt-3">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap;gap:0.5rem;">
|
||||
<h2><?php esc_html_e( 'Latest Strains', 'weedops' ); ?></h2>
|
||||
<a href="<?php echo esc_url( home_url( '/strains' ) ); ?>" class="wo-btn wo-btn--outline" style="font-size:0.85rem;">
|
||||
<?php esc_html_e( 'View All →', 'weedops' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="wo-grid wo-grid--3">
|
||||
<?php while ( $strains->have_posts() ) : $strains->the_post(); ?>
|
||||
<article <?php post_class( 'wo-card' ); ?>>
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<a href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
|
||||
<?php the_post_thumbnail( 'medium', [
|
||||
'class' => 'wo-card__img',
|
||||
'loading' => 'lazy',
|
||||
'style' => 'width:100%;height:180px;object-fit:cover;border-radius:8px;margin-bottom:1rem;',
|
||||
] ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wo-card__meta" style="margin-bottom:0.5rem;">
|
||||
<?php
|
||||
$types = get_the_terms( get_the_ID(), 'wo_strain_type' );
|
||||
if ( $types && ! is_wp_error( $types ) ) {
|
||||
foreach ( $types as $t ) {
|
||||
weedops_strain_badge( $t->slug );
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<h3 style="font-size:1.05rem;margin-bottom:0.4rem;">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h3>
|
||||
|
||||
<?php $canna = weedops_get_cannabinoid_str( get_the_ID() ); ?>
|
||||
<?php if ( $canna ) : ?>
|
||||
<p style="font-size:0.82rem;font-weight:600;color:var(--wo-green-mid);margin-bottom:0.5rem;">
|
||||
<?php echo esc_html( $canna ); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?php the_permalink(); ?>" class="wo-btn wo-btn--outline" style="font-size:0.8rem;padding:0.4rem 0.8rem;">
|
||||
<?php esc_html_e( 'View Details', 'weedops' ); ?>
|
||||
</a>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php
|
||||
wp_reset_postdata();
|
||||
endif;
|
||||
?>
|
||||
|
||||
<?php
|
||||
get_footer();
|
||||
192
functions.php
Normal file
192
functions.php
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
<?php
|
||||
/**
|
||||
* Weedops Theme Functions
|
||||
*
|
||||
* Cannabis industry platform — theme setup, enqueues, custom post types,
|
||||
* taxonomies, REST API extensions, and helper utilities.
|
||||
*
|
||||
* @package Weedops
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
define( 'WEEDOPS_VERSION', '1.0.0' );
|
||||
define( 'WEEDOPS_DIR', get_template_directory() );
|
||||
define( 'WEEDOPS_URI', get_template_directory_uri() );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Theme Setup
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_setup(): void {
|
||||
load_theme_textdomain( 'weedops', WEEDOPS_DIR . '/languages' );
|
||||
|
||||
add_theme_support( 'title-tag' );
|
||||
add_theme_support( 'post-thumbnails' );
|
||||
add_theme_support( 'html5', [ 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'style', 'script' ] );
|
||||
add_theme_support( 'customize-selective-refresh-widgets' );
|
||||
add_theme_support( 'woocommerce' );
|
||||
add_theme_support( 'wc-product-gallery-zoom' );
|
||||
add_theme_support( 'wc-product-gallery-lightbox' );
|
||||
add_theme_support( 'wc-product-gallery-slider' );
|
||||
|
||||
register_nav_menus( [
|
||||
'primary' => __( 'Primary Navigation', 'weedops' ),
|
||||
'footer' => __( 'Footer Navigation', 'weedops' ),
|
||||
'account' => __( 'Account Menu', 'weedops' ),
|
||||
] );
|
||||
}
|
||||
add_action( 'after_setup_theme', 'weedops_setup' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Scripts & Styles
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_enqueue_assets(): void {
|
||||
// Google Fonts — Inter
|
||||
wp_enqueue_style(
|
||||
'weedops-fonts',
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap',
|
||||
[],
|
||||
null
|
||||
);
|
||||
|
||||
// Main stylesheet
|
||||
wp_enqueue_style(
|
||||
'weedops-style',
|
||||
get_stylesheet_uri(),
|
||||
[ 'weedops-fonts' ],
|
||||
WEEDOPS_VERSION
|
||||
);
|
||||
|
||||
// Main JS bundle
|
||||
wp_enqueue_script(
|
||||
'weedops-main',
|
||||
WEEDOPS_URI . '/assets/js/main.js',
|
||||
[],
|
||||
WEEDOPS_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
// Pass data to JS
|
||||
wp_localize_script( 'weedops-main', 'WeedopsData', [
|
||||
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
|
||||
'restUrl' => esc_url_raw( rest_url( 'weedops/v1/' ) ),
|
||||
'nonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'siteUrl' => get_site_url(),
|
||||
'isLoggedIn'=> is_user_logged_in(),
|
||||
] );
|
||||
}
|
||||
add_action( 'wp_enqueue_scripts', 'weedops_enqueue_assets' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Custom Post Types, Taxonomies & Meta Fields
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// Post types, taxonomies, and meta field registration live in their own file.
|
||||
require_once WEEDOPS_DIR . '/inc/custom-post-types.php';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Widget Areas
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_register_sidebars(): void {
|
||||
$sidebars = [
|
||||
[ 'id' => 'sidebar-main', 'name' => __( 'Main Sidebar', 'weedops' ) ],
|
||||
[ 'id' => 'sidebar-catalog', 'name' => __( 'Catalog Sidebar', 'weedops' ) ],
|
||||
[ 'id' => 'footer-col-1', 'name' => __( 'Footer Column 1', 'weedops' ) ],
|
||||
[ 'id' => 'footer-col-2', 'name' => __( 'Footer Column 2', 'weedops' ) ],
|
||||
[ 'id' => 'footer-col-3', 'name' => __( 'Footer Column 3', 'weedops' ) ],
|
||||
];
|
||||
|
||||
foreach ( $sidebars as $s ) {
|
||||
register_sidebar( [
|
||||
'id' => $s['id'],
|
||||
'name' => $s['name'],
|
||||
'before_widget' => '<div id="%1$s" class="wo-widget %2$s">',
|
||||
'after_widget' => '</div>',
|
||||
'before_title' => '<h4 class="wo-widget__title">',
|
||||
'after_title' => '</h4>',
|
||||
] );
|
||||
}
|
||||
}
|
||||
add_action( 'widgets_init', 'weedops_register_sidebars' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Helper Functions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Render a strain type badge.
|
||||
*
|
||||
* @param string $type indica | sativa | hybrid | cbd
|
||||
* @param bool $echo Echo or return.
|
||||
*/
|
||||
function weedops_strain_badge( string $type, bool $echo = true ): string {
|
||||
$label = ucfirst( $type );
|
||||
$class = 'wo-badge wo-badge--' . sanitize_html_class( strtolower( $type ) );
|
||||
$html = sprintf( '<span class="%s">%s</span>', esc_attr( $class ), esc_html( $label ) );
|
||||
if ( $echo ) echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return formatted THC/CBD string for a strain.
|
||||
*
|
||||
* @param int $post_id
|
||||
*/
|
||||
function weedops_get_cannabinoid_str( int $post_id ): string {
|
||||
$thc = get_post_meta( $post_id, 'wo_thc_percent', true );
|
||||
$cbd = get_post_meta( $post_id, 'wo_cbd_percent', true );
|
||||
$parts = [];
|
||||
if ( $thc !== '' ) $parts[] = 'THC ' . number_format( (float) $thc, 1 ) . '%';
|
||||
if ( $cbd !== '' ) $parts[] = 'CBD ' . number_format( (float) $cbd, 1 ) . '%';
|
||||
return implode( ' · ', $parts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a product has a valid COA (lab test certificate).
|
||||
*/
|
||||
function weedops_has_valid_coa( int $post_id ): bool {
|
||||
$coa = get_post_meta( $post_id, 'wo_coa_url', true );
|
||||
$tested = get_post_meta( $post_id, 'wo_lab_tested', true );
|
||||
return ! empty( $coa ) && (bool) $tested;
|
||||
}
|
||||
|
||||
/**
|
||||
* Age-gate: returns true if the user has confirmed they are 21+.
|
||||
* Stored in a session cookie.
|
||||
*/
|
||||
function weedops_age_verified(): bool {
|
||||
return ! empty( $_COOKIE['wo_age_verified'] );
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Age Verification AJAX Handler
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_ajax_age_verify(): void {
|
||||
check_ajax_referer( 'wo_age_verify', 'nonce' );
|
||||
setcookie( 'wo_age_verified', '1', time() + ( 30 * DAY_IN_SECONDS ), COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true );
|
||||
wp_send_json_success( [ 'verified' => true ] );
|
||||
}
|
||||
add_action( 'wp_ajax_nopriv_wo_age_verify', 'weedops_ajax_age_verify' );
|
||||
add_action( 'wp_ajax_wo_age_verify', 'weedops_ajax_age_verify' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Title Tag
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_document_title_parts( array $parts ): array {
|
||||
$parts['tagline'] = get_bloginfo( 'description' );
|
||||
return $parts;
|
||||
}
|
||||
add_filter( 'document_title_parts', 'weedops_document_title_parts' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Excerpt length
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
add_filter( 'excerpt_length', fn() => 30 );
|
||||
add_filter( 'excerpt_more', fn() => '…' );
|
||||
91
header.php
Normal file
91
header.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<meta charset="<?php bloginfo( 'charset' ); ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#1a3d2b">
|
||||
<link rel="profile" href="https://gmpg.org/xfn/11">
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
|
||||
<body <?php body_class(); ?>>
|
||||
|
||||
<?php wp_body_open(); ?>
|
||||
|
||||
<?php // ── Age-gate compliance notice ─────────────────────────── ?>
|
||||
<div class="wo-age-notice" role="note" aria-label="<?php esc_attr_e( 'Age compliance notice', 'weedops' ); ?>">
|
||||
<?php esc_html_e( '21+ only. Cannabis products are for adults. Comply with your local laws.', 'weedops' ); ?>
|
||||
</div>
|
||||
|
||||
<?php // ── Site Header ───────────────────────────────────────── ?>
|
||||
<header class="wo-header" role="banner">
|
||||
<div class="wo-container">
|
||||
<div class="wo-header__inner">
|
||||
|
||||
<?php // Logo ?>
|
||||
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" class="wo-logo" rel="home">
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" aria-hidden="true" focusable="false">
|
||||
<path d="M14 2C8.5 2 4 6.5 4 12c0 3.5 2 6.5 5 8.5L14 26l5-5.5c3-2 5-5 5-8.5C24 6.5 19.5 2 14 2z" fill="#4a9e68"/>
|
||||
<path d="M14 6c-3.3 0-6 2.7-6 6 0 2 1 3.8 2.5 4.8L14 20l3.5-3.2c1.5-1 2.5-2.8 2.5-4.8 0-3.3-2.7-6-6-6z" fill="#c8a951"/>
|
||||
</svg>
|
||||
Weed<span>ops</span>
|
||||
</a>
|
||||
|
||||
<?php // Primary navigation ?>
|
||||
<nav class="wo-nav" id="wo-primary-nav" role="navigation" aria-label="<?php esc_attr_e( 'Primary', 'weedops' ); ?>">
|
||||
<?php
|
||||
wp_nav_menu( [
|
||||
'theme_location' => 'primary',
|
||||
'menu_class' => '',
|
||||
'container' => false,
|
||||
'fallback_cb' => 'weedops_fallback_nav',
|
||||
] );
|
||||
?>
|
||||
</nav>
|
||||
|
||||
<?php // Header actions ?>
|
||||
<div class="wo-header__actions">
|
||||
<?php if ( is_user_logged_in() ) : ?>
|
||||
<a href="<?php echo esc_url( get_dashboard_url() ); ?>" class="wo-btn wo-btn--outline" style="font-size:0.82rem;padding:0.45rem 0.9rem;">
|
||||
<?php esc_html_e( 'Dashboard', 'weedops' ); ?>
|
||||
</a>
|
||||
<?php else : ?>
|
||||
<a href="<?php echo esc_url( wp_login_url() ); ?>" class="wo-btn wo-btn--primary" style="font-size:0.82rem;padding:0.45rem 0.9rem;">
|
||||
<?php esc_html_e( 'Sign In', 'weedops' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php // Mobile hamburger ?>
|
||||
<button
|
||||
class="wo-nav-toggle"
|
||||
aria-controls="wo-primary-nav"
|
||||
aria-expanded="false"
|
||||
aria-label="<?php esc_attr_e( 'Toggle navigation', 'weedops' ); ?>"
|
||||
style="display:none;background:none;border:none;cursor:pointer;padding:0.5rem;"
|
||||
>
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" aria-hidden="true">
|
||||
<rect y="3" width="22" height="2.5" rx="1.25" fill="#fff"/>
|
||||
<rect y="10" width="22" height="2.5" rx="1.25" fill="#fff"/>
|
||||
<rect y="17" width="22" height="2.5" rx="1.25" fill="#fff"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div><!-- .wo-header__inner -->
|
||||
</div><!-- .wo-container -->
|
||||
</header>
|
||||
|
||||
<?php
|
||||
// Fallback nav when no menu is assigned
|
||||
function weedops_fallback_nav(): void {
|
||||
echo '<ul>';
|
||||
echo '<li><a href="' . esc_url( home_url( '/' ) ) . '">' . esc_html__( 'Home', 'weedops' ) . '</a></li>';
|
||||
echo '<li><a href="' . esc_url( home_url( '/strains' ) ) . '">' . esc_html__( 'Strains', 'weedops' ) . '</a></li>';
|
||||
echo '<li><a href="' . esc_url( home_url( '/products' ) ) . '">' . esc_html__( 'Products', 'weedops' ) . '</a></li>';
|
||||
echo '<li><a href="' . esc_url( home_url( '/dispensaries' ) ) . '">' . esc_html__( 'Dispensaries', 'weedops' ) . '</a></li>';
|
||||
echo '</ul>';
|
||||
}
|
||||
?>
|
||||
|
||||
<main class="wo-main" id="main-content" role="main">
|
||||
<div class="wo-container">
|
||||
391
inc/custom-post-types.php
Normal file
391
inc/custom-post-types.php
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
<?php
|
||||
/**
|
||||
* Weedops Custom Post Types, Taxonomies & Meta Fields
|
||||
*
|
||||
* Registers the 'strain' post type (and related CPTs) with full
|
||||
* meta support: THC %, CBD %, strain type, effects, and more.
|
||||
*
|
||||
* @package Weedops
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Post Types
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_register_post_types(): void {
|
||||
|
||||
// ── Strains ──────────────────────────────────────────────────────────────
|
||||
register_post_type( 'wo_strain', [
|
||||
'label' => __( 'Strains', 'weedops' ),
|
||||
'labels' => [
|
||||
'name' => __( 'Strains', 'weedops' ),
|
||||
'singular_name' => __( 'Strain', 'weedops' ),
|
||||
'add_new' => __( 'Add New', 'weedops' ),
|
||||
'add_new_item' => __( 'Add New Strain', 'weedops' ),
|
||||
'edit_item' => __( 'Edit Strain', 'weedops' ),
|
||||
'new_item' => __( 'New Strain', 'weedops' ),
|
||||
'view_item' => __( 'View Strain', 'weedops' ),
|
||||
'search_items' => __( 'Search Strains', 'weedops' ),
|
||||
'not_found' => __( 'No strains found', 'weedops' ),
|
||||
'not_found_in_trash' => __( 'No strains in trash', 'weedops' ),
|
||||
'menu_name' => __( 'Strains', 'weedops' ),
|
||||
],
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => true,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'strains',
|
||||
'menu_icon' => 'dashicons-palmtree',
|
||||
'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields', 'revisions' ],
|
||||
'has_archive' => true,
|
||||
'rewrite' => [ 'slug' => 'strains', 'with_front' => false ],
|
||||
'capability_type' => 'post',
|
||||
'map_meta_cap' => true,
|
||||
] );
|
||||
|
||||
// ── Cannabis Products ─────────────────────────────────────────────────────
|
||||
register_post_type( 'wo_product', [
|
||||
'label' => __( 'Cannabis Products', 'weedops' ),
|
||||
'labels' => [
|
||||
'name' => __( 'Cannabis Products', 'weedops' ),
|
||||
'singular_name' => __( 'Cannabis Product', 'weedops' ),
|
||||
'add_new_item' => __( 'Add New Product', 'weedops' ),
|
||||
'edit_item' => __( 'Edit Product', 'weedops' ),
|
||||
'not_found' => __( 'No products found', 'weedops' ),
|
||||
],
|
||||
'public' => true,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'cannabis-products',
|
||||
'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ],
|
||||
'menu_icon' => 'dashicons-archive',
|
||||
'has_archive' => true,
|
||||
'rewrite' => [ 'slug' => 'products', 'with_front' => false ],
|
||||
'capability_type' => 'post',
|
||||
] );
|
||||
|
||||
// ── Compliance Records ────────────────────────────────────────────────────
|
||||
register_post_type( 'wo_compliance', [
|
||||
'label' => __( 'Compliance Records', 'weedops' ),
|
||||
'labels' => [
|
||||
'name' => __( 'Compliance Records', 'weedops' ),
|
||||
'singular_name' => __( 'Compliance Record', 'weedops' ),
|
||||
'add_new_item' => __( 'Add Record', 'weedops' ),
|
||||
],
|
||||
'public' => false,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => true,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'compliance',
|
||||
'supports' => [ 'title', 'custom-fields' ],
|
||||
'menu_icon' => 'dashicons-shield',
|
||||
'capability_type' => 'post',
|
||||
] );
|
||||
|
||||
// ── Dispensaries / Locations ──────────────────────────────────────────────
|
||||
register_post_type( 'wo_dispensary', [
|
||||
'label' => __( 'Dispensaries', 'weedops' ),
|
||||
'public' => true,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'dispensaries',
|
||||
'supports' => [ 'title', 'editor', 'thumbnail', 'custom-fields' ],
|
||||
'menu_icon' => 'dashicons-location-alt',
|
||||
'has_archive' => true,
|
||||
'rewrite' => [ 'slug' => 'dispensaries', 'with_front' => false ],
|
||||
] );
|
||||
}
|
||||
add_action( 'init', 'weedops_register_post_types' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Taxonomies
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_register_taxonomies(): void {
|
||||
|
||||
// ── Strain Type: indica / sativa / hybrid / cbd ───────────────────────────
|
||||
register_taxonomy( 'wo_strain_type', [ 'wo_strain', 'wo_product' ], [
|
||||
'label' => __( 'Strain Type', 'weedops' ),
|
||||
'labels' => [
|
||||
'name' => __( 'Strain Types', 'weedops' ),
|
||||
'singular_name' => __( 'Strain Type', 'weedops' ),
|
||||
'add_new_item' => __( 'Add Strain Type', 'weedops' ),
|
||||
'search_items' => __( 'Search Types', 'weedops' ),
|
||||
],
|
||||
'hierarchical' => true,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'strain-types',
|
||||
'rewrite' => [ 'slug' => 'strain-type' ],
|
||||
'show_admin_column' => true,
|
||||
] );
|
||||
|
||||
// ── Effects (relaxed, euphoric, creative, …) ──────────────────────────────
|
||||
register_taxonomy( 'wo_effect', [ 'wo_strain', 'wo_product' ], [
|
||||
'label' => __( 'Effects', 'weedops' ),
|
||||
'labels' => [
|
||||
'name' => __( 'Effects', 'weedops' ),
|
||||
'singular_name' => __( 'Effect', 'weedops' ),
|
||||
'add_new_item' => __( 'Add Effect', 'weedops' ),
|
||||
],
|
||||
'hierarchical' => false,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'effects',
|
||||
'rewrite' => [ 'slug' => 'effect' ],
|
||||
'show_admin_column' => true,
|
||||
] );
|
||||
|
||||
// ── Terpenes ──────────────────────────────────────────────────────────────
|
||||
register_taxonomy( 'wo_terpene', [ 'wo_strain', 'wo_product' ], [
|
||||
'label' => __( 'Terpenes', 'weedops' ),
|
||||
'hierarchical' => false,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'terpenes',
|
||||
'rewrite' => [ 'slug' => 'terpene' ],
|
||||
] );
|
||||
|
||||
// ── Product Category (flower / concentrate / edible / topical / …) ────────
|
||||
register_taxonomy( 'wo_product_cat', [ 'wo_product' ], [
|
||||
'label' => __( 'Product Category', 'weedops' ),
|
||||
'hierarchical' => true,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'product-categories',
|
||||
'rewrite' => [ 'slug' => 'product-category' ],
|
||||
] );
|
||||
|
||||
// ── Compliance Status ─────────────────────────────────────────────────────
|
||||
register_taxonomy( 'wo_compliance_status', [ 'wo_compliance', 'wo_product' ], [
|
||||
'label' => __( 'Compliance Status', 'weedops' ),
|
||||
'hierarchical' => true,
|
||||
'show_in_rest' => true,
|
||||
'public' => false,
|
||||
'show_ui' => true,
|
||||
] );
|
||||
}
|
||||
add_action( 'init', 'weedops_register_taxonomies' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Meta Field Registration (REST API + Gutenberg)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_register_meta_fields(): void {
|
||||
|
||||
// Strain meta
|
||||
$strain_meta = [
|
||||
'wo_thc_percent' => [ 'type' => 'number', 'label' => 'THC %', 'sanitize' => 'floatval' ],
|
||||
'wo_cbd_percent' => [ 'type' => 'number', 'label' => 'CBD %', 'sanitize' => 'floatval' ],
|
||||
'wo_genetics' => [ 'type' => 'string', 'label' => 'Genetics / Lineage', 'sanitize' => 'sanitize_text_field' ],
|
||||
'wo_flowering_time' => [ 'type' => 'integer', 'label' => 'Flowering Time (days)', 'sanitize' => 'absint' ],
|
||||
'wo_yield_indoor' => [ 'type' => 'string', 'label' => 'Indoor Yield', 'sanitize' => 'sanitize_text_field' ],
|
||||
'wo_yield_outdoor' => [ 'type' => 'string', 'label' => 'Outdoor Yield', 'sanitize' => 'sanitize_text_field' ],
|
||||
'wo_difficulty' => [ 'type' => 'string', 'label' => 'Grow Difficulty', 'sanitize' => 'sanitize_text_field' ],
|
||||
];
|
||||
|
||||
foreach ( $strain_meta as $key => $config ) {
|
||||
register_post_meta( 'wo_strain', $key, [
|
||||
'type' => $config['type'],
|
||||
'single' => true,
|
||||
'show_in_rest' => true,
|
||||
'description' => $config['label'],
|
||||
'sanitize_callback' => $config['sanitize'],
|
||||
'auth_callback' => fn() => current_user_can( 'edit_posts' ),
|
||||
] );
|
||||
}
|
||||
|
||||
// Product meta
|
||||
$product_meta = [
|
||||
'wo_sku' => [ 'type' => 'string', 'label' => 'SKU / License #', 'sanitize' => 'sanitize_text_field' ],
|
||||
'wo_batch_id' => [ 'type' => 'string', 'label' => 'Batch ID', 'sanitize' => 'sanitize_text_field' ],
|
||||
'wo_lab_tested' => [ 'type' => 'boolean', 'label' => 'Lab Tested', 'sanitize' => 'rest_sanitize_boolean' ],
|
||||
'wo_coa_url' => [ 'type' => 'string', 'label' => 'COA (Certificate of Analysis) URL','sanitize' => 'esc_url_raw' ],
|
||||
'wo_price_gram' => [ 'type' => 'number', 'label' => 'Price per Gram', 'sanitize' => 'floatval' ],
|
||||
'wo_inventory_qty' => [ 'type' => 'integer', 'label' => 'Inventory Qty (g)', 'sanitize' => 'absint' ],
|
||||
'wo_origin_state' => [ 'type' => 'string', 'label' => 'Origin State', 'sanitize' => 'sanitize_text_field' ],
|
||||
'wo_license_no' => [ 'type' => 'string', 'label' => 'Producer License #', 'sanitize' => 'sanitize_text_field' ],
|
||||
];
|
||||
|
||||
foreach ( $product_meta as $key => $config ) {
|
||||
register_post_meta( 'wo_product', $key, [
|
||||
'type' => $config['type'],
|
||||
'single' => true,
|
||||
'show_in_rest' => true,
|
||||
'description' => $config['label'],
|
||||
'sanitize_callback' => $config['sanitize'],
|
||||
'auth_callback' => fn() => current_user_can( 'edit_posts' ),
|
||||
] );
|
||||
}
|
||||
}
|
||||
add_action( 'init', 'weedops_register_meta_fields' );
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Admin Meta Box — Strain Details
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function weedops_add_strain_meta_box(): void {
|
||||
add_meta_box(
|
||||
'wo_strain_details',
|
||||
__( 'Strain Details', 'weedops' ),
|
||||
'weedops_render_strain_meta_box',
|
||||
'wo_strain',
|
||||
'normal',
|
||||
'high'
|
||||
);
|
||||
}
|
||||
add_action( 'add_meta_boxes', 'weedops_add_strain_meta_box' );
|
||||
|
||||
function weedops_render_strain_meta_box( WP_Post $post ): void {
|
||||
wp_nonce_field( 'wo_save_strain_details', 'wo_strain_nonce' );
|
||||
|
||||
$thc = get_post_meta( $post->ID, 'wo_thc_percent', true );
|
||||
$cbd = get_post_meta( $post->ID, 'wo_cbd_percent', true );
|
||||
$genetics = get_post_meta( $post->ID, 'wo_genetics', true );
|
||||
$difficulty = get_post_meta( $post->ID, 'wo_difficulty', true );
|
||||
|
||||
// Strain type from taxonomy
|
||||
$strain_types = get_the_terms( $post->ID, 'wo_strain_type' );
|
||||
$current_type = ( $strain_types && ! is_wp_error( $strain_types ) )
|
||||
? $strain_types[0]->slug
|
||||
: '';
|
||||
|
||||
// Effects from taxonomy
|
||||
$effects_terms = get_terms( [ 'taxonomy' => 'wo_effect', 'hide_empty' => false ] );
|
||||
$assigned_effects = wp_get_post_terms( $post->ID, 'wo_effect', [ 'fields' => 'ids' ] );
|
||||
|
||||
?>
|
||||
<style>
|
||||
.wo-metabox-grid { display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; }
|
||||
.wo-metabox-field label { display:block; font-weight:600; margin-bottom:4px; }
|
||||
.wo-metabox-field input,
|
||||
.wo-metabox-field select { width:100%; }
|
||||
.wo-effects-list { columns:3; gap:12px; }
|
||||
.wo-effects-list label { display:block; font-weight:normal; margin-bottom:4px; }
|
||||
</style>
|
||||
|
||||
<div class="wo-metabox-grid">
|
||||
|
||||
<div class="wo-metabox-field">
|
||||
<label for="wo_thc_percent"><?php esc_html_e( 'THC %', 'weedops' ); ?></label>
|
||||
<input type="number" id="wo_thc_percent" name="wo_thc_percent"
|
||||
value="<?php echo esc_attr( $thc ); ?>"
|
||||
step="0.1" min="0" max="100" placeholder="e.g. 22.5" />
|
||||
</div>
|
||||
|
||||
<div class="wo-metabox-field">
|
||||
<label for="wo_cbd_percent"><?php esc_html_e( 'CBD %', 'weedops' ); ?></label>
|
||||
<input type="number" id="wo_cbd_percent" name="wo_cbd_percent"
|
||||
value="<?php echo esc_attr( $cbd ); ?>"
|
||||
step="0.1" min="0" max="100" placeholder="e.g. 0.5" />
|
||||
</div>
|
||||
|
||||
<div class="wo-metabox-field">
|
||||
<label for="wo_strain_type_select"><?php esc_html_e( 'Strain Type', 'weedops' ); ?></label>
|
||||
<select id="wo_strain_type_select" name="wo_strain_type_select">
|
||||
<option value=""><?php esc_html_e( '— Select type —', 'weedops' ); ?></option>
|
||||
<?php foreach ( [ 'indica' => 'Indica', 'sativa' => 'Sativa', 'hybrid' => 'Hybrid', 'cbd' => 'CBD / High-CBD' ] as $slug => $label ) : ?>
|
||||
<option value="<?php echo esc_attr( $slug ); ?>"
|
||||
<?php selected( $current_type, $slug ); ?>>
|
||||
<?php echo esc_html( $label ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="wo-metabox-field">
|
||||
<label for="wo_difficulty"><?php esc_html_e( 'Grow Difficulty', 'weedops' ); ?></label>
|
||||
<select id="wo_difficulty" name="wo_difficulty">
|
||||
<option value=""><?php esc_html_e( '— Select —', 'weedops' ); ?></option>
|
||||
<?php foreach ( [ 'beginner' => 'Beginner', 'intermediate' => 'Intermediate', 'advanced' => 'Advanced' ] as $val => $lbl ) : ?>
|
||||
<option value="<?php echo esc_attr( $val ); ?>"
|
||||
<?php selected( $difficulty, $val ); ?>>
|
||||
<?php echo esc_html( $lbl ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="wo-metabox-field" style="margin-bottom:16px;">
|
||||
<label for="wo_genetics"><?php esc_html_e( 'Genetics / Lineage', 'weedops' ); ?></label>
|
||||
<input type="text" id="wo_genetics" name="wo_genetics"
|
||||
value="<?php echo esc_attr( $genetics ); ?>"
|
||||
placeholder="e.g. OG Kush × Durban Poison" style="width:100%;" />
|
||||
</div>
|
||||
|
||||
<?php if ( ! is_wp_error( $effects_terms ) && ! empty( $effects_terms ) ) : ?>
|
||||
<div class="wo-metabox-field">
|
||||
<label><?php esc_html_e( 'Effects', 'weedops' ); ?></label>
|
||||
<div class="wo-effects-list">
|
||||
<?php foreach ( $effects_terms as $effect ) : ?>
|
||||
<label>
|
||||
<input type="checkbox" name="wo_effect_terms[]"
|
||||
value="<?php echo esc_attr( $effect->term_id ); ?>"
|
||||
<?php checked( in_array( $effect->term_id, (array) $assigned_effects, true ) ); ?> />
|
||||
<?php echo esc_html( $effect->name ); ?>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
function weedops_save_strain_meta( int $post_id ): void {
|
||||
// Bail on autosave / AJAX / wrong post type
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
|
||||
if ( ! isset( $_POST['wo_strain_nonce'] ) ) return;
|
||||
if ( ! wp_verify_nonce( sanitize_key( $_POST['wo_strain_nonce'] ), 'wo_save_strain_details' ) ) return;
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
|
||||
if ( get_post_type( $post_id ) !== 'wo_strain' ) return;
|
||||
|
||||
// THC %
|
||||
if ( isset( $_POST['wo_thc_percent'] ) ) {
|
||||
$thc = (float) $_POST['wo_thc_percent'];
|
||||
update_post_meta( $post_id, 'wo_thc_percent', $thc );
|
||||
}
|
||||
|
||||
// CBD %
|
||||
if ( isset( $_POST['wo_cbd_percent'] ) ) {
|
||||
$cbd = (float) $_POST['wo_cbd_percent'];
|
||||
update_post_meta( $post_id, 'wo_cbd_percent', $cbd );
|
||||
}
|
||||
|
||||
// Genetics
|
||||
if ( isset( $_POST['wo_genetics'] ) ) {
|
||||
update_post_meta( $post_id, 'wo_genetics', sanitize_text_field( wp_unslash( $_POST['wo_genetics'] ) ) );
|
||||
}
|
||||
|
||||
// Difficulty
|
||||
if ( isset( $_POST['wo_difficulty'] ) ) {
|
||||
$allowed = [ 'beginner', 'intermediate', 'advanced', '' ];
|
||||
$diff = in_array( $_POST['wo_difficulty'], $allowed, true ) ? $_POST['wo_difficulty'] : '';
|
||||
update_post_meta( $post_id, 'wo_difficulty', $diff );
|
||||
}
|
||||
|
||||
// Strain type — set taxonomy term by slug
|
||||
if ( isset( $_POST['wo_strain_type_select'] ) ) {
|
||||
$type_slug = sanitize_key( $_POST['wo_strain_type_select'] );
|
||||
if ( ! empty( $type_slug ) ) {
|
||||
// Make sure the term exists (create if needed)
|
||||
$term = get_term_by( 'slug', $type_slug, 'wo_strain_type' );
|
||||
if ( ! $term ) {
|
||||
$inserted = wp_insert_term( ucfirst( $type_slug ), 'wo_strain_type', [ 'slug' => $type_slug ] );
|
||||
$term_id = is_wp_error( $inserted ) ? 0 : $inserted['term_id'];
|
||||
} else {
|
||||
$term_id = $term->term_id;
|
||||
}
|
||||
if ( $term_id ) {
|
||||
wp_set_post_terms( $post_id, [ $term_id ], 'wo_strain_type' );
|
||||
}
|
||||
} else {
|
||||
wp_set_post_terms( $post_id, [], 'wo_strain_type' );
|
||||
}
|
||||
}
|
||||
|
||||
// Effects — array of term IDs
|
||||
$effect_ids = isset( $_POST['wo_effect_terms'] )
|
||||
? array_map( 'absint', (array) $_POST['wo_effect_terms'] )
|
||||
: [];
|
||||
wp_set_post_terms( $post_id, $effect_ids, 'wo_effect' );
|
||||
}
|
||||
add_action( 'save_post_wo_strain', 'weedops_save_strain_meta' );
|
||||
144
index.php
Normal file
144
index.php
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
/**
|
||||
* Weedops — Main Template File
|
||||
*
|
||||
* Fallback template used when no more specific template matches.
|
||||
* Also serves as the blog/post archive.
|
||||
*
|
||||
* @package Weedops
|
||||
*/
|
||||
|
||||
get_header();
|
||||
?>
|
||||
|
||||
<?php if ( is_home() && ! is_front_page() ) : ?>
|
||||
<header class="wo-page-header wo-mb-3">
|
||||
<h1 class="wo-page-title"><?php esc_html_e( 'Latest Posts', 'weedops' ); ?></h1>
|
||||
</header>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
|
||||
<div class="wo-grid wo-grid--3">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class( 'wo-card' ); ?>>
|
||||
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<a href="<?php the_permalink(); ?>" class="wo-card__thumb" aria-hidden="true" tabindex="-1">
|
||||
<?php
|
||||
the_post_thumbnail( 'medium', [
|
||||
'class' => 'wo-card__img',
|
||||
'loading' => 'lazy',
|
||||
'style' => 'width:100%;height:180px;object-fit:cover;border-radius:8px 8px 0 0;margin:-1.5rem -1.5rem 1rem;width:calc(100% + 3rem);',
|
||||
] );
|
||||
?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Post type / taxonomy badges ?>
|
||||
<div class="wo-card__meta" style="margin-bottom:0.6rem;">
|
||||
<?php
|
||||
$post_type = get_post_type();
|
||||
if ( 'wo_strain' === $post_type ) {
|
||||
$types = get_the_terms( get_the_ID(), 'wo_strain_type' );
|
||||
if ( $types && ! is_wp_error( $types ) ) {
|
||||
foreach ( $types as $t ) {
|
||||
weedops_strain_badge( $t->slug );
|
||||
}
|
||||
}
|
||||
} elseif ( 'wo_product' === $post_type ) {
|
||||
$cats = get_the_terms( get_the_ID(), 'wo_product_cat' );
|
||||
if ( $cats && ! is_wp_error( $cats ) ) {
|
||||
echo '<span class="wo-badge" style="background:#1a2e3d;color:#b3d9ff;">';
|
||||
echo esc_html( $cats[0]->name );
|
||||
echo '</span>';
|
||||
}
|
||||
} else {
|
||||
echo '<span class="wo-text-muted" style="font-size:0.78rem;">';
|
||||
echo esc_html( get_the_category_list( ', ' ) );
|
||||
echo '</span>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<h2 class="wo-card__title" style="font-size:1.1rem;margin-bottom:0.5rem;">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h2>
|
||||
|
||||
<?php // Cannabinoid info for strains/products ?>
|
||||
<?php if ( in_array( $post_type, [ 'wo_strain', 'wo_product' ], true ) ) : ?>
|
||||
<?php $canna_str = weedops_get_cannabinoid_str( get_the_ID() ); ?>
|
||||
<?php if ( $canna_str ) : ?>
|
||||
<p style="font-size:0.82rem;font-weight:600;color:var(--wo-green-mid);margin-bottom:0.5rem;">
|
||||
<?php echo esc_html( $canna_str ); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wo-card__excerpt" style="font-size:0.875rem;color:var(--wo-text-muted);margin-bottom:1rem;">
|
||||
<?php the_excerpt(); ?>
|
||||
</div>
|
||||
|
||||
<div class="wo-card__footer" style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.5rem;">
|
||||
<a href="<?php the_permalink(); ?>" class="wo-btn wo-btn--outline" style="font-size:0.8rem;padding:0.4rem 0.8rem;">
|
||||
<?php esc_html_e( 'View Details', 'weedops' ); ?>
|
||||
</a>
|
||||
|
||||
<?php // COA badge for lab-tested products ?>
|
||||
<?php if ( 'wo_product' === $post_type && weedops_has_valid_coa( get_the_ID() ) ) : ?>
|
||||
<span class="wo-compliance-tag wo-compliance-tag--ok">
|
||||
✓ <?php esc_html_e( 'Lab Tested', 'weedops' ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Date for blog posts ?>
|
||||
<?php if ( 'post' === $post_type ) : ?>
|
||||
<time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>" style="font-size:0.78rem;color:var(--wo-text-muted);">
|
||||
<?php echo esc_html( get_the_date() ); ?>
|
||||
</time>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
|
||||
<?php endwhile; ?>
|
||||
</div><!-- .wo-grid -->
|
||||
|
||||
<?php // Pagination ?>
|
||||
<nav class="wo-pagination wo-mt-3" role="navigation" aria-label="<?php esc_attr_e( 'Posts pagination', 'weedops' ); ?>">
|
||||
<?php
|
||||
the_posts_pagination( [
|
||||
'mid_size' => 2,
|
||||
'prev_text' => '← ' . __( 'Previous', 'weedops' ),
|
||||
'next_text' => __( 'Next', 'weedops' ) . ' →',
|
||||
'before_page_number' => '<span class="wo-sr-only">' . __( 'Page', 'weedops' ) . ' </span>',
|
||||
] );
|
||||
?>
|
||||
</nav>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<?php // No posts found ?>
|
||||
<section class="wo-card wo-text-center" style="max-width:560px;margin:4rem auto;">
|
||||
<svg width="56" height="56" viewBox="0 0 28 28" fill="none" aria-hidden="true" style="margin:0 auto 1rem;display:block;opacity:0.25;">
|
||||
<path d="M14 2C8.5 2 4 6.5 4 12c0 3.5 2 6.5 5 8.5L14 26l5-5.5c3-2 5-5 5-8.5C24 6.5 19.5 2 14 2z" fill="#1a3d2b"/>
|
||||
</svg>
|
||||
<h2 style="font-size:1.3rem;"><?php esc_html_e( 'Nothing found', 'weedops' ); ?></h2>
|
||||
<p class="wo-text-muted wo-mt-1">
|
||||
<?php esc_html_e( 'No content matches your query. Try searching or browse our strain database.', 'weedops' ); ?>
|
||||
</p>
|
||||
<div class="wo-mt-2">
|
||||
<?php get_search_form(); ?>
|
||||
</div>
|
||||
<div class="wo-mt-2">
|
||||
<a href="<?php echo esc_url( home_url( '/strains' ) ); ?>" class="wo-btn wo-btn--primary">
|
||||
<?php esc_html_e( 'Browse Strains', 'weedops' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
get_footer();
|
||||
224
single-strain.php
Normal file
224
single-strain.php
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
/**
|
||||
* Single Strain Template
|
||||
* Displays individual strain details: THC%, CBD%, type, effects, and product image.
|
||||
*
|
||||
* @package Weedops
|
||||
*/
|
||||
|
||||
get_header(); ?>
|
||||
|
||||
<main id="main" class="weedops-main">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<article id="strain-<?php the_ID(); ?>" <?php post_class( 'strain-single' ); ?>>
|
||||
|
||||
<div class="strain-hero">
|
||||
<div class="strain-hero__image">
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<?php the_post_thumbnail( 'large', [ 'class' => 'strain-hero__img' ] ); ?>
|
||||
<?php else : ?>
|
||||
<div class="strain-hero__placeholder">
|
||||
<div class="strain-hero__placeholder-inner">
|
||||
<span class="strain-hero__placeholder-icon">🌿</span>
|
||||
<span class="strain-hero__placeholder-text">Product Image Coming Soon</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="strain-hero__info">
|
||||
<div class="strain-badge strain-badge--<?php echo esc_attr( get_post_meta( get_the_ID(), '_strain_type', true ) ); ?>">
|
||||
<?php
|
||||
$strain_type = get_post_meta( get_the_ID(), '_strain_type', true );
|
||||
echo esc_html( ucfirst( $strain_type ? $strain_type : 'Unknown' ) );
|
||||
?>
|
||||
</div>
|
||||
|
||||
<h1 class="strain-title"><?php the_title(); ?></h1>
|
||||
|
||||
<div class="strain-potency">
|
||||
<?php
|
||||
$thc = get_post_meta( get_the_ID(), '_strain_thc', true );
|
||||
$cbd = get_post_meta( get_the_ID(), '_strain_cbd', true );
|
||||
?>
|
||||
|
||||
<?php if ( $thc !== '' ) : ?>
|
||||
<div class="potency-card potency-card--thc">
|
||||
<span class="potency-card__label">THC</span>
|
||||
<span class="potency-card__value"><?php echo esc_html( $thc ); ?>%</span>
|
||||
<div class="potency-bar">
|
||||
<div class="potency-bar__fill potency-bar__fill--thc" style="width: <?php echo esc_attr( min( floatval( $thc ), 35 ) / 35 * 100 ); ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $cbd !== '' ) : ?>
|
||||
<div class="potency-card potency-card--cbd">
|
||||
<span class="potency-card__label">CBD</span>
|
||||
<span class="potency-card__value"><?php echo esc_html( $cbd ); ?>%</span>
|
||||
<div class="potency-bar">
|
||||
<div class="potency-bar__fill potency-bar__fill--cbd" style="width: <?php echo esc_attr( min( floatval( $cbd ), 25 ) / 25 * 100 ); ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$effects_raw = get_post_meta( get_the_ID(), '_strain_effects', true );
|
||||
$effects = array_filter( array_map( 'trim', explode( ',', $effects_raw ) ) );
|
||||
if ( ! empty( $effects ) ) :
|
||||
?>
|
||||
<div class="strain-effects">
|
||||
<h3 class="strain-effects__heading">Effects</h3>
|
||||
<div class="strain-effects__tags">
|
||||
<?php foreach ( $effects as $effect ) : ?>
|
||||
<span class="effect-tag"><?php echo esc_html( $effect ); ?></span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( get_the_content() ) : ?>
|
||||
<div class="strain-description">
|
||||
<h2 class="strain-description__heading">About This Strain</h2>
|
||||
<div class="strain-description__content">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="strain-compliance-notice">
|
||||
<p>⚠️ For use only by adults 21+. Keep out of reach of children. This product has not been evaluated by the FDA.</p>
|
||||
</div>
|
||||
|
||||
<nav class="strain-nav">
|
||||
<?php
|
||||
$prev = get_previous_post();
|
||||
$next = get_next_post();
|
||||
if ( $prev ) :
|
||||
?>
|
||||
<a href="<?php echo esc_url( get_permalink( $prev ) ); ?>" class="strain-nav__link strain-nav__link--prev">
|
||||
← <?php echo esc_html( get_the_title( $prev ) ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo esc_url( get_post_type_archive_link( 'strain' ) ); ?>" class="strain-nav__link strain-nav__link--archive">
|
||||
All Strains
|
||||
</a>
|
||||
<?php if ( $next ) : ?>
|
||||
<a href="<?php echo esc_url( get_permalink( $next ) ); ?>" class="strain-nav__link strain-nav__link--next">
|
||||
<?php echo esc_html( get_the_title( $next ) ); ?> →
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</nav>
|
||||
|
||||
</article>
|
||||
|
||||
<?php endwhile; ?>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
/* ── Single Strain Styles ─────────────────────────────── */
|
||||
.strain-single { max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem; }
|
||||
|
||||
.strain-hero {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3rem;
|
||||
align-items: start;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.strain-hero { grid-template-columns: 1fr; gap: 1.5rem; }
|
||||
}
|
||||
|
||||
/* Image / Placeholder */
|
||||
.strain-hero__img { width: 100%; border-radius: 12px; object-fit: cover; aspect-ratio: 4/3; }
|
||||
.strain-hero__placeholder {
|
||||
width: 100%; aspect-ratio: 4/3;
|
||||
background: linear-gradient(135deg, #1a3a1a 0%, #2d5a2d 100%);
|
||||
border-radius: 12px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
border: 2px dashed #4a8c4a;
|
||||
}
|
||||
.strain-hero__placeholder-inner { text-align: center; color: #8ec88e; }
|
||||
.strain-hero__placeholder-icon { font-size: 3rem; display: block; margin-bottom: .5rem; }
|
||||
.strain-hero__placeholder-text { font-size: .9rem; letter-spacing: .05em; }
|
||||
|
||||
/* Badge */
|
||||
.strain-badge {
|
||||
display: inline-block;
|
||||
padding: .3rem .9rem;
|
||||
border-radius: 999px;
|
||||
font-size: .75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .08em;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.strain-badge--indica { background: #4a148c; color: #e1bee7; }
|
||||
.strain-badge--sativa { background: #e65100; color: #ffe0b2; }
|
||||
.strain-badge--hybrid { background: #1b5e20; color: #c8e6c9; }
|
||||
|
||||
/* Title */
|
||||
.strain-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 1.5rem; color: #1a3a1a; line-height: 1.2; }
|
||||
|
||||
/* Potency */
|
||||
.strain-potency { display: flex; gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap; }
|
||||
.potency-card {
|
||||
flex: 1; min-width: 120px;
|
||||
background: #f4f9f4;
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
.potency-card--thc { border-color: #388e3c; }
|
||||
.potency-card--cbd { border-color: #0288d1; }
|
||||
.potency-card__label { display: block; font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: #666; }
|
||||
.potency-card__value { display: block; font-size: 2rem; font-weight: 800; color: #1a3a1a; line-height: 1.1; margin-bottom: .4rem; }
|
||||
.potency-bar { height: 6px; background: #ddd; border-radius: 3px; overflow: hidden; }
|
||||
.potency-bar__fill--thc { height: 100%; background: #388e3c; border-radius: 3px; transition: width .4s ease; }
|
||||
.potency-bar__fill--cbd { height: 100%; background: #0288d1; border-radius: 3px; transition: width .4s ease; }
|
||||
|
||||
/* Effects */
|
||||
.strain-effects__heading { font-size: .85rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: #555; margin-bottom: .6rem; }
|
||||
.strain-effects__tags { display: flex; flex-wrap: wrap; gap: .4rem; }
|
||||
.effect-tag {
|
||||
background: #e8f5e9; color: #2e7d32;
|
||||
border: 1px solid #a5d6a7;
|
||||
border-radius: 999px;
|
||||
padding: .25rem .8rem;
|
||||
font-size: .85rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Description */
|
||||
.strain-description { background: #f9fafb; border-radius: 12px; padding: 2rem; margin-bottom: 2rem; }
|
||||
.strain-description__heading { font-size: 1.3rem; font-weight: 700; color: #1a3a1a; margin-top: 0; }
|
||||
|
||||
/* Compliance */
|
||||
.strain-compliance-notice {
|
||||
background: #fff8e1; border-left: 4px solid #fbc02d;
|
||||
border-radius: 6px; padding: .8rem 1.2rem;
|
||||
font-size: .8rem; color: #5d4037;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.strain-compliance-notice p { margin: 0; }
|
||||
|
||||
/* Nav */
|
||||
.strain-nav { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; padding-top: 1.5rem; border-top: 1px solid #e0e0e0; }
|
||||
.strain-nav__link {
|
||||
color: #2e7d32; font-weight: 600; text-decoration: none;
|
||||
padding: .5rem 1rem; border-radius: 6px;
|
||||
border: 1px solid #a5d6a7;
|
||||
transition: background .2s;
|
||||
}
|
||||
.strain-nav__link:hover { background: #e8f5e9; }
|
||||
.strain-nav__link--archive { background: #2e7d32; color: #fff; border-color: #2e7d32; }
|
||||
.strain-nav__link--archive:hover { background: #1b5e20; }
|
||||
</style>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
393
style.css
Normal file
393
style.css
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
Theme Name: Weedops
|
||||
Theme URI: https://weedops.site
|
||||
Author: Weedops Dev Team
|
||||
Author URI: https://weedops.site
|
||||
Description: Cannabis industry product management and compliance platform theme. Built for dispensaries, growers, and cannabis brands.
|
||||
Version: 1.0.0
|
||||
Requires at least: 6.0
|
||||
Tested up to: 6.7
|
||||
Requires PHP: 8.0
|
||||
License: Proprietary
|
||||
License URI: https://weedops.site/license
|
||||
Text Domain: weedops
|
||||
Tags: cannabis, dispensary, woocommerce, compliance, inventory
|
||||
*/
|
||||
|
||||
/* ============================================================
|
||||
WEEDOPS THEME — Cannabis Industry Platform
|
||||
Brand: Deep green (#1a3d2b), Gold (#c8a951), Off-white (#f5f0e8)
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
--wo-green-dark: #1a3d2b;
|
||||
--wo-green-mid: #2e6b47;
|
||||
--wo-green-light: #4a9e68;
|
||||
--wo-gold: #c8a951;
|
||||
--wo-gold-light: #e2c97a;
|
||||
--wo-cream: #f5f0e8;
|
||||
--wo-white: #ffffff;
|
||||
--wo-text-dark: #1c1c1c;
|
||||
--wo-text-muted: #666666;
|
||||
--wo-border: #d4cfc6;
|
||||
--wo-error: #c0392b;
|
||||
--wo-success: #27ae60;
|
||||
|
||||
--wo-font-sans: 'Inter', 'Helvetica Neue', Arial, sans-serif;
|
||||
--wo-font-serif: 'Georgia', 'Times New Roman', serif;
|
||||
--wo-font-mono: 'JetBrains Mono', 'Courier New', monospace;
|
||||
|
||||
--wo-radius: 6px;
|
||||
--wo-radius-lg: 12px;
|
||||
--wo-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
--wo-shadow-lg: 0 8px 32px rgba(0,0,0,0.18);
|
||||
--wo-transition: 0.2s ease;
|
||||
}
|
||||
|
||||
/* ── Reset ────────────────────────────────────────────────── */
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
html { font-size: 16px; scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
font-family: var(--wo-font-sans);
|
||||
color: var(--wo-text-dark);
|
||||
background-color: var(--wo-cream);
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* ── Typography ───────────────────────────────────────────── */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
color: var(--wo-green-dark);
|
||||
}
|
||||
|
||||
h1 { font-size: clamp(1.8rem, 4vw, 2.8rem); }
|
||||
h2 { font-size: clamp(1.4rem, 3vw, 2.1rem); }
|
||||
h3 { font-size: clamp(1.1rem, 2.5vw, 1.5rem); }
|
||||
h4 { font-size: 1.15rem; }
|
||||
|
||||
p { margin-bottom: 1rem; }
|
||||
|
||||
a { color: var(--wo-green-mid); text-decoration: none; transition: color var(--wo-transition); }
|
||||
a:hover { color: var(--wo-gold); }
|
||||
|
||||
/* ── Layout ───────────────────────────────────────────────── */
|
||||
.wo-container {
|
||||
width: 100%;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
}
|
||||
|
||||
.wo-main {
|
||||
min-height: calc(100vh - 80px - 160px);
|
||||
padding: 2.5rem 0;
|
||||
}
|
||||
|
||||
.wo-grid {
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.wo-grid--2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
|
||||
.wo-grid--3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
|
||||
.wo-grid--4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
|
||||
|
||||
/* ── Header ───────────────────────────────────────────────── */
|
||||
.wo-header {
|
||||
background-color: var(--wo-green-dark);
|
||||
border-bottom: 3px solid var(--wo-gold);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
box-shadow: var(--wo-shadow);
|
||||
}
|
||||
|
||||
.wo-header__inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.wo-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
color: var(--wo-white);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.wo-logo span { color: var(--wo-gold); }
|
||||
.wo-logo:hover { color: var(--wo-gold-light); }
|
||||
|
||||
/* ── Navigation ───────────────────────────────────────────── */
|
||||
.wo-nav ul {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.wo-nav a {
|
||||
color: rgba(255,255,255,0.85);
|
||||
padding: 0.5rem 0.9rem;
|
||||
border-radius: var(--wo-radius);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
transition: background var(--wo-transition), color var(--wo-transition);
|
||||
}
|
||||
|
||||
.wo-nav a:hover,
|
||||
.wo-nav .current-menu-item > a {
|
||||
background: rgba(200,169,81,0.2);
|
||||
color: var(--wo-gold-light);
|
||||
}
|
||||
|
||||
/* ── Buttons ──────────────────────────────────────────────── */
|
||||
.wo-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: var(--wo-radius);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all var(--wo-transition);
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.wo-btn--primary {
|
||||
background: var(--wo-gold);
|
||||
color: var(--wo-green-dark);
|
||||
border-color: var(--wo-gold);
|
||||
}
|
||||
.wo-btn--primary:hover {
|
||||
background: var(--wo-gold-light);
|
||||
border-color: var(--wo-gold-light);
|
||||
color: var(--wo-green-dark);
|
||||
}
|
||||
|
||||
.wo-btn--outline {
|
||||
background: transparent;
|
||||
color: var(--wo-green-dark);
|
||||
border-color: var(--wo-green-mid);
|
||||
}
|
||||
.wo-btn--outline:hover {
|
||||
background: var(--wo-green-dark);
|
||||
color: var(--wo-white);
|
||||
}
|
||||
|
||||
/* ── Cards ────────────────────────────────────────────────── */
|
||||
.wo-card {
|
||||
background: var(--wo-white);
|
||||
border-radius: var(--wo-radius-lg);
|
||||
border: 1px solid var(--wo-border);
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--wo-shadow);
|
||||
transition: box-shadow var(--wo-transition), transform var(--wo-transition);
|
||||
}
|
||||
|
||||
.wo-card:hover {
|
||||
box-shadow: var(--wo-shadow-lg);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* ── Strain / Product badges ──────────────────────────────── */
|
||||
.wo-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.2rem 0.6rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.wo-badge--indica { background: #3d1a5e; color: #e8ccff; }
|
||||
.wo-badge--sativa { background: #1a3d1a; color: #ccffcc; }
|
||||
.wo-badge--hybrid { background: #3d2e1a; color: #ffe0b2; }
|
||||
.wo-badge--cbd { background: #1a2e3d; color: #b3d9ff; }
|
||||
|
||||
/* ── Compliance tags ──────────────────────────────────────── */
|
||||
.wo-compliance-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
padding: 0.25rem 0.7rem;
|
||||
border-radius: var(--wo-radius);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
border: 1px solid currentColor;
|
||||
}
|
||||
|
||||
.wo-compliance-tag--ok { color: var(--wo-success); }
|
||||
.wo-compliance-tag--warning { color: var(--wo-gold); }
|
||||
.wo-compliance-tag--fail { color: var(--wo-error); }
|
||||
|
||||
/* ── Footer ───────────────────────────────────────────────── */
|
||||
.wo-footer {
|
||||
background: var(--wo-green-dark);
|
||||
color: rgba(255,255,255,0.7);
|
||||
padding: 2.5rem 0 1.5rem;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.wo-footer__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.wo-footer__brand .wo-logo { font-size: 1.2rem; margin-bottom: 0.75rem; }
|
||||
.wo-footer p { font-size: 0.85rem; line-height: 1.7; }
|
||||
|
||||
.wo-footer h4 {
|
||||
color: var(--wo-gold);
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.wo-footer ul { list-style: none; }
|
||||
.wo-footer ul li { margin-bottom: 0.4rem; }
|
||||
.wo-footer ul a { color: rgba(255,255,255,0.65); font-size: 0.875rem; }
|
||||
.wo-footer ul a:hover { color: var(--wo-gold-light); }
|
||||
|
||||
.wo-footer__bottom {
|
||||
border-top: 1px solid rgba(255,255,255,0.12);
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 0.8rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* ── Age-gate / Compliance notice ─────────────────────────── */
|
||||
.wo-age-notice {
|
||||
background: var(--wo-green-dark);
|
||||
color: var(--wo-cream);
|
||||
text-align: center;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8rem;
|
||||
border-bottom: 1px solid var(--wo-gold);
|
||||
}
|
||||
|
||||
/* ── Hero (Photography Style) ────────────────────────────── */
|
||||
.wo-hero {
|
||||
position: relative;
|
||||
min-height: 85vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background:
|
||||
url('assets/img/hero-cannabis.jpg')
|
||||
center center / cover
|
||||
no-repeat;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wo-hero__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
160deg,
|
||||
rgba(26, 61, 43, 0.88) 0%,
|
||||
rgba(26, 61, 43, 0.55) 50%,
|
||||
rgba(0, 0, 0, 0.40) 100%
|
||||
);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.wo-hero__content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
max-width: 720px;
|
||||
padding: 3rem 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wo-hero__eyebrow {
|
||||
display: inline-block;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.18em;
|
||||
color: var(--wo-gold);
|
||||
margin-bottom: 1.25rem;
|
||||
padding: 0.35rem 1rem;
|
||||
border: 1px solid rgba(200, 169, 81, 0.4);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.wo-hero__title {
|
||||
font-size: clamp(2rem, 5vw, 3.4rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.12;
|
||||
color: var(--wo-white);
|
||||
margin-bottom: 1.25rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.wo-hero__subtitle {
|
||||
font-size: clamp(1rem, 2vw, 1.2rem);
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
line-height: 1.7;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.wo-hero__actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.wo-btn--lg {
|
||||
padding: 0.85rem 1.8rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.wo-btn--ghost {
|
||||
background: transparent;
|
||||
color: var(--wo-white);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.wo-btn--ghost:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border-color: var(--wo-white);
|
||||
color: var(--wo-white);
|
||||
}
|
||||
|
||||
/* ── Sections ────────────────────────────────────────────── */
|
||||
.wo-section { padding: 1rem 0; }
|
||||
|
||||
/* ── Utilities ────────────────────────────────────────────── */
|
||||
.wo-text-center { text-align: center; }
|
||||
.wo-text-muted { color: var(--wo-text-muted); }
|
||||
.wo-mt-1 { margin-top: 0.5rem; }
|
||||
.wo-mt-2 { margin-top: 1rem; }
|
||||
.wo-mt-3 { margin-top: 1.5rem; }
|
||||
.wo-mb-2 { margin-bottom: 1rem; }
|
||||
.wo-mb-3 { margin-bottom: 1.5rem; }
|
||||
.wo-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
|
||||
|
||||
/* ── Responsive ───────────────────────────────────────────── */
|
||||
@media (max-width: 768px) {
|
||||
.wo-header__inner { height: 60px; }
|
||||
.wo-nav { display: none; } /* mobile nav handled by JS toggle */
|
||||
.wo-footer__bottom { flex-direction: column; text-align: center; }
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue