Add RAR Storefront WordPress theme
Implements the Reply All Regrets™ frontend design: retro office aesthetic with manila/ink/stamp-red/olive palette, Fraunces + JetBrains Mono + Inter typography. Includes homepage, category, product detail, blog, about, cart templates with WooCommerce integration and interactive JS (filter, sort, gallery). Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
18
theme/404.php
Normal file
18
theme/404.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<section style="padding:120px 56px;text-align:center;">
|
||||
<div class="rar-form-tag" style="margin-bottom:24px;justify-content:center;">ERROR 404 · PAGE NOT FOUND · MISFILED</div>
|
||||
<h1 style="font-family:var(--serif);font-size:88px;font-weight:500;line-height:0.95;margin:0 0 24px;letter-spacing:-0.03em;">
|
||||
This page<br>has been<br><em style="color:var(--stamp);font-style:italic;">parked in the lot.</em>
|
||||
</h1>
|
||||
<p style="font-size:16px;line-height:1.6;color:var(--ink-muted);max-width:440px;margin:0 auto 40px;">
|
||||
The page you're looking for has been circled back on indefinitely.
|
||||
Try navigating from the top, or use the search.
|
||||
</p>
|
||||
<div style="display:flex;gap:12px;justify-content:center;">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>" class="rar-btn rar-btn--stamp">← Back to shop</a>
|
||||
<a href="<?php echo esc_url(get_permalink(wc_get_page_id('shop'))); ?>" class="rar-btn rar-btn--ghost">Browse products</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
69
theme/archive.php
Normal file
69
theme/archive.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* Blog index — "The Memo"
|
||||
*/
|
||||
get_header();
|
||||
?>
|
||||
|
||||
<section class="rar-blog-header">
|
||||
<div class="rar-form-tag" style="margin-bottom:22px;">FORM 09 · THE MEMO · WEEKLY DISPATCH</div>
|
||||
<div class="rar-blog-masthead">
|
||||
The Memo.<br>
|
||||
<em style="color:var(--stamp);font-style:italic;">Dispatches from the chronically employed.</em>
|
||||
</div>
|
||||
<div class="rar-blog-subtitle">PUBLISHED WEEKLY · CIRCULATE TO YOUR DEPARTMENT · VOL. 4 · NO. <?php echo date('W'); ?></div>
|
||||
</section>
|
||||
|
||||
<div class="rar-blog-body">
|
||||
<?php if (have_posts()) : ?>
|
||||
<?php
|
||||
// Featured post (first one)
|
||||
the_post();
|
||||
$thumb = get_the_post_thumbnail_url(get_the_ID(), 'rar-hero');
|
||||
$cats = get_the_category();
|
||||
$cat = $cats ? $cats[0]->name : 'Feature';
|
||||
$wc = max(1, ceil(str_word_count(strip_tags(get_the_content())) / 200));
|
||||
?>
|
||||
<a href="<?php the_permalink(); ?>" style="display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:center;margin-bottom:48px;padding-bottom:48px;border-bottom:1px solid var(--hairline-strong);cursor:pointer;color:inherit;">
|
||||
<div class="rar-blog-thumb" style="aspect-ratio:16/9;">
|
||||
<?php if ($thumb) : ?><img src="<?php echo esc_url($thumb); ?>" alt="<?php the_title_attribute(); ?>" /><?php endif; ?>
|
||||
</div>
|
||||
<div>
|
||||
<div class="rar-post-meta"><?php echo esc_html(strtoupper($cat)); ?> · <?php the_date('M j'); ?> · <?php echo $wc; ?> MIN</div>
|
||||
<h2 style="font-family:var(--serif);font-size:36px;font-weight:500;line-height:1.1;margin:0 0 16px;letter-spacing:-0.02em;"><?php the_title(); ?></h2>
|
||||
<p style="font-size:15px;line-height:1.6;color:var(--ink-muted);margin:0 0 24px;"><?php echo wp_kses_post(wp_trim_words(get_the_excerpt(), 30)); ?></p>
|
||||
<span class="rar-btn rar-btn--ghost" style="display:inline-flex;">Read dispatch →</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<?php if (have_posts()) : ?>
|
||||
<div class="rar-blog-archive">
|
||||
<?php while (have_posts()) : the_post();
|
||||
$thumb2 = get_the_post_thumbnail_url(get_the_ID(), 'rar-blog-thumb');
|
||||
$cats2 = get_the_category();
|
||||
$cat2 = $cats2 ? $cats2[0]->name : 'Notes';
|
||||
$wc2 = max(1, ceil(str_word_count(strip_tags(get_the_content())) / 200));
|
||||
?>
|
||||
<a href="<?php the_permalink(); ?>" class="rar-blog-card">
|
||||
<div class="rar-blog-thumb">
|
||||
<?php if ($thumb2) : ?><img src="<?php echo esc_url($thumb2); ?>" alt="<?php the_title_attribute(); ?>" /><?php endif; ?>
|
||||
</div>
|
||||
<div class="rar-post-meta"><?php echo esc_html(strtoupper($cat2)); ?> · <?php the_date('M j'); ?> · <?php echo $wc2; ?> MIN</div>
|
||||
<div class="rar-post-title"><?php the_title(); ?></div>
|
||||
</a>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:48px;">
|
||||
<?php the_posts_pagination(['mid_size' => 2]); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php else : ?>
|
||||
<p style="font-family:var(--serif);font-size:24px;font-style:italic;color:var(--ink-muted);">
|
||||
Nothing dispatched yet. The memo is delayed. (Again.)
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
4
theme/footer.php
Normal file
4
theme/footer.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php rar_footer_content(); ?>
|
||||
<?php wp_footer(); ?>
|
||||
</body>
|
||||
</html>
|
||||
349
theme/front-page.php
Normal file
349
theme/front-page.php
Normal file
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
/**
|
||||
* Homepage / Front page
|
||||
* Sections: Hero · Categories · Featured Products · Designs · Quote · Blog · Footer
|
||||
*/
|
||||
get_header();
|
||||
|
||||
// Fetch featured/bestselling products
|
||||
$featured_products = wc_get_products([
|
||||
'limit' => 6,
|
||||
'status' => 'publish',
|
||||
'orderby' => 'popularity',
|
||||
'order' => 'DESC',
|
||||
]);
|
||||
|
||||
// Fetch product categories
|
||||
$categories = get_terms([
|
||||
'taxonomy' => 'product_cat',
|
||||
'hide_empty' => true,
|
||||
'parent' => 0,
|
||||
'number' => 4,
|
||||
'exclude' => [get_option('default_product_cat')],
|
||||
]);
|
||||
|
||||
// Fetch recent blog posts
|
||||
$blog_posts = get_posts([
|
||||
'numberposts' => 3,
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'post',
|
||||
]);
|
||||
|
||||
// Shop URL
|
||||
$shop_url = get_permalink(wc_get_page_id('shop'));
|
||||
?>
|
||||
|
||||
<!-- ═══ HERO ═══════════════════════════════════════════════════════════════ -->
|
||||
<section class="rar-hero">
|
||||
<div class="rar-hero__grid">
|
||||
<div>
|
||||
<div class="rar-form-tag" style="margin-bottom:22px;">FORM 01 · NEW ARRIVALS · WEEK <?php echo date('W'); ?></div>
|
||||
<h1>
|
||||
Office<br>
|
||||
supplies for<br>
|
||||
<em class="rar-hero__em">people who hate</em><br>
|
||||
the office.
|
||||
</h1>
|
||||
<p class="rar-hero__sub">
|
||||
Mugs, canvases, planners, and apparel for the chronically CC'd. Each item
|
||||
is a quiet rebellion you can drink coffee out of. Synergize responsibly.
|
||||
</p>
|
||||
<div class="rar-hero__cta">
|
||||
<a href="<?php echo esc_url($shop_url); ?>" class="rar-btn rar-btn--stamp">
|
||||
Shop the catalog
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 5l7 7-7 7"></path></svg>
|
||||
</a>
|
||||
<a href="<?php echo esc_url(home_url('/blog/')); ?>" class="rar-btn rar-btn--ghost">Read the memo</a>
|
||||
<span class="rar-hero__meta"><?php echo wp_count_posts('product')->publish; ?> items · ships in 3-5 biz days</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rar-hero__image">
|
||||
<?php
|
||||
// Show the hero product if available
|
||||
$hero_products = wc_get_products(['limit' => 1, 'featured' => true, 'status' => 'publish']);
|
||||
if (!empty($hero_products)) {
|
||||
$hp = $hero_products[0];
|
||||
$img_id = $hp->get_image_id();
|
||||
if ($img_id) {
|
||||
echo wp_get_attachment_image($img_id, 'rar-hero', false, ['style' => 'position:absolute;inset:0;width:100%;height:100%;object-fit:cover;']);
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="rar-hero__image-label">FIG. 1 — HERO PRODUCT · 11OZ CERAMIC</div>
|
||||
<div class="rar-hero__stamp"><span class="rar-stamp">Best Seller</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Metrics row -->
|
||||
<div class="rar-metrics">
|
||||
<?php
|
||||
$metrics = [
|
||||
['142,038', 'Reply-Alls regretted'],
|
||||
['41 states', 'Currently shipping'],
|
||||
['4.8 ★', 'Avg. on Trustpilot'],
|
||||
['0', 'Calls returned'],
|
||||
];
|
||||
foreach ($metrics as [$num, $label]) {
|
||||
echo '<div class="rar-metrics__item">';
|
||||
echo '<div class="rar-metrics__num rar-serif">' . esc_html($num) . '</div>';
|
||||
echo '<div class="rar-metrics__label">' . esc_html($label) . '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══ CATEGORIES ══════════════════════════════════════════════════════════ -->
|
||||
<section class="rar-cats">
|
||||
<?php rar_section_head('FORM 02 · DEPARTMENTS', 'Shop by category', 'FILED QUARTERLY<br/>SEE INDEX P. 4'); ?>
|
||||
<div class="rar-cats__grid">
|
||||
<?php
|
||||
$cat_meta = [
|
||||
'mugs' => ['DEPT. 01', 'For passive aggression at room temp.'],
|
||||
'canvas' => ['DEPT. 02', 'Wall art for the soul-tired.'],
|
||||
'planners' => ['DEPT. 03', 'Productivity, with a wink.'],
|
||||
'apparel' => ['DEPT. 04', 'Casual Friday, but make it bitter.'],
|
||||
];
|
||||
|
||||
if (!empty($categories)) {
|
||||
foreach ($categories as $i => $cat) {
|
||||
$slug = $cat->slug;
|
||||
$meta = $cat_meta[$slug] ?? ['DEPT. 0' . ($i + 1), $cat->description ?: 'Office essentials.'];
|
||||
$url = get_term_link($cat);
|
||||
?>
|
||||
<a href="<?php echo esc_url($url); ?>" class="rar-cat-card">
|
||||
<div class="rar-cat-card__header">
|
||||
<span class="rar-cat-card__sku"><?php echo esc_html($meta[0]); ?></span>
|
||||
<span class="rar-cat-card__count"><?php echo esc_html($cat->count); ?> items</span>
|
||||
</div>
|
||||
<div class="rar-cat-card__name"><?php echo esc_html($cat->name); ?></div>
|
||||
<div class="rar-cat-card__desc"><?php echo esc_html($meta[1]); ?></div>
|
||||
<span class="rar-cat-card__browse">
|
||||
Browse
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 5l7 7-7 7"></path></svg>
|
||||
</span>
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
// Fallback static categories
|
||||
$static_cats = [
|
||||
['Mugs', 'DEPT. 01', 47, 'For passive aggression at room temp.', '/product-category/mugs/'],
|
||||
['Canvas', 'DEPT. 02', 18, 'Wall art for the soul-tired.', '/product-category/canvas/'],
|
||||
['Planners', 'DEPT. 03', 12, 'Productivity, with a wink.', '/product-category/planners/'],
|
||||
['Apparel', 'DEPT. 04', 24, 'Casual Friday, but make it bitter.', '/product-category/apparel/'],
|
||||
];
|
||||
foreach ($static_cats as [$name, $sku, $count, $desc, $path]) {
|
||||
?>
|
||||
<a href="<?php echo esc_url(home_url($path)); ?>" class="rar-cat-card">
|
||||
<div class="rar-cat-card__header">
|
||||
<span class="rar-cat-card__sku"><?php echo esc_html($sku); ?></span>
|
||||
<span class="rar-cat-card__count"><?php echo esc_html($count); ?> items</span>
|
||||
</div>
|
||||
<div class="rar-cat-card__name"><?php echo esc_html($name); ?></div>
|
||||
<div class="rar-cat-card__desc"><?php echo esc_html($desc); ?></div>
|
||||
<span class="rar-cat-card__browse">Browse →</span>
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══ FEATURED PRODUCTS ═══════════════════════════════════════════════════ -->
|
||||
<section class="rar-products">
|
||||
<?php rar_section_head('FORM 03 · FEATURED INVENTORY', 'The bestsellers.', 'UPDATED ' . strtoupper(date('m.d.Y')) . '<br/>SUBJECT TO CHANGE'); ?>
|
||||
<div class="rar-products__grid">
|
||||
<?php if (!empty($featured_products)) : ?>
|
||||
<?php foreach ($featured_products as $product) : ?>
|
||||
<?php
|
||||
$img_id = $product->get_image_id();
|
||||
$img_url = $img_id ? wp_get_attachment_image_url($img_id, 'rar-product-card') : '';
|
||||
$sku = $product->get_sku() ?: 'SKU-' . $product->get_id();
|
||||
$cat_terms = get_the_terms($product->get_id(), 'product_cat');
|
||||
$cat_name = $cat_terms ? $cat_terms[0]->name : 'Product';
|
||||
$price = $product->get_price_html();
|
||||
$url = get_permalink($product->get_id());
|
||||
?>
|
||||
<a href="<?php echo esc_url($url); ?>" class="rar-card">
|
||||
<div class="rar-card__media">
|
||||
<div class="rar-card__sku">SKU <?php echo esc_html($sku); ?></div>
|
||||
<?php if ($img_url) : ?>
|
||||
<img src="<?php echo esc_url($img_url); ?>" alt="<?php echo esc_attr($product->get_name()); ?>" />
|
||||
<?php else : ?>
|
||||
<div class="rar-placeholder__label"><?php echo esc_html(strtoupper($cat_name)); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($product->is_featured()) : ?>
|
||||
<div class="rar-card__badge">Featured</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="rar-card__body">
|
||||
<div class="rar-card__cat"><?php echo esc_html($cat_name); ?></div>
|
||||
<div class="rar-card__title"><?php echo esc_html($product->get_name()); ?></div>
|
||||
<div class="rar-card__row">
|
||||
<span class="rar-card__price"><?php echo wp_kses_post($price); ?></span>
|
||||
<span style="color:var(--ink-muted);display:inline-flex;align-items:center;gap:4px;">
|
||||
View ·
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 5l7 7-7 7"></path></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<!-- Placeholder cards -->
|
||||
<?php
|
||||
$placeholders = [
|
||||
['001-A', 'Drinkware', 'Per My Last Email', '$24'],
|
||||
['012-C', 'Wall Decor', 'Sent From My Deathbed', '$58'],
|
||||
['034-B', 'Stationery', "The Quiet Quitter's Planner", '$32'],
|
||||
['007-D', 'Drinkware', 'Looping In For Visibility', '$24'],
|
||||
['021-A', 'Apparel', 'OOO Forever Tee', '$36'],
|
||||
['045-F', 'Stickers', 'Circle-Back Sticker Pack', '$8'],
|
||||
];
|
||||
foreach ($placeholders as [$sku, $cat, $title, $price]) {
|
||||
?>
|
||||
<a href="<?php echo esc_url($shop_url); ?>" class="rar-card">
|
||||
<div class="rar-card__media">
|
||||
<div class="rar-card__sku">SKU <?php echo esc_html($sku); ?></div>
|
||||
<div class="rar-placeholder__label"><?php echo esc_html(strtoupper($cat)); ?></div>
|
||||
</div>
|
||||
<div class="rar-card__body">
|
||||
<div class="rar-card__cat"><?php echo esc_html($cat); ?></div>
|
||||
<div class="rar-card__title"><?php echo esc_html($title); ?></div>
|
||||
<div class="rar-card__row">
|
||||
<span class="rar-card__price"><?php echo esc_html($price); ?></span>
|
||||
<span style="color:var(--ink-muted);">View →</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══ SHOP BY DESIGN ═══════════════════════════════════════════════════════ -->
|
||||
<section class="rar-designs">
|
||||
<?php rar_section_head('FORM 04 · SHOP BY DESIGN', 'One slogan, many surfaces.', '9 DESIGNS · 47 SKUS<br/>SEE FULL CATALOG →'); ?>
|
||||
<p style="font-size:14px;line-height:1.6;color:var(--ink-muted);max-width:560px;margin:-16px 0 32px;">
|
||||
Every design lives across multiple products. Pick a phrase you'd like to commit to
|
||||
and we'll show you every form it ships in — mug, canvas, tee, sticker, the works.
|
||||
</p>
|
||||
<div class="rar-designs__grid">
|
||||
<?php
|
||||
$designs = [
|
||||
['Per My Last Email', 'Passive Aggressive', 'paper', ['Per my', 'last email'], 8],
|
||||
['Sent from my Deathbed','Email Signatures', 'ink', ['Sent from', 'my deathbed'], 6],
|
||||
['The Quiet Quitter', 'Lifestyle', 'olive', ['Quietly', 'quitting'], 5],
|
||||
["OOO Forever", 'Vacation Mode', 'paper', ['OOO', 'forever'], 7],
|
||||
["Let's Circle Back", 'Meeting Recovery', 'ink', ['Circle', 'back ↻'], 4],
|
||||
['My Plate Is Full', 'Capacity Issues', 'paper', ['My plate', 'is full.'], 5],
|
||||
];
|
||||
$color_map = [
|
||||
'paper' => ['bg' => '#FBF8EF', 'fg' => '#1A1A1A'],
|
||||
'ink' => ['bg' => '#1A1A1A', 'fg' => '#F5F1E8'],
|
||||
'olive' => ['bg' => '#7B8C5A', 'fg' => '#F5F1E8'],
|
||||
];
|
||||
foreach ($designs as [$title, $tag, $color, $lines, $count]) {
|
||||
$cm = $color_map[$color];
|
||||
$designs_url = home_url('/designs/');
|
||||
?>
|
||||
<a href="<?php echo esc_url($designs_url); ?>" class="rar-card">
|
||||
<div class="rar-card__media" style="aspect-ratio:5/3;">
|
||||
<div style="width:82%;aspect-ratio:4/2.4;background:<?php echo esc_attr($cm['bg']); ?>;border:1.5px solid var(--ink);display:flex;flex-direction:column;align-items:center;justify-content:center;color:<?php echo esc_attr($cm['fg']); ?>;font-family:var(--serif);font-style:italic;font-weight:500;font-size:20px;line-height:1.15;text-align:center;padding:10px;">
|
||||
<?php foreach ($lines as $line) echo '<div>' . esc_html($line) . '</div>'; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rar-card__body">
|
||||
<div class="rar-card__cat"><?php echo esc_html($tag); ?></div>
|
||||
<div class="rar-card__title"><?php echo esc_html($title); ?></div>
|
||||
<div class="rar-card__row">
|
||||
<span class="rar-card__price"><?php echo esc_html($count); ?> products</span>
|
||||
<span style="color:var(--ink-muted);display:inline-flex;align-items:center;gap:4px;">
|
||||
Shop design ·
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 5l7 7-7 7"></path></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:center;margin-top:32px;">
|
||||
<a href="<?php echo esc_url(home_url('/designs/')); ?>" class="rar-btn rar-btn--ghost">Browse all designs →</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══ TESTIMONIAL / EDITORIAL ═════════════════════════════════════════════ -->
|
||||
<section class="rar-editorial">
|
||||
<div class="rar-editorial__memo">MEMO 04 · CC: THE DESK-BOUND</div>
|
||||
<div class="rar-editorial__inner">
|
||||
<div class="rar-editorial__as-seen">❝ AS SEEN IN ❞</div>
|
||||
<blockquote class="rar-editorial__quote">
|
||||
"Finally, a brand that gets that the meeting could have been an email,
|
||||
and the email could have been silence."
|
||||
</blockquote>
|
||||
<div class="rar-editorial__attr">— The Cubicle Quarterly · <?php echo date('M Y'); ?></div>
|
||||
<div class="rar-editorial__press">
|
||||
<span>FAST CO.</span>
|
||||
<span>OFFICE LIFE MAG</span>
|
||||
<span>THE PROCRASTINATOR</span>
|
||||
<span>HR WEEKLY (REGRETTABLY)</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ═══ FROM THE BLOG ════════════════════════════════════════════════════════ -->
|
||||
<?php if (!empty($blog_posts)) : ?>
|
||||
<section class="rar-blog-section">
|
||||
<?php rar_section_head('FORM 05 · FROM THE MEMO', 'Recent dispatches.', 'WEEKLY ISSUE<br/>VOL. 4 · NO. ' . date('W')); ?>
|
||||
<div class="rar-blog-grid">
|
||||
<?php foreach ($blog_posts as $post) :
|
||||
setup_postdata($post);
|
||||
$thumb_url = get_the_post_thumbnail_url($post->ID, 'rar-blog-thumb');
|
||||
$cats = get_the_category($post->ID);
|
||||
$cat_name = $cats ? $cats[0]->name : 'Field Notes';
|
||||
$read_time = max(1, ceil(str_word_count(strip_tags(get_post_field('post_content', $post->ID))) / 200));
|
||||
?>
|
||||
<a href="<?php the_permalink($post->ID); ?>" class="rar-blog-card">
|
||||
<div class="rar-blog-card__thumb">
|
||||
<?php if ($thumb_url) : ?>
|
||||
<img src="<?php echo esc_url($thumb_url); ?>" alt="<?php echo esc_attr($post->post_title); ?>" />
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="rar-blog-card__tag"><?php echo esc_html(strtoupper($cat_name)); ?> · <?php echo strtoupper(date('M j', strtotime($post->post_date))); ?> · <?php echo esc_html($read_time); ?> MIN</div>
|
||||
<div class="rar-blog-card__title"><?php echo esc_html($post->post_title); ?></div>
|
||||
</a>
|
||||
<?php endforeach; wp_reset_postdata(); ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php else : ?>
|
||||
<section class="rar-blog-section">
|
||||
<?php rar_section_head('FORM 05 · FROM THE MEMO', 'Recent dispatches.', 'WEEKLY ISSUE<br/>VOL. 4 · NO. 17'); ?>
|
||||
<div class="rar-blog-grid">
|
||||
<?php
|
||||
$static_posts = [
|
||||
['Field Notes', 'A taxonomy of "circle back" — when it means goodbye and when it means war.', 'APR 28', '6'],
|
||||
['Investigation', 'We surveyed 400 office workers on which mug they hate the most.', 'APR 22', '11'],
|
||||
['Op-Ed', 'In defense of the calendar block titled "Focus" that is just a nap.', 'APR 14', '4'],
|
||||
];
|
||||
foreach ($static_posts as [$tag, $title, $date, $read]) {
|
||||
?>
|
||||
<a href="<?php echo esc_url(home_url('/blog/')); ?>" class="rar-blog-card">
|
||||
<div class="rar-blog-card__thumb"></div>
|
||||
<div class="rar-blog-card__tag"><?php echo esc_html(strtoupper($tag)); ?> · <?php echo esc_html($date); ?> · <?php echo esc_html($read); ?> MIN</div>
|
||||
<div class="rar-blog-card__title"><?php echo esc_html($title); ?></div>
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
323
theme/functions.php
Normal file
323
theme/functions.php
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
/**
|
||||
* RAR Storefront — Theme functions
|
||||
* Reply All Regrets™ WooCommerce theme
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
// ─── Theme Setup ────────────────────────────────────────────────────────────
|
||||
function rar_setup() {
|
||||
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('woocommerce');
|
||||
add_theme_support('wc-product-gallery-zoom');
|
||||
add_theme_support('wc-product-gallery-lightbox');
|
||||
add_theme_support('wc-product-gallery-slider');
|
||||
add_theme_support('custom-logo');
|
||||
add_theme_support('automatic-feed-links');
|
||||
add_theme_support('align-wide');
|
||||
|
||||
register_nav_menus([
|
||||
'primary' => __('Primary Navigation', 'rar-storefront'),
|
||||
'footer' => __('Footer Navigation', 'rar-storefront'),
|
||||
]);
|
||||
}
|
||||
add_action('after_setup_theme', 'rar_setup');
|
||||
|
||||
// ─── Enqueue Assets ─────────────────────────────────────────────────────────
|
||||
function rar_enqueue_assets() {
|
||||
// Google Fonts
|
||||
wp_enqueue_style(
|
||||
'rar-fonts',
|
||||
'https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,400;1,9..144,500&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap',
|
||||
[],
|
||||
null
|
||||
);
|
||||
|
||||
// Theme stylesheet
|
||||
wp_enqueue_style('rar-style', get_stylesheet_uri(), ['rar-fonts'], '1.0.0');
|
||||
|
||||
// Theme JS
|
||||
wp_enqueue_script('rar-main', get_template_directory_uri() . '/js/rar.js', [], '1.0.0', true);
|
||||
|
||||
// Pass data to JS
|
||||
wp_localize_script('rar-main', 'rarData', [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('rar-nonce'),
|
||||
'cartUrl' => wc_get_cart_url(),
|
||||
'shopUrl' => get_permalink(wc_get_page_id('shop')),
|
||||
]);
|
||||
}
|
||||
add_action('wp_enqueue_scripts', 'rar_enqueue_assets');
|
||||
|
||||
// ─── Remove default WC styles we override ───────────────────────────────────
|
||||
add_filter('woocommerce_enqueue_styles', function($styles) {
|
||||
// Keep WooCommerce core but remove some defaults we fully override
|
||||
return $styles;
|
||||
});
|
||||
|
||||
// ─── Widget Areas ────────────────────────────────────────────────────────────
|
||||
function rar_register_sidebars() {
|
||||
register_sidebar([
|
||||
'name' => 'Shop Filter Sidebar',
|
||||
'id' => 'shop-filter',
|
||||
'before_widget' => '<div class="rar-filter-widget">',
|
||||
'after_widget' => '</div>',
|
||||
'before_title' => '<h4 class="rar-filter-widget__title">',
|
||||
'after_title' => '</h4>',
|
||||
]);
|
||||
}
|
||||
add_action('widgets_init', 'rar_register_sidebars');
|
||||
|
||||
// ─── WooCommerce: remove default wrappers ───────────────────────────────────
|
||||
remove_action('woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10);
|
||||
remove_action('woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10);
|
||||
|
||||
add_action('woocommerce_before_main_content', function() {
|
||||
echo '<div class="rar-wc-wrap">';
|
||||
});
|
||||
add_action('woocommerce_after_main_content', function() {
|
||||
echo '</div>';
|
||||
});
|
||||
|
||||
// ─── Remove WC breadcrumb (we build our own) ────────────────────────────────
|
||||
remove_action('woocommerce_before_main_content', 'woocommerce_breadcrumb', 20);
|
||||
|
||||
// ─── Product loop: 3 columns ────────────────────────────────────────────────
|
||||
add_filter('loop_shop_columns', fn() => 3);
|
||||
add_filter('loop_shop_per_page', fn() => 12, 20);
|
||||
|
||||
// ─── Custom product loop template ───────────────────────────────────────────
|
||||
add_filter('woocommerce_product_loop_start', function($html) {
|
||||
return '<ul class="rar-product-grid products">';
|
||||
});
|
||||
add_filter('woocommerce_product_loop_end', function($html) {
|
||||
return '</ul>';
|
||||
});
|
||||
|
||||
// ─── Helper: announcement bar ───────────────────────────────────────────────
|
||||
function rar_announcement_bar() {
|
||||
$msg = get_option('rar_announcement', 'FREE DESK-CHAIR DELIVERY ON ORDERS OVER $40 · CIRCULATE TO YOUR TEAM · DOC. REV. 04.26');
|
||||
if ($msg) {
|
||||
echo '<div class="rar-bar">' . esc_html($msg) . '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Helper: nav ────────────────────────────────────────────────────────────
|
||||
function rar_nav() {
|
||||
$cart_count = WC()->cart ? WC()->cart->get_cart_contents_count() : 0;
|
||||
$cart_url = wc_get_cart_url();
|
||||
$shop_url = get_permalink(wc_get_page_id('shop'));
|
||||
?>
|
||||
<nav class="rar-nav" id="rar-nav">
|
||||
<div class="rar-nav__logo">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>" class="rar-nav__logo-mark">Reply All Regrets™</a>
|
||||
<span class="rar-nav__logo-sub">EST. 2024 · INTERNAL USE ONLY</span>
|
||||
</div>
|
||||
<div class="rar-nav__links">
|
||||
<?php
|
||||
wp_nav_menu([
|
||||
'theme_location' => 'primary',
|
||||
'container' => false,
|
||||
'items_wrap' => '%3$s',
|
||||
'fallback_cb' => function() use ($shop_url) {
|
||||
$links = [
|
||||
['Shop', $shop_url],
|
||||
['Designs', home_url('/designs/')],
|
||||
['Mugs', home_url('/product-category/mugs/')],
|
||||
['Canvas', home_url('/product-category/canvas/')],
|
||||
['Planners', home_url('/product-category/planners/')],
|
||||
['Apparel', home_url('/product-category/apparel/')],
|
||||
['The Memo', home_url('/blog/')],
|
||||
['About', home_url('/about/')],
|
||||
];
|
||||
foreach ($links as [$label, $url]) {
|
||||
echo '<a href="' . esc_url($url) . '">' . esc_html($label) . '</a>';
|
||||
}
|
||||
},
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<div class="rar-nav__icons">
|
||||
<a href="<?php echo esc_url(home_url('/?s=')); ?>" aria-label="Search">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="11" cy="11" r="7"></circle><path d="m20 20-3.5-3.5"></path>
|
||||
</svg>
|
||||
Search
|
||||
</a>
|
||||
<a href="<?php echo esc_url(get_permalink(wc_get_page_id('myaccount'))); ?>" aria-label="Account">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="8" r="4"></circle>
|
||||
<path d="M4 21c1.5-4.5 5-7 8-7s6.5 2.5 8 7"></path>
|
||||
</svg>
|
||||
Account
|
||||
</a>
|
||||
<a href="<?php echo esc_url($cart_url); ?>" class="rar-nav__cart">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 4h2l2.5 12h11l2-8H6"></path>
|
||||
<circle cx="9" cy="20" r="1.5"></circle><circle cx="17" cy="20" r="1.5"></circle>
|
||||
</svg>
|
||||
Cart (<?php echo esc_html($cart_count); ?>)
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
<?php
|
||||
}
|
||||
|
||||
// ─── Helper: footer ─────────────────────────────────────────────────────────
|
||||
function rar_footer_content() {
|
||||
$shop_url = get_permalink(wc_get_page_id('shop'));
|
||||
?>
|
||||
<footer class="rar-footer">
|
||||
<div class="rar-footer__grid">
|
||||
<div>
|
||||
<div style="font-family:var(--serif);font-size:28px;margin-bottom:8px;">Reply All Regrets™</div>
|
||||
<p style="font-family:var(--mono);font-size:11px;line-height:1.7;color:rgba(245,241,232,0.7);max-width:280px;margin:0;">
|
||||
Deliverables for the chronically employed. Filed quarterly,<br>
|
||||
shipped from a warehouse in Cleveland.
|
||||
</p>
|
||||
<div class="rar-footer__newsletter">
|
||||
<?php echo do_shortcode('[mc4wp_form id="1"]'); ?>
|
||||
<input type="email" placeholder="your.name@workplace.com" aria-label="Email for newsletter" id="rar-newsletter-email" />
|
||||
<button class="rar-btn rar-btn--stamp" style="padding:10px 16px;" onclick="document.getElementById('rar-newsletter-email').form && document.getElementById('rar-newsletter-email').form.submit()">CC: ME →</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rar-footer__col">
|
||||
<div class="rar-footer__col-title">Departments</div>
|
||||
<ul>
|
||||
<li><a href="<?php echo esc_url(home_url('/product-category/mugs/')); ?>">Mugs</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/product-category/canvas/')); ?>">Canvases</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/product-category/planners/')); ?>">Planners</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/product-category/apparel/')); ?>">Apparel</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/bulk/')); ?>">Bulk / HR</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="rar-footer__col">
|
||||
<div class="rar-footer__col-title">Company</div>
|
||||
<ul>
|
||||
<li><a href="<?php echo esc_url(home_url('/about/')); ?>">About</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/blog/')); ?>">The Memo (blog)</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/press/')); ?>">Press</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/careers/')); ?>">Careers</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/wholesale/')); ?>">Wholesale</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="rar-footer__col">
|
||||
<div class="rar-footer__col-title">Form 9-A: Help</div>
|
||||
<ul>
|
||||
<li><a href="<?php echo esc_url(home_url('/shipping/')); ?>">Shipping</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/returns/')); ?>">Returns & Grievances</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/order-status/')); ?>">Order Status</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/contact/')); ?>">Contact (no calls)</a></li>
|
||||
<li><a href="<?php echo esc_url(home_url('/faq/')); ?>">FAQ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rar-footer__legal">
|
||||
<span>© <?php echo date('Y'); ?> RAR HOLDINGS LLC · ALL RIGHTS RESERVED</span>
|
||||
<span>
|
||||
<a href="<?php echo esc_url(home_url('/terms/')); ?>">TERMS</a> ·
|
||||
<a href="<?php echo esc_url(get_privacy_policy_url()); ?>">PRIVACY</a> ·
|
||||
<a href="<?php echo esc_url(home_url('/accessibility/')); ?>">ACCESSIBILITY</a>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
<?php
|
||||
}
|
||||
|
||||
// ─── Helper: breadcrumb ─────────────────────────────────────────────────────
|
||||
function rar_breadcrumb() {
|
||||
echo '<div class="rar-breadcrumb">';
|
||||
if (function_exists('woocommerce_breadcrumb')) {
|
||||
woocommerce_breadcrumb(['wrap_before' => '', 'wrap_after' => '', 'before' => '', 'after' => '', 'delimiter' => ' / ']);
|
||||
} else {
|
||||
echo '<a href="' . esc_url(home_url('/')) . '">Home</a> / ';
|
||||
if (is_singular()) {
|
||||
echo '<span>' . get_the_title() . '</span>';
|
||||
} elseif (is_archive()) {
|
||||
echo '<span>' . get_the_archive_title() . '</span>';
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// ─── Helper: section header ──────────────────────────────────────────────────
|
||||
function rar_section_head($form, $title, $meta = '') {
|
||||
echo '<div class="rar-section-head">';
|
||||
echo '<div>';
|
||||
echo '<div class="rar-form-tag" style="margin-bottom:10px;">' . esc_html($form) . '</div>';
|
||||
echo '<h2>' . esc_html($title) . '</h2>';
|
||||
echo '</div>';
|
||||
if ($meta) {
|
||||
echo '<div class="rar-section-head__meta">' . wp_kses_post($meta) . '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// ─── Add WooCommerce cart fragment support ───────────────────────────────────
|
||||
add_filter('woocommerce_add_to_cart_fragments', function($fragments) {
|
||||
$cart_count = WC()->cart->get_cart_contents_count();
|
||||
$fragments['.rar-nav__cart'] = '<a href="' . esc_url(wc_get_cart_url()) . '" class="rar-nav__cart">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 4h2l2.5 12h11l2-8H6"></path>
|
||||
<circle cx="9" cy="20" r="1.5"></circle><circle cx="17" cy="20" r="1.5"></circle>
|
||||
</svg>
|
||||
Cart (' . $cart_count . ')
|
||||
</a>';
|
||||
return $fragments;
|
||||
});
|
||||
|
||||
// ─── Custom image sizes ──────────────────────────────────────────────────────
|
||||
add_image_size('rar-product-card', 600, 600, true);
|
||||
add_image_size('rar-blog-thumb', 800, 450, true);
|
||||
add_image_size('rar-hero', 900, 1125, true);
|
||||
|
||||
// ─── Page templates ──────────────────────────────────────────────────────────
|
||||
add_filter('theme_page_templates', function($templates) {
|
||||
$templates['page-designs.php'] = 'Designs Index';
|
||||
$templates['page-design-detail.php'] = 'Design Detail';
|
||||
$templates['page-about.php'] = 'About';
|
||||
return $templates;
|
||||
});
|
||||
|
||||
// ─── AJAX: add to cart from homepage ────────────────────────────────────────
|
||||
add_action('wp_ajax_rar_add_to_cart', 'rar_ajax_add_to_cart');
|
||||
add_action('wp_ajax_nopriv_rar_add_to_cart', 'rar_ajax_add_to_cart');
|
||||
function rar_ajax_add_to_cart() {
|
||||
check_ajax_referer('rar-nonce', 'nonce');
|
||||
$product_id = absint($_POST['product_id'] ?? 0);
|
||||
$qty = absint($_POST['qty'] ?? 1);
|
||||
if ($product_id) {
|
||||
WC()->cart->add_to_cart($product_id, $qty);
|
||||
wp_send_json_success(['count' => WC()->cart->get_cart_contents_count()]);
|
||||
}
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// ─── Customizer settings ─────────────────────────────────────────────────────
|
||||
add_action('customize_register', function($wp_customize) {
|
||||
$wp_customize->add_section('rar_options', [
|
||||
'title' => __('Reply All Regrets Settings', 'rar-storefront'),
|
||||
'priority' => 30,
|
||||
]);
|
||||
$wp_customize->add_setting('rar_announcement', [
|
||||
'default' => 'FREE DESK-CHAIR DELIVERY ON ORDERS OVER $40 · CIRCULATE TO YOUR TEAM · DOC. REV. 04.26',
|
||||
'transport' => 'refresh',
|
||||
]);
|
||||
$wp_customize->add_control('rar_announcement', [
|
||||
'label' => __('Announcement Bar Text', 'rar-storefront'),
|
||||
'section' => 'rar_options',
|
||||
'type' => 'text',
|
||||
]);
|
||||
$wp_customize->add_setting('rar_hero_tagline', [
|
||||
'default' => 'Office supplies for people who hate the office.',
|
||||
'transport' => 'postMessage',
|
||||
]);
|
||||
$wp_customize->add_control('rar_hero_tagline', [
|
||||
'label' => __('Hero Tagline', 'rar-storefront'),
|
||||
'section' => 'rar_options',
|
||||
'type' => 'textarea',
|
||||
]);
|
||||
});
|
||||
12
theme/header.php
Normal file
12
theme/header.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<meta charset="<?php bloginfo('charset'); ?>" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
<body <?php body_class(); ?>>
|
||||
<?php wp_body_open(); ?>
|
||||
|
||||
<?php rar_announcement_bar(); ?>
|
||||
<?php rar_nav(); ?>
|
||||
24
theme/index.php
Normal file
24
theme/index.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<div style="padding:64px 56px;">
|
||||
<?php if (have_posts()) : ?>
|
||||
<div class="rar-blog-archive">
|
||||
<?php while (have_posts()) : the_post(); ?>
|
||||
<a href="<?php the_permalink(); ?>" class="rar-blog-card">
|
||||
<?php if (has_post_thumbnail()) : ?>
|
||||
<div class="rar-blog-thumb"><?php the_post_thumbnail('rar-blog-thumb'); ?></div>
|
||||
<?php else : ?>
|
||||
<div class="rar-blog-thumb"></div>
|
||||
<?php endif; ?>
|
||||
<div class="rar-post-meta"><?php the_category(' · '); ?> · <?php the_date('M j, Y'); ?></div>
|
||||
<div class="rar-post-title"><?php the_title(); ?></div>
|
||||
</a>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php the_posts_pagination(); ?>
|
||||
<?php else : ?>
|
||||
<p style="font-family:var(--serif);font-size:24px;">Nothing filed yet. Check back later.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
230
theme/js/rar.js
Normal file
230
theme/js/rar.js
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Reply All Regrets — Interactive features
|
||||
* Filter sidebar, sort, view toggle, gallery switcher, qty controls
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// ─── Gallery switcher ────────────────────────────────────────────────────
|
||||
window.rarSwitchGallery = function (index, url) {
|
||||
var img = document.getElementById('rar-gallery-img');
|
||||
var counter = document.getElementById('rar-gallery-counter');
|
||||
var label = document.getElementById('rar-gallery-label');
|
||||
var thumbs = document.querySelectorAll('.rar-gallery__thumb');
|
||||
|
||||
if (img) img.src = url;
|
||||
if (counter) counter.textContent = index + 1;
|
||||
if (label) label.textContent = 'FIG. ' + (index + 1) + ' — PRODUCT VIEW';
|
||||
|
||||
thumbs.forEach(function (t, i) {
|
||||
t.classList.toggle('active', i === index);
|
||||
});
|
||||
};
|
||||
|
||||
// ─── Grid / List view toggle ─────────────────────────────────────────────
|
||||
window.rarSetView = function (view) {
|
||||
var grid = document.getElementById('rar-product-grid');
|
||||
var gridBtn = document.getElementById('rar-grid-btn');
|
||||
var listBtn = document.getElementById('rar-list-btn');
|
||||
|
||||
if (!grid) return;
|
||||
|
||||
if (view === 'list') {
|
||||
grid.classList.add('list-view');
|
||||
if (gridBtn) gridBtn.classList.remove('active');
|
||||
if (listBtn) listBtn.classList.add('active');
|
||||
} else {
|
||||
grid.classList.remove('list-view');
|
||||
if (gridBtn) gridBtn.classList.add('active');
|
||||
if (listBtn) listBtn.classList.remove('active');
|
||||
}
|
||||
|
||||
try { localStorage.setItem('rar-view', view); } catch (e) {}
|
||||
};
|
||||
|
||||
// Restore saved view preference
|
||||
(function () {
|
||||
try {
|
||||
var saved = localStorage.getItem('rar-view');
|
||||
if (saved === 'list') { rarSetView('list'); }
|
||||
} catch (e) {}
|
||||
})();
|
||||
|
||||
// ─── Sort menu close on outside click ────────────────────────────────────
|
||||
document.addEventListener('click', function (e) {
|
||||
var sortMenu = document.getElementById('rar-sort-menu');
|
||||
var sortBtn = document.querySelector('.rar-sort-btn');
|
||||
if (sortMenu && !sortMenu.contains(e.target) && sortBtn && !sortBtn.contains(e.target)) {
|
||||
sortMenu.classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
// ─── Filter: category/attribute ──────────────────────────────────────────
|
||||
window.rarApplyFilter = function (checkbox) {
|
||||
var url = new URL(window.location.href);
|
||||
if (checkbox.checked) {
|
||||
url.searchParams.set(checkbox.name, checkbox.value);
|
||||
} else {
|
||||
url.searchParams.delete(checkbox.name);
|
||||
}
|
||||
window.location.href = url.toString();
|
||||
};
|
||||
|
||||
window.rarPriceFilter = function (checkbox) {
|
||||
var url = new URL(window.location.href);
|
||||
// Uncheck siblings
|
||||
document.querySelectorAll('[id^="price-"]').forEach(function (c) {
|
||||
if (c !== checkbox) c.checked = false;
|
||||
});
|
||||
if (checkbox.checked) {
|
||||
url.searchParams.set('min_price', checkbox.dataset.min);
|
||||
url.searchParams.set('max_price', checkbox.dataset.max);
|
||||
} else {
|
||||
url.searchParams.delete('min_price');
|
||||
url.searchParams.delete('max_price');
|
||||
}
|
||||
window.location.href = url.toString();
|
||||
};
|
||||
|
||||
window.rarStockFilter = function (checkbox) {
|
||||
var url = new URL(window.location.href);
|
||||
if (checkbox.checked) {
|
||||
url.searchParams.set('availability', 'instock');
|
||||
} else {
|
||||
url.searchParams.delete('availability');
|
||||
}
|
||||
window.location.href = url.toString();
|
||||
};
|
||||
|
||||
window.rarApplyAllFilters = function () {
|
||||
// Collect all checked filters and navigate
|
||||
var url = new URL(window.location.href);
|
||||
document.querySelectorAll('.rar-filter-item input[type=checkbox]:checked').forEach(function (c) {
|
||||
if (c.name && c.value) url.searchParams.set(c.name, c.value);
|
||||
});
|
||||
window.location.href = url.toString();
|
||||
};
|
||||
|
||||
// ─── Designs index: tag filter ──────────────────────────────────────────
|
||||
window.rarFilterDesigns = function (tag, btn) {
|
||||
var cards = document.querySelectorAll('[data-design-tag]');
|
||||
var buttons = document.querySelectorAll('.rar-design-filter-btn');
|
||||
|
||||
buttons.forEach(function (b) { b.classList.remove('active'); });
|
||||
btn.classList.add('active');
|
||||
|
||||
cards.forEach(function (card) {
|
||||
if (tag === 'All' || card.dataset.designTag === tag) {
|
||||
card.style.display = '';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// ─── Qty controls ────────────────────────────────────────────────────────
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.matches('.rar-qty__btn')) {
|
||||
var wrap = e.target.closest('.rar-qty');
|
||||
if (!wrap) return;
|
||||
var display = wrap.querySelector('.rar-qty__val');
|
||||
var input = wrap.querySelector('input[type=number], input.qty');
|
||||
var current = parseInt(display ? display.textContent : (input ? input.value : 1)) || 1;
|
||||
|
||||
if (e.target.dataset.action === 'plus') {
|
||||
current++;
|
||||
} else if (e.target.dataset.action === 'minus') {
|
||||
current = Math.max(1, current - 1);
|
||||
}
|
||||
|
||||
if (display) display.textContent = current;
|
||||
if (input) {
|
||||
input.value = current;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ─── Nav: highlight current section ──────────────────────────────────────
|
||||
(function () {
|
||||
var path = window.location.pathname;
|
||||
var links = document.querySelectorAll('.rar-nav__links a');
|
||||
links.forEach(function (link) {
|
||||
var href = link.getAttribute('href') || '';
|
||||
if (href && href !== '/' && path.indexOf(href) === 0) {
|
||||
link.style.color = 'var(--stamp)';
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// ─── Cart count update via WooCommerce fragments ──────────────────────────
|
||||
document.addEventListener('wc_fragments_refreshed', function () {
|
||||
// WooCommerce will update .rar-nav__cart via the fragments filter in functions.php
|
||||
});
|
||||
|
||||
// ─── Announcement bar close ───────────────────────────────────────────────
|
||||
var bar = document.querySelector('.rar-bar');
|
||||
if (bar) {
|
||||
bar.style.cursor = 'pointer';
|
||||
bar.title = 'Click to dismiss';
|
||||
bar.addEventListener('click', function () {
|
||||
bar.style.display = 'none';
|
||||
try { sessionStorage.setItem('rar-bar-dismissed', '1'); } catch (e) {}
|
||||
});
|
||||
try {
|
||||
if (sessionStorage.getItem('rar-bar-dismissed') === '1') bar.style.display = 'none';
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// ─── WooCommerce quantity controls (override default +/-) ─────────────────
|
||||
// Replace WC's quantity input with our styled controls
|
||||
function initQtyControls() {
|
||||
document.querySelectorAll('.quantity:not(.rar-qty-init)').forEach(function (wrap) {
|
||||
var input = wrap.querySelector('input.qty, input[type=number]');
|
||||
if (!input) return;
|
||||
wrap.classList.add('rar-qty-init');
|
||||
|
||||
var minusBtn = document.createElement('button');
|
||||
minusBtn.type = 'button';
|
||||
minusBtn.className = 'rar-qty__btn';
|
||||
minusBtn.dataset.action = 'minus';
|
||||
minusBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 12h14"></path></svg>';
|
||||
minusBtn.style.cssText = 'padding:0 14px;border-right:1px solid var(--ink);display:flex;align-items:center;';
|
||||
|
||||
var plusBtn = document.createElement('button');
|
||||
plusBtn.type = 'button';
|
||||
plusBtn.className = 'rar-qty__btn';
|
||||
plusBtn.dataset.action = 'plus';
|
||||
plusBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M12 5v14M5 12h14"></path></svg>';
|
||||
plusBtn.style.cssText = 'padding:0 14px;border-left:1px solid var(--ink);display:flex;align-items:center;';
|
||||
|
||||
input.style.cssText = 'padding:0 18px;font-family:var(--mono);font-size:14px;min-width:50px;text-align:center;border:none;background:transparent;';
|
||||
|
||||
wrap.style.cssText = 'display:flex;align-items:stretch;border:1.5px solid var(--ink);';
|
||||
wrap.insertBefore(minusBtn, input);
|
||||
wrap.appendChild(plusBtn);
|
||||
|
||||
[minusBtn, plusBtn].forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var val = parseInt(input.value) || 1;
|
||||
var step = parseInt(input.step) || 1;
|
||||
if (btn.dataset.action === 'plus') {
|
||||
input.value = val + step;
|
||||
} else {
|
||||
input.value = Math.max(parseInt(input.min) || 1, val - step);
|
||||
}
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Run on DOM ready and after any AJAX
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initQtyControls);
|
||||
} else {
|
||||
initQtyControls();
|
||||
}
|
||||
document.addEventListener('wc_fragments_refreshed', initQtyControls);
|
||||
|
||||
})();
|
||||
89
theme/page-about.php
Normal file
89
theme/page-about.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* Template Name: About
|
||||
* About page — manifesto + origin + stats + team
|
||||
*/
|
||||
get_header();
|
||||
the_post();
|
||||
?>
|
||||
|
||||
<div class="rar-breadcrumb">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>">Home</a> / <span>About</span>
|
||||
</div>
|
||||
|
||||
<section class="rar-about-hero">
|
||||
<div>
|
||||
<div class="rar-form-tag" style="margin-bottom:22px;">FORM 11 · ABOUT · COMPANY FILE</div>
|
||||
<h1>
|
||||
We make things<br>
|
||||
for people who are<br>
|
||||
<em style="color:var(--stamp);font-style:italic;">mostly fine.</em>
|
||||
</h1>
|
||||
<div class="rar-about-manifesto">
|
||||
<?php if (get_the_content()) : ?>
|
||||
<?php the_content(); ?>
|
||||
<?php else : ?>
|
||||
<p>Reply All Regrets™ was founded on the premise that office culture deserves better merchandise. We make mugs, canvases, planners, and apparel for the chronically employed — people who have sent a reply-all they regret, attended a meeting that could have been an email, and circled back when they absolutely should not have.</p>
|
||||
<p>Everything ships from Cleveland. Everything is dishwasher safe. Most things are HR safe.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:repeating-linear-gradient(135deg,var(--manila-deep) 0 14px,var(--manila-dark) 14px 28px);border:1px solid var(--hairline-strong);aspect-ratio:4/5;display:flex;align-items:center;justify-content:center;">
|
||||
<div style="font-family:var(--serif);font-style:italic;font-size:48px;font-weight:500;text-align:center;color:var(--ink);line-height:1.1;padding:20px;">
|
||||
Mostly<br>fine.™
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="rar-about-body">
|
||||
<div class="rar-form-tag" style="margin-bottom:16px;">FORM 11-A · BY THE NUMBERS</div>
|
||||
|
||||
<div class="rar-about-stats">
|
||||
<?php
|
||||
$stats = [
|
||||
['2024', 'Year founded'],
|
||||
['141', 'Products in catalog'],
|
||||
['41', 'States shipping'],
|
||||
['4.8★', 'Average review'],
|
||||
];
|
||||
foreach ($stats as [$num, $label]) {
|
||||
echo '<div class="rar-about-stat">';
|
||||
echo '<div class="rar-about-stat__num rar-serif">' . esc_html($num) . '</div>';
|
||||
echo '<div class="rar-about-stat__label">' . esc_html($label) . '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div style="max-width:720px;margin:48px 0;">
|
||||
<div class="rar-form-tag" style="margin-bottom:16px;">FORM 11-B · ORIGIN STORY</div>
|
||||
<h2 style="font-family:var(--serif);font-size:38px;font-weight:500;margin:0 0 24px;letter-spacing:-0.02em;">
|
||||
It started with a mug.
|
||||
</h2>
|
||||
<p style="font-size:16px;line-height:1.7;color:var(--ink-muted);margin-bottom:20px;">
|
||||
The "Per My Last Email" mug was designed in 2024 after one too many unnecessary reply-all
|
||||
chains. The original batch of 50 sold out in a weekend. We have since shipped to 41 states,
|
||||
been featured in 3 workplace humor newsletters, and received one cease-and-desist from a
|
||||
consulting firm whose name we will not mention here.
|
||||
</p>
|
||||
<p style="font-size:16px;line-height:1.7;color:var(--ink-muted);">
|
||||
We believe that the best way to survive office culture is to laugh at it loudly,
|
||||
drink your coffee from a mug that says what you wish you could, and hang something
|
||||
honest on the wall behind your monitor.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:64px;">
|
||||
<div class="rar-form-tag" style="margin-bottom:16px;">FORM 11-C · PRESS</div>
|
||||
<div style="display:flex;gap:40px;align-items:center;flex-wrap:wrap;padding:24px 0;border-top:1.5px solid var(--ink);border-bottom:1.5px solid var(--ink);">
|
||||
<?php
|
||||
$press = ['Fast Co.', 'Office Life Mag', 'The Procrastinator', 'HR Weekly (Regrettably)', 'The Cubicle Quarterly'];
|
||||
foreach ($press as $p) {
|
||||
echo '<span style="font-family:var(--mono);font-size:11px;letter-spacing:0.2em;text-transform:uppercase;color:var(--ink-muted);">' . esc_html($p) . '</span>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
21
theme/page.php
Normal file
21
theme/page.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Generic page template
|
||||
*/
|
||||
get_header();
|
||||
the_post();
|
||||
?>
|
||||
|
||||
<div class="rar-breadcrumb">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>">Home</a> / <span><?php the_title(); ?></span>
|
||||
</div>
|
||||
|
||||
<div style="max-width:900px;margin:0 auto;padding:64px 56px;">
|
||||
<div class="rar-form-tag" style="margin-bottom:16px;">PAGE · <?php echo esc_html(strtoupper(get_the_date('M j, Y'))); ?></div>
|
||||
<h1 style="font-family:var(--serif);font-size:52px;font-weight:500;line-height:1.0;margin:0 0 40px;letter-spacing:-0.025em;"><?php the_title(); ?></h1>
|
||||
<div style="font-size:16px;line-height:1.7;color:var(--ink-soft);">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
100
theme/single.php
Normal file
100
theme/single.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* Single blog post — "The Memo" article
|
||||
*/
|
||||
get_header();
|
||||
the_post();
|
||||
$cats = get_the_category();
|
||||
$cat = $cats ? $cats[0]->name : 'Field Notes';
|
||||
$wc = max(1, ceil(str_word_count(strip_tags(get_the_content())) / 200));
|
||||
$thumb = get_the_post_thumbnail_url(get_the_ID(), 'full');
|
||||
?>
|
||||
|
||||
<div class="rar-breadcrumb">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>">Home</a> /
|
||||
<a href="<?php echo esc_url(home_url('/blog/')); ?>">The Memo</a> /
|
||||
<span><?php the_title(); ?></span>
|
||||
</div>
|
||||
|
||||
<section class="rar-post-header">
|
||||
<div class="rar-form-tag" style="margin-bottom:16px;">
|
||||
<?php echo esc_html(strtoupper($cat)); ?> · <?php the_date('M j, Y'); ?> · <?php echo esc_html($wc); ?> MIN READ
|
||||
</div>
|
||||
<h1><?php the_title(); ?></h1>
|
||||
<div style="display:flex;align-items:center;gap:20px;margin-top:20px;font-family:var(--mono);font-size:11px;letter-spacing:0.14em;text-transform:uppercase;color:var(--ink-muted);">
|
||||
<span>By <?php the_author(); ?></span>
|
||||
<span>·</span>
|
||||
<span><?php the_date('F j, Y'); ?></span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php if ($thumb) : ?>
|
||||
<div style="padding:0 56px;margin-bottom:-1px;">
|
||||
<div style="aspect-ratio:16/9;overflow:hidden;border:1px solid var(--hairline-strong);">
|
||||
<img src="<?php echo esc_url($thumb); ?>" alt="<?php the_title_attribute(); ?>" style="width:100%;height:100%;object-fit:cover;" />
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<article class="rar-post-content">
|
||||
<?php the_content(); ?>
|
||||
|
||||
<?php wp_link_pages(); ?>
|
||||
|
||||
<div style="margin-top:48px;padding-top:24px;border-top:1.5px solid var(--ink);">
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;">
|
||||
<?php
|
||||
$tags = get_the_tags();
|
||||
if ($tags) {
|
||||
foreach ($tags as $tag) {
|
||||
echo '<span class="rar-tag">' . esc_html($tag->name) . '</span>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Author box -->
|
||||
<div style="padding:48px 56px;background:var(--paper);border-top:1px solid var(--hairline-strong);">
|
||||
<div style="max-width:720px;margin:0 auto;display:flex;gap:24px;align-items:flex-start;">
|
||||
<?php echo get_avatar(get_the_author_meta('email'), 64, '', '', ['style' => 'border-radius:2px;border:1px solid var(--hairline-strong);flex-shrink:0;']); ?>
|
||||
<div>
|
||||
<div style="font-family:var(--mono);font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:var(--ink-muted);margin-bottom:6px;">Filed by</div>
|
||||
<div style="font-family:var(--serif);font-size:22px;font-weight:500;"><?php the_author(); ?></div>
|
||||
<p style="font-size:14px;color:var(--ink-muted);margin:6px 0 0;line-height:1.5;"><?php the_author_meta('description'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Related posts -->
|
||||
<?php
|
||||
$related = get_posts([
|
||||
'numberposts' => 3,
|
||||
'post__not_in' => [get_the_ID()],
|
||||
'category__in' => wp_get_post_categories(get_the_ID()),
|
||||
'post_status' => 'publish',
|
||||
]);
|
||||
if (!empty($related)) :
|
||||
?>
|
||||
<section class="rar-blog-section" style="padding-top:64px;">
|
||||
<?php rar_section_head('FORM 10 · RELATED DISPATCHES', 'More from the memo.'); ?>
|
||||
<div class="rar-blog-grid">
|
||||
<?php foreach ($related as $rp) :
|
||||
$rt = get_the_post_thumbnail_url($rp->ID, 'rar-blog-thumb');
|
||||
$rc = get_the_category($rp->ID);
|
||||
$rcat = $rc ? $rc[0]->name : 'Notes';
|
||||
?>
|
||||
<a href="<?php echo get_permalink($rp->ID); ?>" class="rar-blog-card">
|
||||
<div class="rar-blog-card__thumb">
|
||||
<?php if ($rt) : ?><img src="<?php echo esc_url($rt); ?>" alt="<?php echo esc_attr($rp->post_title); ?>" /><?php endif; ?>
|
||||
</div>
|
||||
<div class="rar-blog-card__tag"><?php echo esc_html(strtoupper($rcat)); ?> · <?php echo strtoupper(date('M j', strtotime($rp->post_date))); ?></div>
|
||||
<div class="rar-blog-card__title"><?php echo esc_html($rp->post_title); ?></div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
1052
theme/style.css
Normal file
1052
theme/style.css
Normal file
File diff suppressed because it is too large
Load Diff
236
theme/woocommerce/archive-product.php
Normal file
236
theme/woocommerce/archive-product.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce Archive/Category page — shop product listing with filter sidebar + sort
|
||||
*/
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
get_header('shop');
|
||||
|
||||
$term = get_queried_object();
|
||||
$is_category = $term instanceof WP_Term;
|
||||
$cat_name = $is_category ? $term->name : 'Shop';
|
||||
$cat_desc = $is_category ? $term->description : '';
|
||||
$cat_count = $is_category ? $term->count : wp_count_posts('product')->publish;
|
||||
$cat_slug = $is_category ? $term->slug : 'shop';
|
||||
|
||||
// Category descriptions
|
||||
$cat_desc_map = [
|
||||
'mugs' => '47 ceramics, 12 enamels, and a few we honestly forgot to count. Dishwasher safe. Microwave safe. HR safe (mostly).',
|
||||
'canvas' => 'Print-on-demand wall art for the soul-tired and decoratively passive-aggressive.',
|
||||
'planners' => 'For the person who plans a lot and does a little. Or the other way around.',
|
||||
'apparel' => 'Wear your grievances. Business casual with a quiet fury.',
|
||||
];
|
||||
if (empty($cat_desc)) {
|
||||
$cat_desc = $cat_desc_map[$cat_slug] ?? 'The complete collection. Curated for the chronically employed.';
|
||||
}
|
||||
|
||||
// Sort order
|
||||
$orderby = isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'menu_order';
|
||||
?>
|
||||
|
||||
<!-- Breadcrumb -->
|
||||
<div class="rar-breadcrumb">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>">Shop</a> /
|
||||
<?php if ($is_category) : ?>
|
||||
<a href="<?php echo esc_url(home_url('/shop/')); ?>">Departments</a> /
|
||||
<span><?php echo esc_html($cat_name); ?></span>
|
||||
<?php else : ?>
|
||||
<span>All Products</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Category Hero -->
|
||||
<div class="rar-cat-hero">
|
||||
<?php if ($is_category) : ?>
|
||||
<div class="rar-folder-tab">DEPT. <?php echo strtoupper($cat_slug); ?> · <?php echo esc_html(strtoupper($cat_name)); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="rar-cat-hero__inner">
|
||||
<div>
|
||||
<h1>
|
||||
<?php echo esc_html($cat_name); ?>.<br>
|
||||
<em style="color:var(--stamp);font-style:italic;"><?php echo esc_html(wp_trim_words($cat_desc, 6)); ?></em>
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<p style="font-size:14px;line-height:1.6;color:var(--ink-muted);margin:0 0 18px;max-width:380px;"><?php echo esc_html($cat_desc); ?></p>
|
||||
<div class="rar-cat-hero__stats">
|
||||
<span><?php echo esc_html($cat_count); ?> ITEMS</span>
|
||||
<span>·</span>
|
||||
<span>FREE SHIP OVER $40</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<div class="rar-toolbar">
|
||||
<div class="rar-toolbar__left">
|
||||
Showing
|
||||
<?php woocommerce_result_count(); ?>
|
||||
</div>
|
||||
<div class="rar-toolbar__right">
|
||||
<!-- Grid/List toggle -->
|
||||
<div class="rar-view-toggle">
|
||||
<button class="rar-view-toggle__btn active" id="rar-grid-btn" onclick="rarSetView('grid')">Grid</button>
|
||||
<button class="rar-view-toggle__btn" id="rar-list-btn" onclick="rarSetView('list')">List</button>
|
||||
</div>
|
||||
|
||||
<!-- Sort -->
|
||||
<div class="rar-sort-wrap">
|
||||
<button class="rar-sort-btn" onclick="document.getElementById('rar-sort-menu').classList.toggle('open')">
|
||||
Sort: <span id="rar-sort-label"><?php echo esc_html(wc_get_loop_prop('orderby', 'Featured')); ?></span>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"></path></svg>
|
||||
</button>
|
||||
<div class="rar-sort-menu" id="rar-sort-menu">
|
||||
<?php
|
||||
$sort_options = WC()->query->get_catalog_ordering_args();
|
||||
foreach (wc_get_catalog_ordering_args() as $val => $opt) {
|
||||
$current = (isset($_GET['orderby']) ? $_GET['orderby'] : get_option('woocommerce_default_catalog_orderby')) === $val;
|
||||
$url = add_query_arg('orderby', $val);
|
||||
echo '<a href="' . esc_url($url) . '" class="' . ($current ? 'active' : '') . '" onclick="document.getElementById(\'rar-sort-label\').textContent=this.textContent;document.getElementById(\'rar-sort-menu\').classList.remove(\'open\');">' . esc_html($opt) . '</a>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Category layout: filter sidebar + product grid -->
|
||||
<div class="rar-cat-layout">
|
||||
|
||||
<!-- Filter Sidebar -->
|
||||
<aside class="rar-filter-sidebar">
|
||||
<div class="rar-form-tag" style="margin-bottom:14px;">FORM 06-B · FILTERS</div>
|
||||
|
||||
<!-- Subcategories -->
|
||||
<?php if ($is_category) {
|
||||
$subcats = get_terms(['taxonomy' => 'product_cat', 'parent' => $term->term_id, 'hide_empty' => true]);
|
||||
if (!empty($subcats)) {
|
||||
echo '<div class="rar-filter-group">';
|
||||
echo '<div class="rar-filter-group__label">Subcategories <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14"></path></svg></div>';
|
||||
foreach ($subcats as $sc) {
|
||||
$active = (isset($_GET['product_cat']) && $_GET['product_cat'] === $sc->slug) ? ' checked' : '';
|
||||
echo '<label class="rar-filter-item"><input type="checkbox" name="product_cat" value="' . esc_attr($sc->slug) . '"' . $active . ' onchange="rarApplyFilter(this)"> ' . esc_html($sc->name) . ' <span style="font-family:var(--mono);font-size:10px;color:var(--ink-faint);margin-left:auto;">' . esc_html($sc->count) . '</span></label>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
} ?>
|
||||
|
||||
<!-- Price filter -->
|
||||
<div class="rar-filter-group">
|
||||
<div class="rar-filter-group__label">
|
||||
Price
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14"></path></svg>
|
||||
</div>
|
||||
<?php
|
||||
$price_ranges = [
|
||||
['under-25', 'Under $25', '0', '25'],
|
||||
['25-40', '$25 – $40', '25', '40'],
|
||||
['over-40', 'Over $40', '40', '999'],
|
||||
];
|
||||
foreach ($price_ranges as [$id, $label, $min, $max]) {
|
||||
$active = (isset($_GET['min_price']) && $_GET['min_price'] === $min) ? ' checked' : '';
|
||||
echo '<label class="rar-filter-item"><input type="checkbox" id="price-' . esc_attr($id) . '" data-min="' . esc_attr($min) . '" data-max="' . esc_attr($max) . '"' . $active . ' onchange="rarPriceFilter(this)"> ' . esc_html($label) . '</label>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- In-stock filter -->
|
||||
<div class="rar-filter-group">
|
||||
<div class="rar-filter-group__label">
|
||||
Availability
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14"></path></svg>
|
||||
</div>
|
||||
<label class="rar-filter-item">
|
||||
<input type="checkbox" id="rar-in-stock" <?php echo (isset($_GET['availability']) && $_GET['availability'] === 'instock') ? 'checked' : ''; ?> onchange="rarStockFilter(this)">
|
||||
In Stock Only
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<?php if (is_active_sidebar('shop-filter')) : ?>
|
||||
<?php dynamic_sidebar('shop-filter'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="rar-filter-apply">
|
||||
<button class="rar-btn" style="width:100%;" onclick="rarApplyAllFilters()">Apply filters</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Product Grid -->
|
||||
<div>
|
||||
<div class="rar-product-grid" id="rar-product-grid">
|
||||
<?php
|
||||
if (have_posts()) :
|
||||
while (have_posts()) :
|
||||
the_post();
|
||||
global $product;
|
||||
if (!$product) $product = wc_get_product(get_the_ID());
|
||||
if (!$product) continue;
|
||||
|
||||
$img_id = $product->get_image_id();
|
||||
$img_url = $img_id ? wp_get_attachment_image_url($img_id, 'rar-product-card') : '';
|
||||
$sku = $product->get_sku() ?: 'SKU-' . $product->get_id();
|
||||
$cats = get_the_terms(get_the_ID(), 'product_cat');
|
||||
$catname = $cats ? $cats[0]->name : '';
|
||||
$price = $product->get_price_html();
|
||||
$url = get_permalink();
|
||||
$stock = $product->get_stock_status();
|
||||
$tag = $product->is_featured() ? 'Featured' : '';
|
||||
if ($product->is_on_sale()) $tag = 'Sale';
|
||||
if ($stock === 'onbackorder') $tag = 'Backorder';
|
||||
$stock_label = $stock === 'instock' ? 'IN STOCK' : ($stock === 'onbackorder' ? 'BACKORDER' : 'OUT OF STOCK');
|
||||
$stock_color = $stock === 'instock' ? 'var(--olive-dark)' : ($stock === 'onbackorder' ? 'var(--ink-faint)' : 'var(--stamp)');
|
||||
?>
|
||||
<a href="<?php echo esc_url($url); ?>" class="rar-card">
|
||||
<div class="rar-card__media">
|
||||
<div class="rar-card__sku">SKU <?php echo esc_html($sku); ?></div>
|
||||
<?php if ($tag) : ?>
|
||||
<div class="rar-card__badge"><?php echo esc_html($tag); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($img_url) : ?>
|
||||
<img src="<?php echo esc_url($img_url); ?>" alt="<?php echo esc_attr($product->get_name()); ?>" />
|
||||
<?php else : ?>
|
||||
<div class="rar-placeholder__label"><?php echo esc_html(strtoupper($catname ?: $product->get_name())); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="rar-card__body">
|
||||
<?php if ($catname) : ?>
|
||||
<div class="rar-card__cat"><?php echo esc_html($catname); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="rar-card__title"><?php echo esc_html($product->get_name()); ?></div>
|
||||
<div class="rar-card__row">
|
||||
<span class="rar-card__price"><?php echo wp_kses_post($price); ?></span>
|
||||
<span style="color:<?php echo esc_attr($stock_color); ?>;font-family:var(--mono);font-size:9px;letter-spacing:0.18em;"><?php echo esc_html($stock_label); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php
|
||||
endwhile;
|
||||
else :
|
||||
echo '<p style="font-family:var(--serif);font-size:18px;font-style:italic;color:var(--ink-muted);grid-column:1/-1;">No products found. The warehouse is confused.</p>';
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="rar-pagination">
|
||||
<span class="rar-mono" style="font-size:10px;letter-spacing:0.16em;text-transform:uppercase;color:var(--ink-muted);">
|
||||
Page <?php echo max(1, get_query_var('paged')); ?> of <?php echo max(1, $wp_query->max_num_pages); ?>
|
||||
</span>
|
||||
<div class="rar-page-btns">
|
||||
<?php
|
||||
the_posts_pagination([
|
||||
'mid_size' => 2,
|
||||
'prev_text' => '‹',
|
||||
'next_text' => '›',
|
||||
'screen_reader_text' => ' ',
|
||||
'before_page_number' => '',
|
||||
'after_page_number' => '',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php get_footer('shop'); ?>
|
||||
209
theme/woocommerce/single-product.php
Normal file
209
theme/woocommerce/single-product.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce Single Product — gallery + variants + add-to-cart + reviews
|
||||
*/
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
get_header('shop');
|
||||
the_post();
|
||||
global $product;
|
||||
if (!$product) $product = wc_get_product(get_the_ID());
|
||||
|
||||
$sku = $product->get_sku() ?: 'SKU-' . $product->get_id();
|
||||
$cats = get_the_terms(get_the_ID(), 'product_cat');
|
||||
$catname = $cats ? $cats[0]->name : 'Product';
|
||||
$cat_url = $cats ? get_term_link($cats[0]) : get_permalink(wc_get_page_id('shop'));
|
||||
$gallery_ids = $product->get_gallery_image_ids();
|
||||
$main_img_id = $product->get_image_id();
|
||||
$all_imgs = $main_img_id ? array_merge([$main_img_id], $gallery_ids) : $gallery_ids;
|
||||
$price = $product->get_price_html();
|
||||
$stock = $product->get_stock_status();
|
||||
$stock_label = $stock === 'instock' ? '● IN STOCK' : ($stock === 'onbackorder' ? '◐ BACKORDER' : '○ OUT OF STOCK');
|
||||
$stock_color = $stock === 'instock' ? 'var(--olive-dark)' : ($stock === 'onbackorder' ? 'var(--stamp)' : 'var(--ink-faint)');
|
||||
?>
|
||||
|
||||
<!-- Breadcrumb -->
|
||||
<div class="rar-breadcrumb">
|
||||
<a href="<?php echo esc_url(home_url('/')); ?>">Shop</a> /
|
||||
<a href="<?php echo esc_url($cat_url); ?>"><?php echo esc_html($catname); ?></a> /
|
||||
<span><?php the_title(); ?></span>
|
||||
</div>
|
||||
|
||||
<!-- Product layout -->
|
||||
<div class="rar-product-detail">
|
||||
|
||||
<!-- Gallery -->
|
||||
<div class="rar-gallery" id="rar-gallery">
|
||||
<div class="rar-gallery__thumbs">
|
||||
<?php foreach ($all_imgs as $i => $img_id) :
|
||||
$thumb_url = wp_get_attachment_image_url($img_id, 'thumbnail');
|
||||
$full_url = wp_get_attachment_image_url($img_id, 'rar-product-card');
|
||||
?>
|
||||
<button class="rar-gallery__thumb <?php echo $i === 0 ? 'active' : ''; ?>"
|
||||
onclick="rarSwitchGallery(<?php echo esc_attr($i); ?>, '<?php echo esc_url($full_url); ?>')"
|
||||
aria-label="View image <?php echo esc_attr($i + 1); ?>">
|
||||
<?php if ($thumb_url) : ?>
|
||||
<img src="<?php echo esc_url($thumb_url); ?>" alt="Image <?php echo esc_attr($i + 1); ?>" />
|
||||
<?php endif; ?>
|
||||
<span style="position:absolute;bottom:4px;left:4px;font-family:var(--mono);font-size:8px;color:var(--ink-soft);background:var(--paper);padding:1px 4px;border:1px solid var(--ink);">0<?php echo esc_html($i + 1); ?></span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if (empty($all_imgs)) : ?>
|
||||
<button class="rar-gallery__thumb active" aria-label="Default image">
|
||||
<span style="position:absolute;bottom:4px;left:4px;font-family:var(--mono);font-size:8px;color:var(--ink-soft);background:var(--paper);padding:1px 4px;border:1px solid var(--ink);">01</span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="rar-gallery__main" id="rar-gallery-main">
|
||||
<?php if (!empty($all_imgs)) :
|
||||
$main_url = wp_get_attachment_image_url($all_imgs[0], 'rar-product-card');
|
||||
?>
|
||||
<img id="rar-gallery-img" src="<?php echo esc_url($main_url); ?>" alt="<?php the_title_attribute(); ?>" />
|
||||
<?php else : ?>
|
||||
<div class="rar-placeholder__label"><?php echo esc_html(strtoupper($catname)); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="rar-gallery__label" id="rar-gallery-label">FIG. 1 — FRONT</div>
|
||||
<div style="position:absolute;bottom:18px;left:18px;">
|
||||
<span class="rar-stamp">SKU <?php echo esc_html($sku); ?></span>
|
||||
</div>
|
||||
<div style="position:absolute;bottom:18px;right:18px;font-family:var(--mono);font-size:9px;letter-spacing:0.18em;text-transform:uppercase;color:var(--ink-muted);background:var(--paper);padding:4px 8px;border:1px solid var(--hairline-strong);">
|
||||
<span id="rar-gallery-counter">1</span> / <?php echo esc_html(max(1, count($all_imgs))); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product Info -->
|
||||
<div class="rar-product-info">
|
||||
<div class="rar-form-tag" style="margin-bottom:14px;">
|
||||
<?php echo esc_html(strtoupper($catname)); ?> · <?php echo esc_html(strtoupper($product->get_type())); ?> · <?php echo esc_html($sku); ?>
|
||||
</div>
|
||||
|
||||
<h1><?php the_title(); ?></h1>
|
||||
|
||||
<?php if ($product->get_short_description()) : ?>
|
||||
<p class="rar-product-subtitle"><?php echo wp_kses_post($product->get_short_description()); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Rating -->
|
||||
<div style="display:flex;align-items:center;gap:16px;margin-bottom:24px;">
|
||||
<?php if ($product->get_rating_count() > 0) : ?>
|
||||
<?php echo wc_get_rating_html($product->get_average_rating()); ?>
|
||||
<span class="rar-mono" style="font-size:11px;letter-spacing:0.06em;">
|
||||
<?php echo esc_html($product->get_average_rating()); ?> · <?php echo esc_html($product->get_rating_count()); ?> reviews
|
||||
</span>
|
||||
<span style="color:var(--hairline-strong);">·</span>
|
||||
<?php endif; ?>
|
||||
<span class="rar-mono" style="font-size:10px;letter-spacing:0.18em;text-transform:uppercase;color:<?php echo esc_attr($stock_color); ?>;">
|
||||
<?php echo esc_html($stock_label); ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Price -->
|
||||
<div class="rar-product-price"><?php echo wp_kses_post($price); ?></div>
|
||||
<div class="rar-product-price-sub">USD · ship $4.50 · free over $40</div>
|
||||
|
||||
<!-- Description -->
|
||||
<?php if ($product->get_description()) : ?>
|
||||
<div class="rar-product-desc"><?php echo wp_kses_post(wp_trim_words($product->get_description(), 40)); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Add to Cart Form -->
|
||||
<?php woocommerce_template_single_add_to_cart(); ?>
|
||||
|
||||
<!-- Specs from short description / attributes -->
|
||||
<?php $attrs = $product->get_attributes(); ?>
|
||||
<?php if (!empty($attrs)) : ?>
|
||||
<div class="rar-spec-list">
|
||||
<div class="rar-spec-list__label">SECTION 4-A · SPECIFICATIONS</div>
|
||||
<ul>
|
||||
<?php $i = 1; foreach ($attrs as $attr) :
|
||||
$attr_name = wc_attribute_label($attr->get_name());
|
||||
$attr_vals = $attr->is_taxonomy()
|
||||
? wc_get_product_terms($product->get_id(), $attr->get_name(), ['fields' => 'names'])
|
||||
: $attr->get_options();
|
||||
?>
|
||||
<li>
|
||||
<span class="rar-spec-num"><?php echo str_pad($i++, 2, '0', STR_PAD_LEFT); ?>.</span>
|
||||
<span><strong><?php echo esc_html($attr_name); ?>:</strong> <?php echo esc_html(implode(', ', $attr_vals)); ?></span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Shipping meta -->
|
||||
<div class="rar-shipping-grid">
|
||||
<div class="rar-shipping-item">
|
||||
<div class="rar-shipping-item__key">Ships</div>
|
||||
<div class="rar-shipping-item__val">In 3-5 biz days · USPS</div>
|
||||
</div>
|
||||
<div class="rar-shipping-item">
|
||||
<div class="rar-shipping-item__key">Returns</div>
|
||||
<div class="rar-shipping-item__val">30-day grievance window</div>
|
||||
</div>
|
||||
<div class="rar-shipping-item">
|
||||
<div class="rar-shipping-item__key">Origin</div>
|
||||
<div class="rar-shipping-item__val">Cleveland, OH</div>
|
||||
</div>
|
||||
<div class="rar-shipping-item">
|
||||
<div class="rar-shipping-item__key">Stock</div>
|
||||
<div class="rar-shipping-item__val"><?php echo esc_html($product->get_stock_quantity() ?? '—'); ?> units</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product tabs: description, reviews -->
|
||||
<div style="padding:0 56px 64px;">
|
||||
<?php woocommerce_output_product_data_tabs(); ?>
|
||||
</div>
|
||||
|
||||
<!-- Reviews -->
|
||||
<?php if ($product->get_rating_count() > 0) : ?>
|
||||
<section class="rar-reviews">
|
||||
<?php rar_section_head('FORM 12-C · TESTIMONIALS', 'What the chronically CC\'d are saying.', esc_html($product->get_rating_count()) . ' REVIEWS<br/>AVG. ' . esc_html($product->get_average_rating()) . ' ★'); ?>
|
||||
<?php comments_template(); ?>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Related Products -->
|
||||
<?php
|
||||
$related_ids = wc_get_related_products($product->get_id(), 3);
|
||||
if (!empty($related_ids)) :
|
||||
$related_products = array_filter(array_map('wc_get_product', $related_ids));
|
||||
?>
|
||||
<section class="rar-products" style="background:var(--paper);border-top:1px solid var(--hairline-strong);">
|
||||
<?php rar_section_head('FORM 13 · RELATED ITEMS', 'You might also regret buying...'); ?>
|
||||
<div class="rar-products__grid">
|
||||
<?php foreach ($related_products as $rp) :
|
||||
$ri = $rp->get_image_id();
|
||||
$ru = $ri ? wp_get_attachment_image_url($ri, 'rar-product-card') : '';
|
||||
$rc = get_the_terms($rp->get_id(), 'product_cat');
|
||||
$rcat = $rc ? $rc[0]->name : '';
|
||||
?>
|
||||
<a href="<?php echo esc_url(get_permalink($rp->get_id())); ?>" class="rar-card">
|
||||
<div class="rar-card__media">
|
||||
<div class="rar-card__sku">SKU <?php echo esc_html($rp->get_sku() ?: $rp->get_id()); ?></div>
|
||||
<?php if ($ru) : ?>
|
||||
<img src="<?php echo esc_url($ru); ?>" alt="<?php echo esc_attr($rp->get_name()); ?>" />
|
||||
<?php else : ?>
|
||||
<div class="rar-placeholder__label"><?php echo esc_html(strtoupper($rcat ?: $rp->get_name())); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="rar-card__body">
|
||||
<?php if ($rcat) : ?><div class="rar-card__cat"><?php echo esc_html($rcat); ?></div><?php endif; ?>
|
||||
<div class="rar-card__title"><?php echo esc_html($rp->get_name()); ?></div>
|
||||
<div class="rar-card__row">
|
||||
<span class="rar-card__price"><?php echo wp_kses_post($rp->get_price_html()); ?></span>
|
||||
<span style="color:var(--ink-muted);">→</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php get_footer('shop'); ?>
|
||||
Reference in New Issue
Block a user