
Ambrosiano Milano — In Depth Analysis
Enterprise WordPress platform for a Milan-based precious metals trading company. Features real-time gold/silver quotations from external APIs, custom rate-limited lead generation forms with SMS notifications, and ETag-based REST API optimization achieving 95% bandwidth reduction.
Project Overview
Ambrosiano Milano is a Milan-based precious metals trading company specializing in gold and silver buying/selling. The project involved developing a comprehensive WordPress-based platform that handles real-time precious metals quotations, lead generation forms with SMS notifications, B2B wholesale pricing, and landing pages optimized for conversion.
Key Business Requirements
- Real-time quotations for gold (9K-24K) and silver (800-999) updated from external APIs
- Dual pricing systems for retail and B2B wholesale customers
- Lead generation forms with SMS notifications and spam protection
- High-conversion landing pages for marketing campaigns
- Mobile-responsive design with fast loading times
- Italian market compliance including phone validation and GDPR considerations
Technology Stack
| Layer | Technology | Purpose |
|---|---|---|
| CMS | WordPress 6.x | Content management |
| Server | Cloudways (Nginx + PHP-FPM) | Managed hosting |
| Database | MariaDB 10.6 | Data storage |
| Cache | Redis + Breeze | Object caching |
| Forms | Contact Form 7 + Custom Extensions | Lead capture |
| Fields | Advanced Custom Fields Pro | Flexible content |
| Build | Gulp 4, SASS, PostCSS, Terser | Asset pipeline |
| JS Libraries | jQuery, Fancybox, Flickity, jQuery Validate | Frontend interactions |
| External APIs | GoldPrice.org, DaytradingSA.ch, Esendex SMS | Data integration |
| Development | Docker (MariaDB, Redis, WordPress) | Local environment |
| Deployment | rsync over SSH | Server sync |
Architecture Overview
Theme Structure
ambrosiano-theme/
├── functions.php # Theme bootstrap (session init + module loading)
├── inc/ # Modular PHP functionality
│ ├── setup.php # Theme features, admin customization
│ ├── styles-scripts.php # Asset enqueuing
│ ├── acf_fields.php # ACF field definitions
│ ├── panels.php # Quotation API integration
│ ├── prospect_actions.php # Form handling, SMS, rate limiting
│ └── rest.php # Custom REST API endpoints
├── parts/ # Reusable template components
├── tp_*.php # Custom page templates (30+)
├── sass/ # SCSS source files
├── css/ # Compiled CSS
├── js/ # JavaScript (vendor + main.js)
└── gulpfile.js # Build configuration
Data Flow Architecture
Key Features Implemented
1. Real-Time Quotation System
The quotation system fetches precious metals prices from multiple external APIs and displays them to users with automatic updates.
Backend Implementation (inc/panels.php):
<?php
/**
* Fetch quotations from external APIs and store in WordPress options
* Triggered via cron job every 2 minutes
*/
add_action('ambrosiano_refresh_quotations', function() {
// Fetch gold spot prices from GoldPrice.org
$spot_response = wp_remote_get(
'https://data-asg.goldprice.org/dbXRates/EUR',
['timeout' => 30, 'httpversion' => '1.1']
);
if (!is_wp_error($spot_response)) {
$spot_data = json_decode(wp_remote_retrieve_body($spot_response), true);
$gold_spot = $spot_data['items'][0]['xauPrice'] ?? 0;
$silver_spot = $spot_data['items'][0]['xagPrice'] ?? 0;
update_option('ambrosiano_value_gold_stock', $gold_spot);
update_option('ambrosiano_value_silver_stock', $silver_spot);
}
// Fetch karat-specific quotations from DaytradingSA
$quote_response = wp_remote_get(
'https://www.daytradingsa.ch/API/getQuote.php',
['timeout' => 30]
);
if (!is_wp_error($quote_response)) {
$quotes = json_decode(wp_remote_retrieve_body($quote_response), true);
// Store individual karat prices
update_option('ambrosiano_value_gold_09', $quotes['gold_375'] ?? 0);
update_option('ambrosiano_value_gold_14', $quotes['gold_585'] ?? 0);
update_option('ambrosiano_value_gold_18', $quotes['gold_750'] ?? 0);
update_option('ambrosiano_value_gold_24', $quotes['gold_999'] ?? 0);
// ... additional prices
}
// Update timestamp
update_option('ambrosiano_last_timestamp', current_time('mysql'));
// Clear page cache
if (class_exists('Breeze_Admin')) {
do_action('breeze_clear_all_cache');
}
});
REST API with ETag Optimization (inc/rest.php):
<?php
/**
* REST endpoint with ETag-based conditional responses
* Reduces bandwidth by 95% when quotations haven't changed
*/
function ambrosiano_rest_api_check_update() {
$retail_updated = get_transient('ambrosiano_quotations_updated');
$b2b_updated = get_transient('ambrosiano_quotations_b2b_updated');
// Generate ETag from update timestamps
$etag_data = [
'retail' => $retail_updated ? (int)$retail_updated : 0,
'b2b' => $b2b_updated ? (int)$b2b_updated : 0,
];
$etag = '"' . md5(wp_json_encode($etag_data)) . '"';
// Check for If-None-Match header (client's cached ETag)
$client_etag = $_SERVER['HTTP_IF_NONE_MATCH'] ?? '';
// If ETags match, return 304 Not Modified (saves ~1.8KB per request)
if ($client_etag === $etag) {
$response = new WP_REST_Response(null, 304);
$response->header('ETag', $etag);
$response->header('X-Quotation-ETag', $etag); // Cloudways compatibility
$response->header('Cache-Control', 'no-cache, must-revalidate');
return $response;
}
// Return full data with new ETag
$data = [
'retail_updated' => $retail_updated !== false,
'b2b_updated' => $b2b_updated !== false,
'retail_timestamp' => $retail_updated ? (int)$retail_updated : null,
'b2b_timestamp' => $b2b_updated ? (int)$b2b_updated : null,
];
$response = new WP_REST_Response($data, 200);
$response->header('ETag', $etag);
$response->header('Cache-Control', 'no-cache, must-revalidate');
return $response;
}
Frontend JavaScript Polling (js/main.js):
// ETag-based polling for bandwidth optimization
var quotationCheckETag = null;
function checkQuotationUpdates() {
$.ajax({
url: ambro_site_url + '/wp-json/ambrosiano/v1/check-update',
method: 'GET',
beforeSend: function(xhr) {
// Send cached ETag for conditional request
if (quotationCheckETag) {
xhr.setRequestHeader('If-None-Match', quotationCheckETag);
}
},
statusCode: {
304: function() {
// Not Modified - quotations unchanged, no action needed
// Bandwidth saved: ~1.8KB
}
}
})
.done(function(result, textStatus, xhr) {
// Store new ETag for next request
var newETag = xhr.getResponseHeader('ETag') ||
xhr.getResponseHeader('X-Quotation-ETag');
if (newETag) {
quotationCheckETag = newETag;
}
// Update UI if quotations changed
if (result && result.retail_updated) {
refreshQuotationDisplay();
}
});
}
// Poll every 10 seconds
setInterval(checkQuotationUpdates, 10000);
2. Form Rate Limiting System
A custom anti-spam system that limits form submissions to one per phone number per 12 hours.
Database Schema:
CREATE TABLE wp_ambro_blocked_numbers (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
phone_number VARCHAR(20) NOT NULL,
form_id INT NOT NULL,
last_submission DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY form_phone (form_id, phone_number)
);
Rate Limiting Implementation (inc/prospect_actions.php):
<?php
/**
* Check if user can submit based on 12-hour cooldown
*/
function can_user_submit($phone_number, $form_id) {
global $wpdb;
$table = $wpdb->prefix . 'ambro_blocked_numbers';
$last_submission = $wpdb->get_var($wpdb->prepare(
"SELECT last_submission FROM $table
WHERE phone_number = %s AND form_id = %d",
$phone_number, $form_id
));
if ($last_submission) {
$twelve_hours_ago = time() - (12 * 3600);
return strtotime($last_submission) <= $twelve_hours_ago;
}
return true; // Phone not found, allow submission
}
/**
* CF7 validation filter - rate limiting
*/
add_filter('wpcf7_validate_text*', function($result, $tag) {
$tag = new WPCF7_Shortcode($tag);
if ($tag->name === 'your-phone') {
$phone = $_POST['your-phone'] ?? '';
$form_id = $_POST['_wpcf7'] ?? 0;
if (!empty($phone) && !can_user_submit($phone, $form_id)) {
$result->invalidate($tag,
'Hai già inviato una richiesta. Riprova tra 12 ore.');
} else {
// Record submission
global $wpdb;
$wpdb->replace(
$wpdb->prefix . 'ambro_blocked_numbers',
[
'phone_number' => sanitize_text_field($phone),
'form_id' => intval($form_id),
'last_submission' => current_time('mysql')
]
);
}
}
return $result;
}, 10, 2);
3. Italian Phone Validation
Custom regex validation for Italian mobile and landline numbers.
<?php
/**
* Custom Italian phone number validation for Contact Form 7
*/
add_filter('wpcf7_is_tel', function($result, $tel) {
// Match Italian mobile and landline formats
// Mobile: 338, 347, 366, 333, 329, 346 + 6-7 digits
// Accepts: +39, 0039, or without prefix
$result = preg_match(
'/^(\((00|\+)39\)|(00|\+)39)?(38[890]|34[7-90]|36[680]|33[3-90]|32[89]|346)\d{6,7}$/',
$tel
);
return $result;
}, 10, 2);
4. Custom Contact Form 7 Tags
Extended CF7 with custom form field tags for UTM tracking and dynamic quotation display.
<?php
/**
* Register custom CF7 form tags
*/
add_action('wpcf7_init', function() {
// UTM tracking tags
wpcf7_add_form_tag('ambrosiano_utm_source', function() {
return '<input type="hidden" name="utm_source" value="' .
esc_attr($_GET['utm_source'] ?? 'direct') . '">';
});
wpcf7_add_form_tag('ambrosiano_utm_medium', function() {
return '<input type="hidden" name="utm_medium" value="' .
esc_attr($_GET['utm_medium'] ?? 'web') . '">';
});
// Dynamic quotation display tags
wpcf7_add_form_tag('ambrosiano_value_gold_18', function() {
return number_format(get_option('ambrosiano_value_gold_18'), 2, ',', '.');
});
});
/**
* Custom mail tag for session-based quotation data
*/
add_filter('wpcf7_special_mail_tags', function($output, $name, $html) {
if ($name === 'show_session_diamond_quotation') {
if (isset($_SESSION['ambro_diamond_quotation'])) {
$output = $_SESSION['ambro_diamond_quotation'];
unset($_SESSION['ambro_diamond_quotation']); // One-time use
}
}
return $output;
}, 10, 3);
5. Secure Webhook for External Triggers
Token-authenticated endpoint with rate limiting for triggering quotation refreshes.
<?php
/**
* Secure webhook endpoint for quotation refresh
* Requires token authentication and implements rate limiting
*/
function ambrosiano_rest_webhook_trigger_refresh(WP_REST_Request $request) {
// Validate authentication token
if (!defined('AMBROSIANO_WEBHOOK_TOKEN')) {
return new WP_Error('webhook_misconfigured',
'Webhook not configured', ['status' => 500]);
}
$provided_token = $request->get_param('token')
?: ($request->get_headers()['x_webhook_token'][0] ?? null);
if (empty($provided_token)) {
return new WP_Error('missing_token',
'Authentication required', ['status' => 401]);
}
// Constant-time comparison prevents timing attacks
if (!hash_equals(AMBROSIANO_WEBHOOK_TOKEN, $provided_token)) {
error_log('Webhook: Invalid token from ' . $_SERVER['REMOTE_ADDR']);
return new WP_Error('invalid_token',
'Invalid token', ['status' => 401]);
}
// Rate limiting: 30-second cooldown
$lock = get_transient('ambrosiano_webhook_refresh_lock');
if ($lock !== false) {
return new WP_Error('rate_limit',
'Rate limit exceeded', ['status' => 429]);
}
set_transient('ambrosiano_webhook_refresh_lock', time() + 30, 30);
// Trigger refresh
do_action('ambrosiano_refresh_quotations');
return [
'success' => true,
'message' => 'Quotation refresh triggered',
'timestamp' => time()
];
}
Performance Optimizations
1. ETag-Based Conditional Requests
Problem: Frontend polling every 10 seconds transferred 2KB per request, resulting in 8.4MB/hour per user.
Solution: Implemented HTTP ETag headers with 304 Not Modified responses.
Results:
| Metric | Before | After | Improvement |
|---|---|---|---|
| Response Size (unchanged) | 2KB | 200 bytes | 95% reduction |
| Bandwidth/hour/user | 8.4MB | 420KB | 95% reduction |
| HTTP Status | Always 200 | 304 when cached | Better caching |
2. Quotation Caching with Transients
Problem: CPU load reached 4.7 due to excessive API calls and database queries.
Solution: Implemented transient-based caching with 2-minute refresh intervals.
Results:
| Metric | Before | After | Improvement |
|---|---|---|---|
| API Calls/hour | 120 | 6 | 95% reduction |
| Database Queries/hour | 7,440 | 900 | 88% reduction |
| CPU Load Average | 4.7 | 1.0-1.5 | 68-79% reduction |
3. Conditional Asset Loading
Contact Form 7 CSS/JS only loaded on pages that actually use forms.
<?php
// Only load CF7 assets on specific templates
if (is_page_template([
'tp_section_v1.php',
'tp_quotations.php',
'tp_contact.php',
'tp_landing.php',
])) {
wp_enqueue_style('contact-form-7');
wp_enqueue_script('contact-form-7');
}
Build System (Gulp 4)
Asset Pipeline
// gulpfile.js - Build configuration
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const sourcemaps = require('gulp-sourcemaps');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const imagemin = require('gulp-imagemin');
const webp = require('gulp-webp');
const browserSync = require('browser-sync').create();
// PostCSS processors for cross-browser compatibility
const processors = [
autoprefixer,
require('postcss-pxtorem'),
require('postcss-flexibility'),
require('postcss-will-change'),
require('postcss-color-rgba-fallback'),
];
// SASS Compilation
gulp.task('SASS', function() {
return gulp.src('./sass/**/*.scss')
.pipe(sourcemaps.init())
.pipe(sass({ outputStyle: 'expanded' }).on('error', sass.logError))
.pipe(postcss(processors))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./css'));
});
// JavaScript Bundle
gulp.task('MainJs', function() {
return gulp.src([
'./js/vendor/hoverIntent.js',
'./js/vendor/jquery.validate.js',
'./js/vendor/jquery.fancybox.js',
'./js/vendor/flickity.pkgd.js',
'./js/main.js'
])
.pipe(sourcemaps.init())
.pipe(concat('main.min.js'))
.pipe(uglify())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./js'));
});
// Image Optimization with WebP generation
gulp.task('ImageMin', function() {
return gulp.src('./img_original/*.+(png|jpg|jpeg|gif|svg)')
.pipe(imagemin([
imagemin.gifsicle({ interlaced: true }),
imagemin.jpegtran({ progressive: true }),
imagemin.optipng({ optimizationLevel: 5 }),
imagemin.svgo({ plugins: [{ removeViewBox: false }] })
]))
.pipe(gulp.dest('./img'))
.pipe(webp())
.pipe(gulp.dest('./img'));
});
// Development server with live reload
gulp.task('default', gulp.parallel('watch', 'BrowserSync'));
Development Workflow
Local Environment (Docker)
# docker-compose.yml
version: '3.8'
services:
wordpress:
image: wordpress:latest
ports: ['80:80']
volumes:
- ./:/var/www/html
environment:
WORDPRESS_DB_HOST: mariadb
WORDPRESS_DB_NAME: ambrosianomilano
mariadb:
image: mariadb:10.6
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: ambrosianomilano
redis:
image: redis:alpine
ports: ['6379:6379']
Deployment Process
# Push theme changes to production
rsync -avzP --delete \
--exclude='.git' \
--exclude='node_modules' \
--exclude='img_original' \
./wp-content/themes/ambrosiano-theme/ \
user@138.68.111.141:/path/to/public_html/wp-content/themes/ambrosiano-theme/
Project Statistics
| Metric | Value |
|---|---|
| Total Commits | 124 |
| Commits (2024-2025) | 64 |
| PHP Lines of Code | ~19,600 |
| Page Templates | 30+ |
| REST API Endpoints | 6 |
| External API Integrations | 4 |
| Custom Database Tables | 2 |
| ACF Field Groups | 5 |
Key Challenges Solved
1. SMS Service Resilience
Challenge: Esendex SMS API downtime caused form submissions to hang for 5+ minutes.
Solution: Implemented quick timeout (10s) with graceful degradation – forms complete successfully regardless of SMS delivery status. Documented async queue architecture for future implementation.
2. MariaDB 10.6 Compatibility
Challenge: Database dump imports failed due to MariaDB sandbox mode comments.
Solution: Created preprocessing script that strips MariaDB-specific comments before import.
# Skip MariaDB sandbox comment on line 1 tail -n +2 dump.sql > dump-fixed.sql docker exec -i mariadb mysql -uroot -p dbname < dump-fixed.sql
3. Cloudways ETag Header Filtering
Challenge: Nginx on Cloudways stripped standard ETag headers from responses.
Solution: Added custom X-Quotation-ETag header alongside standard ETag, with JavaScript fallback to check both headers.
Technologies & Skills Demonstrated
Backend:
- WordPress Plugin/Theme Development
- Custom REST API Development
- Database Design & Optimization
- External API Integration
- Security (Token Auth, Rate Limiting, Input Validation)
- Cron Jobs & Background Processing
Frontend:
- SASS/SCSS with PostCSS
- JavaScript (jQuery, AJAX)
- HTTP Caching (ETag, 304 Not Modified)
- Form Validation
- Responsive Design
DevOps:
- Docker Development Environment
- SSH/rsync Deployment
- MariaDB Administration
- Redis Caching
- Nginx Configuration
Tools:
- Git Version Control
- Gulp 4 Build System
- BrowserSync
- WP-CLI