Process Jan 14, 2023 5 min read

Custom WooCommerce E-Commerce for Grué Pasticceria

Custom WooCommerce e-commerce platform for an Italian artisan pastry shop. Built with WordPress, Elementor Pro, and a custom child theme featuring OOP PHP architecture, ACF-powered dynamic pricing, Redis caching, and full Italian localization.

Lushano Perera
Lushano Perera
Author

Project Overview

Grué Pasticceria is a fully custom e-commerce platform built for an Italian artisan pastry shop. The project required creating an elegant, performant online store that could handle variable products (different sizes, weights), delivery scheduling, and maintain full Italian localization.

The solution delivered includes a custom Hello Elementor child theme with extensive WooCommerce customizations, advanced product filtering, and an optimized performance stack featuring Redis caching.


Technology Stack

Core Platform

  • WordPress – CMS foundation
  • WooCommerce 7.1.0 – E-commerce engine
  • PHP 7.2+ – Server-side language
  • MySQL – Database

Frontend & Page Building

  • Elementor Pro – Drag-and-drop page builder
  • Hello Elementor Child Theme – Custom lightweight theme
  • Crocoblock Jet Suite – JetEngine, JetElements, JetSmartFilters, JetTabs, JetMenu

Performance Optimization

  • WP Rocket – Page caching and optimization
  • Redis Object Cache – In-memory data caching with Predis
  • Imagify – Automatic image compression

Custom Fields & Data Management

  • Advanced Custom Fields PRO 6.0.4 – Flexible field management

Marketing & SEO

  • Google Listings & Ads – Google Shopping integration
  • Facebook for WooCommerce – Social commerce sync

Security

  • Malcare Security – WAF and malware protection
  • Akismet – Spam protection

Custom Development

Theme Architecture

The custom child theme follows modern PHP practices with namespacing, OOP principles, and the Singleton pattern for clean initialization.

<?php
namespace HelloElementorChild;

final class ThemeSetup {
private static $instance = null;

public static function getInstance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}

private function __construct() {
$this->initHooks();
}

private function initHooks(): void {
add_action('wp_enqueue_scripts', [$this, 'enqueueStyles'], 20);

if ($this->isWooCommerceActive()) {
$this->initWooCommerceHooks();
}
}

private function isWooCommerceActive(): bool {
return class_exists('WooCommerce');
}
}

// Initialize theme
add_action('after_setup_theme', function() {
ThemeSetup::getInstance();
});

WooCommerce Price Customization

One key requirement was displaying variable product prices with an Italian “Starting from” prefix when products have multiple price points.

/**
* Modify variable product price display
*/
public function modifyVariablePrice(string $price, $product): string {
if (!$product->is_type('variable')) {
return $price;
}

$prices = $product->get_variation_prices(true);

if (empty($prices['price'])) {
return (string) apply_filters('woocommerce_variable_empty_price_html', '', $product);
}

$min_price = current($prices['price']);
$max_price = end($prices['price']);
$prefix_html = '<span class="price-prefix">' .
esc_html__('A partire da ', 'grue') .
'</span>';

$prefix = ($min_price !== $max_price) ? $prefix_html : '';

return (string) apply_filters(
'woocommerce_variable_price_html',
$prefix . wc_price($min_price) . $product->get_price_suffix(),
$product
);
}

ACF Integration for Dynamic Price Labels

Products can have custom price labels (e.g., “per kg”, “per piece”) managed through ACF fields:

/**
* Add price label from ACF field
*/
public function addPriceLabel(string $price, $product): string {
if (function_exists('get_field')) {
$label = get_field('price-label', $product->get_id());
if ($label) {
return $price . ' ' . esc_html($label);
}
}
return $price;
}

WooCommerce Hook Integration

The theme hooks into WooCommerce at multiple points for customization:

private function initWooCommerceHooks(): void {
    // Product loop modifications
    add_action('woocommerce_shop_loop_item_title', [$this, 'openTextLayer'], 9);
    add_action('woocommerce_after_shop_loop_item_title', [$this, 'addOrderButton'], 11);
    add_action('woocommerce_after_shop_loop_item_title', [$this, 'closeTextLayer'], 12);

    // Single product modifications
    add_action('woocommerce_before_single_variation', [$this, 'openAdditionalWrap'], 29);
    add_action('woocommerce_after_single_variation', [$this, 'closeAdditionalWrap'], 31);

    // Price display modifications
    add_filter('woocommerce_get_price_html', [$this, 'modifyVariablePrice'], 10, 2);
    add_filter('woocommerce_get_price_html', [$this, 'addPriceLabel'], 100, 2);
}

ProductBox Shortcode Component

A custom shortcode system for displaying product showcases by category:

class ProductBox {
public static function outputProductBoxSection(): void {
global $product;

if (!$product instanceof \WC_Product) {
return;
}

$product_id = $product->get_id();

if ('yes' !== get_post_meta($product_id, '_product_box', true)) {
return;
}

$box_data = self::getBoxData($product_id);

if (empty($box_data)) {
return;
}

self::renderProductBox($box_data);
}

private static function getBoxData(int $product_id): array {
return [
'title' => get_post_meta($product_id, '_product_box_title', true),
'item_qty' => absint(get_post_meta($product_id, '_product_box_item_qty', true)),
'items_per_row' => absint(get_post_meta($product_id, '_product_box_row_item_count', true)) ?: 3,
'layout' => sanitize_html_class(get_post_meta($product_id, '_product_box_item_layout', true) ?: 'row'),
'category' => get_post_meta($product_id, '_product_box_category', true),
'image_size' => sanitize_key(get_post_meta($product_id, '_product_box_display_image_size', true) ?: 'thumbnail')
];
}
}

// Shortcode registration
add_shortcode('grue_product_box_items', function($atts) {
ob_start();
ProductBox::outputProductBoxSection();
return ob_get_clean();
});

Template Overrides

Custom WooCommerce templates with a custom hook for extensibility:

// In variable.php template override
<form class="variations_form cart" ...>
<?php do_action( 'grue_as_woocommerce_form_starts' ); ?>
<?php do_action( 'woocommerce_before_variations_form' ); ?>
<!-- Rest of form -->
</form>

Technical Decisions

Child Theme Approach

Using a child theme of Hello Elementor ensures:

  • Easy updates to parent theme without losing customizations
  • Lightweight base (Hello Elementor is designed for Elementor)
  • Full WooCommerce template override capability

Italian Localization

All custom strings use the grue text domain with proper escaping:

esc_html__('A partire da ', 'grue')
esc_html_x('Ordina', 'grue')

Performance Stack

  • Redis: Object caching reduces database queries significantly
  • WP Rocket: Page caching, minification, lazy loading
  • Imagify: Automatic WebP conversion and compression

Security Considerations

  • All output properly escaped (esc_htmlesc_attresc_url)
  • Input sanitization (sanitize_html_classsanitize_keyabsint)
  • WAF protection via Malcare

Project Structure

wp-content/themes/hello-theme-child-grue/
├── functions.php # Main theme logic (OOP)
├── style.css # Theme metadata & custom styles
└── woocommerce/
└── single-product/
└── add-to-cart/
├── simple.php # Simple product template
└── variable.php # Variable product template

Key Features Implemented

  • Custom variable product pricing with “Starting from” prefix
  • ACF-powered dynamic price labels (per kg, per piece, etc.)
  • Product showcase boxes via shortcode
  • Custom add-to-cart templates
  • Italian localization throughout
  • Advanced product filtering (JetSmartFilters)
  • Delivery date scheduling
  • Google Shopping & Facebook catalog sync
  • Multi-layer caching (page + object)

Plugins Used

CategoryPlugins
E-CommerceWooCommerce, WC Payments, Woo Variation Swatches, Product Delivery Date
Page BuildingElementor Pro, JetEngine, JetElements, JetSmartFilters, JetTabs, JetMenu
Custom FieldsAdvanced Custom Fields PRO
PerformanceWP Rocket, Redis Cache, Imagify
MarketingFacebook for WooCommerce, Google Listings & Ads
SecurityMalcare Security, Akismet

Written by Lushano Perera

Digital craftsman exploring the intersection of design, technology, and human experience.