A WordPress plugin that calculates the structural snow load for any address in Germany – using geocoding, elevation data, and the actual DIN EN 1991-1-3 formulas – and then shows how many days per year a terrace canopy would extend outdoor living. Two tools in one plugin, one address input, two parallel AJAX calls.
I built this for a company that sells terrace canopies, conservatories, and carports. Their sales team needed two things for every customer consultation: what's the snow load at this location (for structural calculations), and how many extra days of terrace use does a canopy provide (for the sales pitch). Before, they used a buggy Excel spreadsheet for the snow load and guessed the terrace days.
How the Snow Load Calculation Works
Germany is divided into five snow load zones (1, 1a, 2, 2a, 3). Each zone has its own formula from DIN EN 1991-1-3:
Zone 1: sk = 0.19 + 0.91 × ((A + 140) / 760)²
Zone 1a: sk = 1.25 × (0.19 + 0.91 × ((A + 140) / 760)²)
Zone 2: sk = 0.25 + 1.91 × ((A + 140) / 760)²
Zone 2a: sk = 1.25 × (0.25 + 1.91 × ((A + 140) / 760)²)
Zone 3: sk = 0.31 + 2.91 × ((A + 140) / 760)²
Where A = elevation above sea level in meters and sk = snow load in kN/m².
The plugin needs two inputs: the snow load zone and the elevation. Getting both from just an address requires three steps.
Step 1: Postal Code → Snow Load Zone
A 1.3 MB JSON file maps every German postal code to its snow load zone. This runs as a local lookup – no API call needed.
$zones = json_decode(file_get_contents('snowloadzones.json'), true);
$zone = $zones[$plz]; // e.g. "2"
This is the most reliable part. The postal code mapping is static data from the DIN standard. No external dependency, no rate limits, instant.
Step 2: Address → Coordinates → Elevation
This is where OpenRouteService comes in. Two API calls, running server-side via PHP:
Geocoding: The structured address (street, number, postal code, city) is sent to /geocode/search/structured. Returns latitude and longitude.
Elevation: The coordinates are sent to /elevation/point. Returns the height above sea level in meters.
// Simplified flow
$coords = openroute_geocode($street, $nr, $plz, $city);
// → ['lat' => 53.5511, 'lng' => 9.9937]
$elevation = openroute_elevation($coords['lat'], $coords['lng']);
// → 18 (meters above sea level)
I chose OpenRouteService over Google Maps because it's free for moderate query volumes and doesn't require a credit card. The elevation data comes from SRTM (Shuttle Radar Topography Mission) – accurate enough for snow load calculations where a few meters don't change the result significantly.
Step 3: Apply the Formula
Zone + elevation → formula → result.
For an address in Hamburg (zone 2, 18m elevation):
sk = 0.25 + 1.91 × ((18 + 140) / 760)²
sk = 0.25 + 1.91 × (158 / 760)²
sk = 0.25 + 1.91 × 0.0432
sk = 0.33 kN/m²
That's 34 kg per square meter. The plugin displays both kN/m² and kg/m², plus the full formula so the user can verify the calculation.
The Terrace Time Calculator
Same address input, completely different calculation. While the snow load AJAX call runs, a parallel request goes to a weather data API that returns historical temperature statistics for the location.
The plugin sorts all 365 days into five categories:
| Category | Temperature | Meaning |
|---|---|---|
| Ice days | below 0°C | Not usable |
| Cold days | 0–10°C | Usable with conservatory |
| Potential days | 10–25°C | Usable with terrace canopy |
| Summer days | 25–30°C | Pleasant without any cover |
| Hot days | above 30°C | Too hot – canopy shade helps |
Without a canopy, only summer days count as real terrace days. For Hamburg, that's about 29 days per year (8%).
The magic happens with two interactive checkboxes: "Terrace canopy" and "Conservatory". When the user checks "Terrace canopy", the potential days are added – the pie chart animates from gray to green, and the number jumps from 29 to around 229 days. Check both, and you're at 344 days (94%).
The pie chart is rendered with Chart.js. The animation on checkbox click is the key UX moment – watching the chart turn green while the number climbs from 29 to 344 is more persuasive than any brochure.
Why Two Tools in One Plugin?
Because they belong together in practice. Every customer consultation needs both: the snow load for structural engineering and the terrace time visualization for the purchase decision.
The sales rep enters the customer's address once. Both AJAX requests fire in parallel. Seconds later, both results are on screen:
- Left side: Snow load, structural calculations, rafter sizing for different profiles
- Right side: Pie chart showing terrace potential, animated checkboxes for products
The snow load determines the technical requirements: which rafter profile, what glass thickness, how much reinforcement. The terrace time calculator delivers the sales argument: "At your location, a terrace canopy gives you 200 extra days of outdoor living per year."
// Both requests fire in parallel
$.when(
$.ajax({ url: ajaxurl, data: { action: 'calc_snowload', ... } }),
$.ajax({ url: ajaxurl, data: { action: 'calculate_regentage', ... } })
).then(function(snowResult, weatherResult) {
renderSnowLoad(snowResult);
renderTerraceTime(weatherResult);
});
The Expert Mode
There are actually two modes. The standard mode is public on the company website – anyone can enter an address, get their snow load and terrace potential, and leave their email for the full report. Classic lead magnet.
The expert mode is for the sales team only. It adds input fields for the planned canopy dimensions: width, depth, glass thickness, height offset, rafter profile. The plugin then calculates not just the snow load but the actual load on the planned structure – including snow load with and without wedge factor, total weight in kg, and rafter sizing across all available profiles (S through XL+).
It checks deflection and stress limits for the company's own product lines and shows green checkmarks for profiles that pass. The sales rep can configure the exact canopy in front of the customer and show immediately whether the chosen profile handles the local snow load.
Architecture Overview
Address Input (Street, Nr, Postal Code, City)
│
┌───────┴───────┐
▼ ▼
SNOW LOAD TERRACE TIME
│ │
PLZ → JSON Weather API
(Zone 1-3) (Temperature data)
│ │
Geocoding │
(→ Coordinates) │
│ │
Elevation │
(→ Height ASL) │
│ │
DIN Formula Sort days
(Zone + Height) (5 categories)
│ │
▼ ▼
0.33 kN/m² 29 → 344 days
(34 kg/m²) (+315 with canopy)
│ │
└───────┬───────┘
▼
Result Display
(Snow load + Pie chart)
The plugin is ~12 files total. PHP backend, jQuery frontend, two JSON data files, email and print templates. No build step, no npm, no framework. It's a WordPress plugin – it gets uploaded, activated, and works.
What I'd Do Differently
Caching. Every calculation makes two live API calls to OpenRouteService. For a tool used by a sales team with maybe 20 queries per day, that's fine. But if the public version gets heavy traffic, I'd add transient caching keyed by postal code + street. Most addresses in the same postal code area have nearly identical elevations.
The weather data API is a separate plugin that I didn't build. If I were starting fresh, I'd integrate it into the same plugin and use Open-Meteo's free historical weather API. One less dependency.
TypeScript instead of jQuery. The plugin was built for a specific WordPress setup where jQuery was already loaded. For a new project, I'd use vanilla JS or a small reactive framework for the interactive elements.
I'm Joshua, freelance web developer from Hamburg. I build WordPress plugins, Shopify themes and custom web tools. More case studies on hafenpixel.de.
Top comments (0)