Compare commits
No commits in common. "8a4216f497e01c1f71a7903c97f231bfa7323a6a" and "2db3c63e5abc52d33055c5478beb977702edad5f" have entirely different histories.
8a4216f497
...
2db3c63e5a
10 changed files with 1467 additions and 1875 deletions
|
|
@ -1,307 +0,0 @@
|
|||
<?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(); ?>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 382 KiB |
94
footer.php
94
footer.php
|
|
@ -1,91 +1,15 @@
|
|||
</div><!-- .wo-container (opened in header.php) -->
|
||||
</main><!-- #main-content -->
|
||||
</main>
|
||||
|
||||
<?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 class="site-footer">
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<span class="footer-location">WeedOps · Los Angeles, California</span>
|
||||
<span class="footer-copy">© <?php echo date('Y'); ?> WeedOps</span>
|
||||
</div>
|
||||
<p class="footer-disclaimer">This is a confidential investor overview. Not a public offering.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<?php wp_footer(); ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
444
front-page.php
444
front-page.php
|
|
@ -1,153 +1,341 @@
|
|||
<?php
|
||||
/**
|
||||
* Weedops — Front Page Template
|
||||
*
|
||||
* Full-width hero with photography-style imagery,
|
||||
* followed by featured sections.
|
||||
*
|
||||
* @package Weedops
|
||||
* Template Name: Home
|
||||
* Home page — investor-facing landing page
|
||||
*/
|
||||
|
||||
get_header();
|
||||
|
||||
$form_result = weedops_get_form_result();
|
||||
?>
|
||||
|
||||
</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>
|
||||
<!-- Hero -->
|
||||
<section class="hero">
|
||||
<div class="container">
|
||||
<div class="hero-content">
|
||||
<p class="section-label">A Confidential Investor Overview</p>
|
||||
<h1>Your home. Your plants.<br>Our expertise. <span class="green">Your check.</span></h1>
|
||||
<p class="subhead">California adults can legally grow cannabis at home. Almost none of them do. We built the company that changes that — and makes money at every step of the process.</p>
|
||||
<p class="hero-note">$500,000 Convertible Notes — Private Party Round Now Open</p>
|
||||
<div class="hero-ctas">
|
||||
<a href="#deck" class="btn btn-primary">Request the Deck</a>
|
||||
<a href="#opportunity" class="btn btn-secondary">Learn How It Works</a>
|
||||
</div>
|
||||
</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>
|
||||
<!-- The Opportunity -->
|
||||
<section class="opportunity" id="opportunity">
|
||||
<div class="container">
|
||||
<p class="section-label">The Opportunity</p>
|
||||
<div class="opportunity-content">
|
||||
<h2>A category that doesn't exist yet. We're defining it.</h2>
|
||||
<p>Millions of California adults consume cannabis. A fraction grow it. The gap isn't desire — it's <span class="emphasis">expertise, equipment, and time</span>. WeedOps is the first company to solve all three with a fully managed, fully licensed, recurring service model.</p>
|
||||
<p>This is not a dispensary. Not a delivery app. Not a brand.</p>
|
||||
<p class="emphasis" style="color: var(--white);">This is infrastructure.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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>
|
||||
<!-- The Problem -->
|
||||
<section id="problem">
|
||||
<div class="container">
|
||||
<p class="section-label">The Problem</p>
|
||||
<h2>Many adults want craft cannabis.<br>Almost none of them grow it.</h2>
|
||||
<div class="problem-grid">
|
||||
<div class="problem-card">
|
||||
<h3>The expertise gap</h3>
|
||||
<p>A successful home grow requires strain knowledge, lighting science, training techniques, and timing. Most adults never get past seed-to-sprout.</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 class="problem-card">
|
||||
<h3>The time barrier</h3>
|
||||
<p>Daily monitoring. Biweekly maintenance. Processing at harvest. A full-time job on top of your actual job.</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 class="problem-card">
|
||||
<h3>The equipment wall</h3>
|
||||
<p>A quality grow tent setup costs $800 - $2,000 upfront — before you've grown a single gram. Most people quit before they start.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</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>
|
||||
<!-- The Solution -->
|
||||
<section class="opportunity" id="model">
|
||||
<div class="container">
|
||||
<p class="section-label">The Solution</p>
|
||||
<h2>We bring the entire operation to your home.</h2>
|
||||
<p class="subhead">WeedOps handles everything — equipment, setup, clones, biweekly visits, harvesting, and processing. You provide the space. We provide the rest.</p>
|
||||
<div class="solution-features">
|
||||
<div class="solution-feature">
|
||||
<h3>Full equipment setup</h3>
|
||||
<p>We bring it. We install it. All of it.</p>
|
||||
</div>
|
||||
<div class="solution-feature">
|
||||
<h3>Expert grow management</h3>
|
||||
<p>Biweekly site visits.</p>
|
||||
</div>
|
||||
<div class="solution-feature">
|
||||
<h3>Monthly product supply</h3>
|
||||
<p>Your share, delivered.</p>
|
||||
</div>
|
||||
<div class="solution-feature">
|
||||
<h3>Revenue share check</h3>
|
||||
<p>Every harvest cycle.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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; ?>
|
||||
<!-- How It Works -->
|
||||
<section id="how-it-works">
|
||||
<div class="container">
|
||||
<p class="section-label">How It Works</p>
|
||||
<h2>Six steps from empty bedroom to monthly check.</h2>
|
||||
<div class="steps-grid">
|
||||
<div class="step-card">
|
||||
<span class="step-number">01</span>
|
||||
<h3>Register</h3>
|
||||
<p>Tell us about your space and household. We send a proposal.</p>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<span class="step-number">02</span>
|
||||
<h3>Setup Day</h3>
|
||||
<p>We arrive with all equipment. Full grow tent installed, clones planted.</p>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<span class="step-number">03</span>
|
||||
<h3>Biweekly Visits</h3>
|
||||
<p>Our tech stops by every two weeks — maintenance, monitoring, training if desired.</p>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<span class="step-number">04</span>
|
||||
<h3>Harvest</h3>
|
||||
<p>Every ~9 weeks. We take the product for processing. You watch if you want, get an estimate.</p>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<span class="step-number">05</span>
|
||||
<h3>Your Supply</h3>
|
||||
<p>Next week: 30-day supply for every registered adult — flower, edible, cart, extract. You choose your format.</p>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<span class="step-number">06</span>
|
||||
<h3>Your Check</h3>
|
||||
<p>Remaining product processed and sold on consignment. Revenue share check every cycle.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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 );
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!-- What You Get as a WeedOpper -->
|
||||
<section class="opportunity">
|
||||
<div class="container">
|
||||
<p class="section-label">What You Get as a WeedOpper</p>
|
||||
<h2>You had a hand in growing it. That's the whole point.</h2>
|
||||
<div class="weedopper-stats">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">$0</div>
|
||||
<div class="stat-label">Out of Pocket</div>
|
||||
<p>Refundable $500 deposit is the only ask. Equipment, clones, nutrients — all on us.</p>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">30</div>
|
||||
<div class="stat-label">Day Supply / Mo</div>
|
||||
<p>Every registered adult in the home gets their full monthly supply, first.</p>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="font-size: clamp(1.5rem, 3vw, 2rem);">Revenue Share</div>
|
||||
<div class="stat-label">Per Harvest</div>
|
||||
<p>Your cut from processed excess, every ~9-week cycle. Passive income.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center" style="color: var(--gray);">Optional webcam inside your grow. Video consultations. And a service you can learn to run yourself.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The Campus -->
|
||||
<section class="opportunity" id="campus">
|
||||
<div class="container">
|
||||
<p class="section-label">The WeedOps Campus</p>
|
||||
<h2>The home service is the foundation. The Superstore is the destination.</h2>
|
||||
<p class="subhead" style="max-width: 800px; margin-bottom: 48px;">This isn't a boutique. It's a floor. WeedOps Superstore is where serious growers come to outfit an operation — flat carts for 50-pound soil runs, shopping carts for accessories and nutrients, a full retail floor with every brand, format, and supply a home grower or commercial operation needs. Think Home Depot. Now think cannabis. Nobody has built it. That's the point.</p>
|
||||
<div class="campus-grid">
|
||||
<div class="campus-card">
|
||||
<h3>Processing</h3>
|
||||
<p>Glass wall. Watch your product get made. Like a brewery.</p>
|
||||
</div>
|
||||
<div class="campus-card">
|
||||
<h3>Retail Store</h3>
|
||||
<p>WeedOps product + curated shelf. You know what's in it.</p>
|
||||
</div>
|
||||
<div class="campus-card">
|
||||
<h3>Farmers Market</h3>
|
||||
<p>Third-party growers. Community. Foot traffic engine.</p>
|
||||
</div>
|
||||
<div class="campus-card">
|
||||
<h3>2nd Floor</h3>
|
||||
<p>Indoor grow suites for lease. No home required.</p>
|
||||
</div>
|
||||
<div class="campus-card">
|
||||
<h3>Rooftop</h3>
|
||||
<p>Outdoor grow plots for lease. Seasonal. Instagrammable.</p>
|
||||
</div>
|
||||
<div class="campus-card">
|
||||
<h3>Supply Shop</h3>
|
||||
<p>All supplies available onsite. Everything a grower needs, where growers already are.</p>
|
||||
</div>
|
||||
<div class="campus-card">
|
||||
<h3>Superstore Floor</h3>
|
||||
<p>Flat carts. Shopping carts. Bulk supply. Full equipment. The complete grow operation, ready to walk out the door.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="campus-tagline">The cannabis superstore. Finally.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Revenue Streams -->
|
||||
<section>
|
||||
<div class="container">
|
||||
<p class="section-label">Revenue Streams</p>
|
||||
<h2>This is not a single-product cannabis company.</h2>
|
||||
<div class="streams-grid">
|
||||
<div class="stream-card">
|
||||
<span class="stream-tag core">Core</span>
|
||||
<h3>Service Contracts</h3>
|
||||
<p>Monthly fee per home grow site. Predictable, recurring, scalable.</p>
|
||||
</div>
|
||||
<div class="stream-card">
|
||||
<span class="stream-tag margin">Margin</span>
|
||||
<h3>Processing</h3>
|
||||
<p>Licensed processing of all harvested product.</p>
|
||||
</div>
|
||||
<div class="stream-card">
|
||||
<span class="stream-tag margin">Margin</span>
|
||||
<h3>Distribution</h3>
|
||||
<p>Licensed distribution of processed product to retail.</p>
|
||||
</div>
|
||||
<div class="stream-card">
|
||||
<span class="stream-tag campus">Campus</span>
|
||||
<h3>Campus Retail</h3>
|
||||
<p>WeedOps-branded product on our own shelf.</p>
|
||||
</div>
|
||||
<div class="stream-card">
|
||||
<span class="stream-tag campus">Campus</span>
|
||||
<h3>Grow Suite Rental</h3>
|
||||
<p>Second floor and rooftop leasable grow spaces.</p>
|
||||
</div>
|
||||
<div class="stream-card">
|
||||
<span class="stream-tag campus">Campus</span>
|
||||
<h3>Supply Sales</h3>
|
||||
<p>Equipment, nutrients, accessories sold where growers already are.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Why Now -->
|
||||
<section class="opportunity">
|
||||
<div class="container">
|
||||
<p class="section-label">Why Now. Why LA. Why Us.</p>
|
||||
<h2>First mover in distributed home cultivation services.</h2>
|
||||
<div class="why-grid">
|
||||
<div class="why-card">
|
||||
<h3>Greater LA launch</h3>
|
||||
<p>5M+ adults in the LA metro. Cannabis-normalized culture. Word travels fast in every neighborhood on the westside.</p>
|
||||
</div>
|
||||
<div class="why-card">
|
||||
<h3>Fully licensed</h3>
|
||||
<p>Every required California license — cultivation, processing, distribution. 100% compliant. Taxes paid. Federal/state tension is real and acknowledged; our structure keeps commercial activity entirely within the state-licensed chain.</p>
|
||||
</div>
|
||||
<div class="why-card">
|
||||
<h3>Referral flywheel</h3>
|
||||
<p>Happy growers share what they grew. That's the whole pitch deck at a dinner party.</p>
|
||||
</div>
|
||||
<div class="why-card">
|
||||
<h3>First mover edge</h3>
|
||||
<p>Nobody has built this. The managed home grow service category doesn't exist yet. We're defining it.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- The Ask -->
|
||||
<section class="ask-section" id="ask">
|
||||
<div class="container">
|
||||
<p class="section-label">The Ask</p>
|
||||
<div class="ask-headline">
|
||||
<div class="amount">$500,000</div>
|
||||
<p class="terms">Convertible Notes · Private Party · No VC</p>
|
||||
<p class="terms-detail">Individual investors only · No institutional money</p>
|
||||
</div>
|
||||
<div class="use-of-funds">
|
||||
<div class="fund-item">
|
||||
<div class="fund-percent">40%</div>
|
||||
<h3>Licensing & Legal</h3>
|
||||
<p>All required CA licenses. Cannabis counsel.</p>
|
||||
</div>
|
||||
<div class="fund-item">
|
||||
<div class="fund-percent">30%</div>
|
||||
<h3>First Cohort Ops</h3>
|
||||
<p>Equipment for first 25 sites. Clones. Setup labor.</p>
|
||||
</div>
|
||||
<div class="fund-item">
|
||||
<div class="fund-percent">20%</div>
|
||||
<h3>Processing Setup</h3>
|
||||
<p>Licensed facility, equipment, first cycle.</p>
|
||||
</div>
|
||||
<div class="fund-item">
|
||||
<div class="fund-percent">10%</div>
|
||||
<h3>Technology & Brand</h3>
|
||||
<p>Customer portal. Ops dashboard. Marketing.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Deck Request CTA -->
|
||||
<section class="cta-section" id="deck">
|
||||
<div class="container">
|
||||
<?php if ($form_result === true): ?>
|
||||
<div class="form-success">
|
||||
<h3>Request received.</h3>
|
||||
<p>We'll send the full investor overview to your email shortly.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<h2>Interested in the round?</h2>
|
||||
<p class="subhead">Request the full investor overview. This is a confidential offering to individual investors.</p>
|
||||
|
||||
<?php if (is_string($form_result)): ?>
|
||||
<div class="form-error"><?php echo esc_html($form_result); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form class="deck-form" method="post" action="#deck">
|
||||
<?php wp_nonce_field('weedops_deck_request'); ?>
|
||||
<input type="hidden" name="weedops_deck_request" value="1">
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" name="name" placeholder="Your name" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" placeholder="you@email.com" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style="font-size:1.05rem;margin-bottom:0.4rem;">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h3>
|
||||
<div class="form-group">
|
||||
<label for="note">Anything you'd like us to know (optional)</label>
|
||||
<textarea id="note" name="note" rows="3" placeholder="How you heard about us, questions, etc."></textarea>
|
||||
</div>
|
||||
|
||||
<?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; ?>
|
||||
<?php if (WEEDOPS_TURNSTILE_SITE_KEY): ?>
|
||||
<div class="cf-turnstile mb-24" data-sitekey="<?php echo WEEDOPS_TURNSTILE_SITE_KEY; ?>" data-theme="dark"></div>
|
||||
<?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;
|
||||
?>
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%;">Request the Deck</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php
|
||||
get_footer();
|
||||
<?php get_footer(); ?>
|
||||
|
|
|
|||
280
functions.php
280
functions.php
|
|
@ -1,192 +1,130 @@
|
|||
<?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
|
||||
* WeedOps Theme Functions
|
||||
*/
|
||||
|
||||
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' ),
|
||||
] );
|
||||
// Theme setup
|
||||
function weedops_setup() {
|
||||
add_theme_support('title-tag');
|
||||
add_theme_support('post-thumbnails');
|
||||
add_theme_support('html5', array('search-form', 'comment-form', 'comment-list', 'gallery', 'caption'));
|
||||
}
|
||||
add_action( 'after_setup_theme', 'weedops_setup' );
|
||||
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(),
|
||||
] );
|
||||
// Enqueue styles
|
||||
function weedops_scripts() {
|
||||
wp_enqueue_style('weedops-style', get_stylesheet_uri(), array(), '1.0');
|
||||
}
|
||||
add_action( 'wp_enqueue_scripts', 'weedops_enqueue_assets' );
|
||||
add_action('wp_enqueue_scripts', 'weedops_scripts');
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Custom Post Types, Taxonomies & Meta Fields
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Remove WordPress junk from head
|
||||
remove_action('wp_head', 'wp_generator');
|
||||
remove_action('wp_head', 'wlwmanifest_link');
|
||||
remove_action('wp_head', 'rsd_link');
|
||||
remove_action('wp_head', 'wp_shortlink_wp_head');
|
||||
remove_action('wp_head', 'rest_output_link_wp_head');
|
||||
remove_action('wp_head', 'wp_oembed_add_discovery_links');
|
||||
remove_action('wp_head', 'print_emoji_detection_script', 7);
|
||||
remove_action('wp_print_styles', 'print_emoji_styles');
|
||||
|
||||
// Post types, taxonomies, and meta field registration live in their own file.
|
||||
require_once WEEDOPS_DIR . '/inc/custom-post-types.php';
|
||||
// Remove WP block library CSS (not using Gutenberg blocks)
|
||||
function weedops_remove_block_css() {
|
||||
wp_dequeue_style('wp-block-library');
|
||||
wp_dequeue_style('wp-block-library-theme');
|
||||
wp_dequeue_style('classic-theme-styles');
|
||||
wp_dequeue_style('global-styles');
|
||||
}
|
||||
add_action('wp_enqueue_scripts', 'weedops_remove_block_css', 100);
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Widget Areas
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Disable Gutenberg for pages
|
||||
function weedops_disable_gutenberg($current_status, $post_type) {
|
||||
if ($post_type === 'page') return false;
|
||||
return $current_status;
|
||||
}
|
||||
add_filter('use_block_editor_for_post_type', 'weedops_disable_gutenberg', 10, 2);
|
||||
|
||||
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' ) ],
|
||||
];
|
||||
// Cloudflare Turnstile (for deck request form)
|
||||
define('WEEDOPS_TURNSTILE_SITE_KEY', '');
|
||||
define('WEEDOPS_TURNSTILE_SECRET_KEY', '');
|
||||
|
||||
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>',
|
||||
] );
|
||||
function weedops_turnstile_scripts() {
|
||||
if (WEEDOPS_TURNSTILE_SITE_KEY) {
|
||||
wp_enqueue_script('turnstile', 'https://challenges.cloudflare.com/turnstile/v0/api.js', array(), null, true);
|
||||
}
|
||||
}
|
||||
add_action( 'widgets_init', 'weedops_register_sidebars' );
|
||||
add_action('wp_enqueue_scripts', 'weedops_turnstile_scripts');
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Helper Functions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
function weedops_verify_turnstile($token) {
|
||||
if (!WEEDOPS_TURNSTILE_SECRET_KEY || empty($token)) return !WEEDOPS_TURNSTILE_SECRET_KEY;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
$response = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', array(
|
||||
'body' => array(
|
||||
'secret' => WEEDOPS_TURNSTILE_SECRET_KEY,
|
||||
'response' => $token,
|
||||
'remoteip' => $_SERVER['REMOTE_ADDR'] ?? '',
|
||||
),
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) return false;
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
return !empty($body['success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
// Handle deck request form submission (early, before headers sent)
|
||||
function weedops_handle_deck_request_init() {
|
||||
if (!isset($_POST['weedops_deck_request'])) return;
|
||||
|
||||
// Verify nonce
|
||||
if (!wp_verify_nonce($_POST['_wpnonce'] ?? '', 'weedops_deck_request')) {
|
||||
set_transient('weedops_form_error_' . $_SERVER['REMOTE_ADDR'], 'Invalid request.', 60);
|
||||
wp_redirect(home_url('/#deck'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verify Turnstile if configured
|
||||
if (WEEDOPS_TURNSTILE_SITE_KEY && !weedops_verify_turnstile($_POST['cf-turnstile-response'] ?? '')) {
|
||||
set_transient('weedops_form_error_' . $_SERVER['REMOTE_ADDR'], 'Verification failed. Please try again.', 60);
|
||||
wp_redirect(home_url('/#deck'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$name = sanitize_text_field($_POST['name'] ?? '');
|
||||
$email = sanitize_email($_POST['email'] ?? '');
|
||||
$note = sanitize_textarea_field($_POST['note'] ?? '');
|
||||
|
||||
if (empty($name) || empty($email)) {
|
||||
set_transient('weedops_form_error_' . $_SERVER['REMOTE_ADDR'], 'Name and email are required.', 60);
|
||||
wp_redirect(home_url('/#deck'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Send notification email
|
||||
$to = 'john@weedops.site';
|
||||
$subject = 'WeedOps Deck Request: ' . $name;
|
||||
$body = "Name: {$name}\nEmail: {$email}\n\nNote:\n{$note}";
|
||||
$headers = array('Reply-To: ' . $name . ' <' . $email . '>');
|
||||
|
||||
wp_mail($to, $subject, $body, $headers);
|
||||
|
||||
set_transient('weedops_form_success_' . $_SERVER['REMOTE_ADDR'], true, 60);
|
||||
wp_redirect(home_url('/#deck'));
|
||||
exit;
|
||||
}
|
||||
add_action('template_redirect', 'weedops_handle_deck_request_init');
|
||||
|
||||
/**
|
||||
* 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;
|
||||
// Get form result from transient (after redirect)
|
||||
function weedops_get_form_result() {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$success = get_transient('weedops_form_success_' . $ip);
|
||||
if ($success) {
|
||||
delete_transient('weedops_form_success_' . $ip);
|
||||
return true;
|
||||
}
|
||||
$error = get_transient('weedops_form_error_' . $ip);
|
||||
if ($error) {
|
||||
delete_transient('weedops_form_error_' . $ip);
|
||||
return $error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() => '…' );
|
||||
|
|
|
|||
100
header.php
100
header.php
|
|
@ -1,91 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<meta charset="<?php bloginfo( 'charset' ); ?>">
|
||||
<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">
|
||||
<meta name="description" content="WeedOps — managed home cannabis cultivation. A confidential investor overview.">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="icon" type="image/svg+xml" href="<?php echo get_template_directory_uri(); ?>/images/favicon.svg">
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
|
||||
<body <?php body_class(); ?>>
|
||||
|
||||
<?php wp_body_open(); ?>
|
||||
<header class="site-header">
|
||||
<nav class="nav-container">
|
||||
<a href="<?php echo home_url(); ?>" class="logo">Weed<span>Ops</span></a>
|
||||
|
||||
<?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>
|
||||
<button class="nav-toggle" aria-label="Toggle navigation" onclick="document.querySelector('.nav-links').classList.toggle('active')">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
|
||||
<?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 -->
|
||||
<ul class="nav-links">
|
||||
<li><a href="<?php echo home_url('/#opportunity'); ?>">The Opportunity</a></li>
|
||||
<li><a href="<?php echo home_url('/#model'); ?>">The Model</a></li>
|
||||
<li><a href="<?php echo home_url('/#campus'); ?>">Campus</a></li>
|
||||
<li><a href="<?php echo home_url('/#ask'); ?>">The Ask</a></li>
|
||||
<li><a href="<?php echo home_url('/#deck'); ?>" class="btn-nav">Request the Deck</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</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">
|
||||
<main>
|
||||
|
|
|
|||
|
|
@ -1,391 +0,0 @@
|
|||
<?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' );
|
||||
154
index.php
154
index.php
|
|
@ -1,144 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* Weedops — Main Template File
|
||||
*
|
||||
* Fallback template used when no more specific template matches.
|
||||
* Also serves as the blog/post archive.
|
||||
*
|
||||
* @package Weedops
|
||||
* Default template fallback — redirect to home
|
||||
*/
|
||||
|
||||
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; ?>
|
||||
<section style="padding-top: calc(var(--nav-height) + 80px); padding-bottom: 64px;">
|
||||
<div class="container">
|
||||
<h1><?php the_title(); ?></h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
<section>
|
||||
<div class="container">
|
||||
<?php
|
||||
if (have_posts()) :
|
||||
while (have_posts()) : the_post();
|
||||
the_content();
|
||||
endwhile;
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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();
|
||||
<?php get_footer(); ?>
|
||||
|
|
|
|||
|
|
@ -1,224 +0,0 @@
|
|||
<?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(); ?>
|
||||
Loading…
Add table
Reference in a new issue