Hail Alley Watch Storm activity reported across Comal & Kendall County — free post-storm roof inspections are being scheduled now. Start a claim →
▲ Serving 10 Hill Country counties ⚑ 3618 Barrington St, San Antonio, TX 78217 Mon–Sat 7a–7p
Developer resources

WordPress code assets for the county silo.

Five deployable files that build 14 Hill Country county landing pages from one template, each emitting its own RoofingContractor schema. Corrected against the current business facts — 512-844-5900, 3618 Barrington St, San Antonio, TX 78217 — and repainted in the earth-tone system.

What is this page for?

A1 runs a WordPress geo-silo alongside this site. These are the actual source files for it, regenerated so both properties state the same phone number, the same physical address, and the same palette. Copy a pane, paste it into WordPress, follow the six-step order below. The deployment notes pane lists the four things that will get a county silo filtered out of the index if you skip them.

Export center

Copy, paste, deploy.

Every pane is complete and self-contained — no truncation, no // TODO, no placeholder credentials invented on A1's behalf.

a1-geo-silo.php · PHP

Schema handler, phone shortcode and county lead routing. Child theme or standalone plugin.

<?php /** * A1 Hill Country Roofing & Remodeling * Automated Geo-Silo & Schema Handler — v2.0 * Site: www.a1hillcountry.com * * Drop into your child theme's functions.php, or better, save as * wp-content/plugins/a1-geo-silo/a1-geo-silo.php with a plugin header so the * behaviour survives a theme change. */ if (!defined('ABSPATH')) exit; /* ------------------------------------------------------------------------- * 1. Allow shortcodes inside ACF text fields * Lets [acf field="..."] tokens resolve inside Elementor widgets. * ---------------------------------------------------------------------- */ add_filter('acf/format_value/type=text', 'do_shortcode', 10, 3); add_filter('acf/format_value/type=textarea', 'do_shortcode', 10, 3); /* ------------------------------------------------------------------------- * 2. Per-county RoofingContractor schema * NOTE: one physical office, many service areas. We publish a single * verifiable postal address on every county page and vary only areaServed. * Inventing a street address per county is the fastest way to get a * Google Business Profile suspended. * ---------------------------------------------------------------------- */ add_action('wp_head', 'a1_inject_county_schema', 20); function a1_inject_county_schema() { if (!is_page()) return; if (!function_exists('get_field')) return; $city = get_field('geo_city_name'); $tagline = get_field('geo_county_tagline'); if (!$city || !$tagline) return; $phone = get_field('geo_phone_number') ?: '512-844-5900'; $email = get_field('geo_lead_email') ?: 'office@a1hillcountry.com'; $towns = get_field('geo_communities'); $area = array( array('@type' => 'AdministrativeArea', 'name' => $tagline), array('@type' => 'City', 'name' => $city), ); // Each named community becomes its own areaServed entity. if ($towns) { foreach (array_filter(array_map('trim', explode(',', $towns))) as $t) { $area[] = array('@type' => 'Place', 'name' => $t); } } $services = array( 'Standing Seam Metal Roof Installation', 'Class 4 Impact-Resistant Shingle Installation', 'Clay & Concrete Tile Roofing', 'Storm & Hail Damage Roof Replacement', 'Whole-Home Remodeling', 'Seamless Gutters & Rainwater Collection', 'HOA & ARC Submittal Assistance', ); $catalog = array(); foreach ($services as $s) { $catalog[] = array( '@type' => 'Offer', 'itemOffered' => array('@type' => 'Service', 'name' => $s), ); } $schema = array( '@context' => 'https://schema.org', '@type' => 'RoofingContractor', '@id' => 'https://www.a1hillcountry.com/#' . sanitize_title($city), 'name' => 'A1 Hill Country Roofing & Remodeling — ' . $city, 'url' => get_permalink(), 'image' => 'https://www.a1hillcountry.com/wp-content/uploads/logo.png', 'telephone' => $phone, 'email' => $email, 'priceRange' => '$$$', 'address' => array( '@type' => 'PostalAddress', 'streetAddress' => '3618 Barrington St', 'addressLocality' => 'San Antonio', 'addressRegion' => 'TX', 'postalCode' => '78217', 'addressCountry' => 'US', ), 'areaServed' => $area, 'hasOfferCatalog' => array( '@type' => 'OfferCatalog', 'name' => 'Hill Country Roofing & Remodeling Services', 'itemListElement' => $catalog, ), ); echo '<script type="application/ld+json">' . wp_json_encode($schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '</script>' . "\n"; } /* ------------------------------------------------------------------------- * 3. Clean canonicals (Rank Math) * ---------------------------------------------------------------------- */ add_filter('rank_math/frontend/canonical', function ($canonical) { return is_page() ? get_permalink() : $canonical; }); /* ------------------------------------------------------------------------- * 4. Click-to-call shortcode — [a1_phone] / [a1_phone link="1"] * Single source of truth for the number so a future change is one edit. * ---------------------------------------------------------------------- */ add_shortcode('a1_phone', function ($atts) { $a = shortcode_atts(array('link' => '0', 'label' => ''), $atts); $display = '512-844-5900'; $href = 'tel:+15128445900'; if ($a['link'] === '1') { $label = $a['label'] ? $a['label'] : $display; return '<a href="' . esc_attr($href) . '" class="a1-tel">' . esc_html($label) . '</a>'; } return esc_html($display); }); /* ------------------------------------------------------------------------- * 5. Route county form entries to the county inbox * Elementor Pro Forms: send the lead to the geo_lead_email of the page it * was submitted from, with the office address as a permanent fallback. * ---------------------------------------------------------------------- */ add_action('elementor_pro/forms/new_record', function ($record, $handler) { if (!function_exists('get_field')) return; $to = get_field('geo_lead_email', get_the_ID()); if (!$to) return; $lines = array(); foreach ($record->get('fields') as $f) { $lines[] = $f['title'] . ': ' . $f['value']; } $lines[] = 'Page: ' . get_permalink(); wp_mail( $to, 'County lead — ' . get_field('geo_city_name'), implode("\n", $lines), array('Bcc: office@a1hillcountry.com') ); }, 10, 2);
a1-acf-field-group.json · JSON

Import this FIRST. The CSV maps to these field names.

[ { "key": "group_a1_geo_silo", "title": "A1 County Geo-Silo Fields", "fields": [ { "key": "field_geo_city_name", "label": "Primary City", "name": "geo_city_name", "type": "text", "required": 1, "instructions": "The anchor city for this silo, e.g. Boerne. Used in schema name and H1 tokens." }, { "key": "field_geo_county_tagline", "label": "County", "name": "geo_county_tagline", "type": "text", "required": 1, "instructions": "e.g. Kendall County. Emitted as schema areaServed AdministrativeArea." }, { "key": "field_geo_hero_headline", "label": "Hero Headline", "name": "geo_hero_headline", "type": "text", "required": 1, "maxlength": 90 }, { "key": "field_geo_hero_subheadline", "label": "Hero Sub-headline", "name": "geo_hero_subheadline", "type": "textarea", "rows": 3, "maxlength": 220 }, { "key": "field_geo_communities", "label": "Communities Served", "name": "geo_communities", "type": "text", "instructions": "Comma separated. Each becomes a schema areaServed Place." }, { "key": "field_geo_phone_number", "label": "Tracking Phone", "name": "geo_phone_number", "type": "text", "default_value": "512-844-5900", "instructions": "Leave as the main line unless this silo has its own call-tracking number." }, { "key": "field_geo_lead_email", "label": "Lead Inbox", "name": "geo_lead_email", "type": "email", "default_value": "office@a1hillcountry.com" } ], "location": [ [ { "param": "page_template", "operator": "==", "value": "default" } ] ], "menu_order": 0, "position": "acf_after_title", "style": "default", "active": true, "description": "Drives county landing page content and per-page RoofingContractor schema." } ]
a1_counties.csv · CSV

One row per county landing page. Phone corrected on every row.

post_title,post_name,geo_city_name,geo_county_tagline,geo_hero_headline,geo_hero_subheadline,geo_communities,geo_phone_number,geo_lead_email Boerne Roofing,boerne-roofing,Boerne,Kendall County,Premier Custom & Metal Roofing in Boerne TX,HOA-compliant Class 4 impact-resistant roof systems designed for Kendall County estates.,"Cordillera Ranch, Esperanza, Menger Springs, Fair Oaks Ranch",512-844-5900,boerne@a1hillcountry.com Fredericksburg Roofing,fredericksburg-roofing,Fredericksburg,Gillespie County,Historic & Commercial Roofing Specialists in Fredericksburg TX,Preserving Gillespie County heritage with historic-compliant metal and commercial roof systems.,"Historic Main Street, 290 Wine Trail, Stonewall, Harper",512-844-5900,fredericksburg@a1hillcountry.com Comal County Roofing,comal-county-roofing,New Braunfels,Comal County,Comal County & Canyon Lake Hail Restoration & Roofing,Class 4 impact-resistant roofs and insurance claim documentation for New Braunfels and Canyon Lake.,"New Braunfels, Bulverde, Spring Branch, Canyon Lake",512-844-5900,comal@a1hillcountry.com Kerr County Roofing,kerr-county-roofing,Kerrville,Kerr County,Kerrville & Kerr County Metal & Residential Roofing,Fire-resistant cool-roof metal systems built to lower attic heat and withstand severe weather.,"Kerrville, Hunt, Ingram, Center Point",512-844-5900,kerr@a1hillcountry.com Hays County Roofing,hays-county-roofing,Dripping Springs,Hays County,Rainwater-Safe Metal Roofing in Hays County TX,Non-toxic Kynar-coated metal roofing engineered for custom estates and rainwater collection.,"Dripping Springs, Wimberley, San Marcos, Belterra",512-844-5900,hays@a1hillcountry.com Lake Travis Luxury Roofing,lake-travis-roofing,Lakeway,West Travis County,Lake Travis Luxury Roof Replacement & Custom Metal,High-wind resistant standing seam metal and tile systems for waterfront cliffside estates.,"Lakeway, Bee Cave, Spicewood, Steiner Ranch",512-844-5900,laketravis@a1hillcountry.com Burnet County Roofing,burnet-county-roofing,Marble Falls,Burnet County,Horseshoe Bay & Marble Falls Lakefront Roofing,Corrosion-resistant fasteners and high-wind rated assemblies for Lake LBJ properties.,"Horseshoe Bay, Marble Falls, Burnet, Lake LBJ",512-844-5900,burnet@a1hillcountry.com Blanco County Roofing,blanco-county-roofing,Johnson City,Blanco County,Johnson City & Blanco TX Ranch Metal Roofing,Heavy-gauge standing seam and ag-building metal roofing built for Hill Country ranches.,"Johnson City, Blanco, Round Mountain",512-844-5900,blanco@a1hillcountry.com Bandera County Roofing,bandera-county-roofing,Bandera,Bandera County,Bandera TX Ranch & Rustic Metal Roofing,Rugged Class A fire-rated standing seam and metal shake systems for Bandera County ranches.,"Bandera, Medina, Pipe Creek, Tarpley",512-844-5900,bandera@a1hillcountry.com Llano County Roofing,llano-county-roofing,Kingsland,Llano County,Kingsland & Llano TX Metal Roof Installers,Reflective cool-roof metal for Lake Buchanan and Kingsland homes facing full western sun.,"Kingsland, Llano, Sunrise Beach, Tow",512-844-5900,llano@a1hillcountry.com Medina County Roofing,medina-county-roofing,Castroville,Medina County,Castroville & Hondo Historic & Ag Metal Roofing,Preserving Castroville historic homes and roofing Hondo agricultural facilities.,"Castroville, Hondo, Devine, LaCoste",512-844-5900,medina@a1hillcountry.com Real County Roofing,real-county-roofing,Leakey,Real County,Leakey & Frio River Cabin Metal Roofing,High-slope standing seam installations engineered for steep Frio River terrain.,"Leakey, Camp Wood, Rio Frio, Utopia",512-844-5900,real@a1hillcountry.com Mason County Roofing,mason-county-roofing,Mason,Mason County,Mason & Junction TX Working Ranch Metal Roofing,24-gauge commercial standing seam built for working livestock ranches.,"Mason, Art, Fredonia, Castell",512-844-5900,mason@a1hillcountry.com West Williamson Roofing,williamson-west-roofing,Liberty Hill,West Williamson County,Liberty Hill & Leander Class 4 Storm Roofing,HOA-compliant Class 4 shingle and standing seam roofing for master-planned communities.,"Liberty Hill, Leander, Cedar Park, Santa Rita Ranch",512-844-5900,williamson@a1hillcountry.com
a1-county-template.json · JSON

Earth-tone hero, lead form, GEO answer band and closing CTA.

{ "version": "0.4", "title": "A1 Hill Country — Master County Landing Page (v2.0 Earth-Tone)", "type": "page", "content": [ { "id": "a1heroc", "elType": "container", "isInner": false, "settings": { "content_width": "full", "container_type": "flex", "flex_direction": "row", "flex_direction_tablet": "column", "flex_gap": { "unit": "px", "size": 44 }, "background_background": "classic", "background_color": "#2E241A", "background_overlay_background": "gradient", "padding": { "unit": "px", "top": "96", "bottom": "96", "left": "24", "right": "24" } }, "elements": [ { "id": "a1herol", "elType": "container", "isInner": true, "settings": { "width": { "unit": "%", "size": 58 }, "width_tablet": { "unit": "%", "size": 100 }, "flex_direction": "column" }, "elements": [ { "id": "a1badge", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<span style=\"display:inline-block;color:#C8A87C;background:rgba(200,168,124,.12);border:1px solid rgba(200,168,124,.34);padding:5px 14px;border-radius:2px;font-family:Archivo,sans-serif;font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;\">[acf field=\"geo_county_tagline\"] Systems Specialist</span>" } }, { "id": "a1h1", "elType": "widget", "widgetType": "heading", "settings": { "title": "[acf field=\"geo_hero_headline\"]", "header_size": "h1", "title_color": "#F4EFE4", "typography_typography": "custom", "typography_font_family": "Fraunces", "typography_font_size": { "unit": "px", "size": 50 }, "typography_font_size_tablet": { "unit": "px", "size": 38 }, "typography_font_size_mobile": { "unit": "px", "size": 31 }, "typography_font_weight": "700", "typography_line_height": { "unit": "em", "size": 1.06 }, "_margin": { "unit": "px", "top": "16", "bottom": "14", "left": "0", "right": "0" } } }, { "id": "a1sub", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<p style=\"color:#B4ADA0;font-family:Archivo,sans-serif;font-size:18px;line-height:1.62;max-width:52ch;\">[acf field=\"geo_hero_subheadline\"]</p>" } }, { "id": "a1proof", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<ul style=\"list-style:none;padding:0;margin:22px 0 0;font-family:Archivo,sans-serif;font-size:14.5px;color:#DED3BE;line-height:1.9;\">\n <li>&#9656;&nbsp; Class 4 impact-resistant shingles (UL 2218) standard, not an upsell</li>\n <li>&#9656;&nbsp; Synthetic underlayment on every tear-off</li>\n <li>&#9656;&nbsp; Serving [acf field=\"geo_communities\"]</li>\n <li>&#9656;&nbsp; Physical office at 3618 Barrington St, San Antonio, TX 78217 &mdash; not a P.O. box</li>\n</ul>" } }, { "id": "a1tel", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<p style=\"margin-top:26px;font-family:Archivo,sans-serif;font-size:15px;color:#F4EFE4;\">Talk to the owner: <a href=\"tel:+15128445900\" style=\"color:#C8A87C;font-weight:700;text-decoration:none;border-bottom:1px solid rgba(200,168,124,.45);\">[a1_phone]</a></p>" } } ] }, { "id": "a1heror", "elType": "container", "isInner": true, "settings": { "width": { "unit": "%", "size": 42 }, "width_tablet": { "unit": "%", "size": 100 }, "background_background": "classic", "background_color": "#FFFDF8", "border_border": "solid", "border_width": { "unit": "px", "top": "1", "bottom": "1", "left": "1", "right": "1" }, "border_color": "#DED3BE", "border_radius": { "unit": "px", "top": "10", "right": "10", "bottom": "10", "left": "10" }, "box_shadow_box_shadow_type": "yes", "box_shadow_box_shadow": { "horizontal": 0, "vertical": 24, "blur": 60, "spread": -18, "color": "rgba(31,24,16,.35)" }, "padding": { "unit": "px", "top": "34", "bottom": "34", "left": "30", "right": "30" } }, "elements": [ { "id": "a1formh", "elType": "widget", "widgetType": "heading", "settings": { "title": "Free roof inspection in [acf field=\"geo_city_name\"]", "header_size": "h3", "title_color": "#2A2118", "typography_typography": "custom", "typography_font_family": "Fraunces", "typography_font_size": { "unit": "px", "size": 25 }, "typography_font_weight": "600" } }, { "id": "a1formsub", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<p style=\"color:#574839;font-family:Archivo,sans-serif;font-size:14px;line-height:1.6;margin:8px 0 18px;\">We photograph the roof, hand you the findings, and tell you plainly whether it needs work. No obligation and no high-pressure close.</p>" } }, { "id": "a1form", "elType": "widget", "widgetType": "form", "settings": { "form_name": "County Lead Capture — [acf field=\"geo_city_name\"]", "form_fields": [ { "custom_id": "name", "field_type": "text", "field_label": "Name", "placeholder": "Full name", "required": "true", "width": "100" }, { "custom_id": "phone", "field_type": "tel", "field_label": "Phone", "placeholder": "512-000-0000", "required": "true", "width": "50" }, { "custom_id": "email", "field_type": "email", "field_label": "Email", "placeholder": "you@email.com", "width": "50" }, { "custom_id": "address", "field_type": "text", "field_label": "Property address", "placeholder": "Street, city, ZIP", "required": "true", "width": "100" }, { "custom_id": "concern", "field_type": "textarea", "field_label": "What is going on?", "placeholder": "Roof age, leaks, storm date, or what you want changed.", "rows": 3, "width": "100" }, { "custom_id": "source_county", "field_type": "hidden", "field_label": "County", "field_value": "[acf field=\"geo_county_tagline\"]", "width": "100" } ], "submit_button_text": "Request my inspection", "button_background_color": "#B4571F", "button_text_color": "#FFFFFF", "button_border_radius": { "unit": "px", "top": "4", "right": "4", "bottom": "4", "left": "4" }, "button_typography_typography": "custom", "button_typography_font_family": "Archivo", "button_typography_font_weight": "700", "success_message": "Received. We will call you from 512-844-5900 to set a time — usually the same business day.", "error_message": "That did not send. Please call 512-844-5900 instead." } }, { "id": "a1formfoot", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<p style=\"color:#574839;font-family:Archivo,sans-serif;font-size:11.5px;line-height:1.55;margin-top:14px;\">By submitting you agree to be contacted about your request. We do not sell contact information.</p>" } } ] } ] }, { "id": "a1answers", "elType": "container", "isInner": false, "settings": { "content_width": "full", "container_type": "flex", "flex_direction": "row", "flex_direction_tablet": "column", "flex_gap": { "unit": "px", "size": 22 }, "background_background": "classic", "background_color": "#EBE3D3", "padding": { "unit": "px", "top": "64", "bottom": "64", "left": "24", "right": "24" } }, "elements": [ { "id": "a1a1", "elType": "container", "isInner": true, "settings": { "width": { "unit": "%", "size": 33 }, "background_background": "classic", "background_color": "#FFFDF8", "border_border": "solid", "border_width": { "unit": "px", "top": "1", "bottom": "1", "left": "1", "right": "5" }, "border_color": "#C8A87C", "border_radius": { "unit": "px", "top": "8", "right": "8", "bottom": "8", "left": "8" }, "padding": { "unit": "px", "top": "24", "bottom": "24", "left": "24", "right": "24" } }, "elements": [ { "id": "a1a1t", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<h2 style=\"font-family:Fraunces,Georgia,serif;font-size:19px;color:#2A2118;margin:0 0 9px;\">What roof holds up best in [acf field=\"geo_county_tagline\"]?</h2><p style=\"font-family:Archivo,sans-serif;font-size:14.5px;line-height:1.65;color:#574839;margin:0;\">A UL 2218 Class 4 impact-rated system. In the hail corridor that runs through the Hill Country, the impact rating decides whether a storm costs you a claim or a rinse. Most Texas carriers credit 10&ndash;25% of the wind-and-hail portion of the premium for a Class 4 roof.</p>" } } ] }, { "id": "a1a2", "elType": "container", "isInner": true, "settings": { "width": { "unit": "%", "size": 33 }, "background_background": "classic", "background_color": "#FFFDF8", "border_border": "solid", "border_width": { "unit": "px", "top": "1", "bottom": "1", "left": "1", "right": "5" }, "border_color": "#C8A87C", "border_radius": { "unit": "px", "top": "8", "right": "8", "bottom": "8", "left": "8" }, "padding": { "unit": "px", "top": "24", "bottom": "24", "left": "24", "right": "24" } }, "elements": [ { "id": "a1a2t", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<h2 style=\"font-family:Fraunces,Georgia,serif;font-size:19px;color:#2A2118;margin:0 0 9px;\">Does a metal roof lower cooling costs here?</h2><p style=\"font-family:Archivo,sans-serif;font-size:14.5px;line-height:1.65;color:#574839;margin:0;\">Yes, when it is installed as a system. A reflective standing seam panel over a vented air gap with balanced intake and exhaust can drop peak attic temperature by up to about 40&deg;F versus dark asphalt on a sealed deck. The panel alone is not what does it &mdash; the air gap and the ventilation are.</p>" } } ] }, { "id": "a1a3", "elType": "container", "isInner": true, "settings": { "width": { "unit": "%", "size": 33 }, "background_background": "classic", "background_color": "#FFFDF8", "border_border": "solid", "border_width": { "unit": "px", "top": "1", "bottom": "1", "left": "1", "right": "5" }, "border_color": "#C8A87C", "border_radius": { "unit": "px", "top": "8", "right": "8", "bottom": "8", "left": "8" }, "padding": { "unit": "px", "top": "24", "bottom": "24", "left": "24", "right": "24" } }, "elements": [ { "id": "a1a3t", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<h2 style=\"font-family:Fraunces,Georgia,serif;font-size:19px;color:#2A2118;margin:0 0 9px;\">Who pays my deductible?</h2><p style=\"font-family:Archivo,sans-serif;font-size:14.5px;line-height:1.65;color:#574839;margin:0;\">You do. Any contractor in Texas offering to waive, absorb, or rebate your deductible is proposing insurance fraud and naming you as a participant. We document damage, meet your adjuster on the roof, and supplement with evidence &mdash; we do not file or negotiate the claim for you, because that is public adjusting and it requires a license we do not hold.</p>" } } ] } ] }, { "id": "a1cta", "elType": "container", "isInner": false, "settings": { "content_width": "boxed", "background_background": "classic", "background_color": "#4A3B2C", "padding": { "unit": "px", "top": "58", "bottom": "58", "left": "24", "right": "24" } }, "elements": [ { "id": "a1ctat", "elType": "widget", "widgetType": "text-editor", "settings": { "editor": "<div style=\"text-align:center;\">\n <h2 style=\"font-family:Fraunces,Georgia,serif;font-size:31px;color:#F4EFE4;margin:0 0 12px;\">Serving [acf field=\"geo_city_name\"] and the rest of [acf field=\"geo_county_tagline\"].</h2>\n <p style=\"font-family:Archivo,sans-serif;font-size:16px;color:#DED3BE;max-width:60ch;margin:0 auto 22px;\">One office, one owner, and a truck that has been on these roads long enough to know which roads flood. Call and you will reach someone who can answer a technical question.</p>\n <a href=\"tel:+15128445900\" style=\"display:inline-block;background:#B4571F;color:#fff;font-family:Archivo,sans-serif;font-weight:700;font-size:15px;padding:15px 30px;border-radius:4px;text-decoration:none;\">Call [a1_phone]</a>\n</div>" } } ] } ] }
README.txt · TEXT

Order of operations and the things that will get the silo filtered if skipped.

A1 HILL COUNTRY — COUNTY GEO-SILO DEPLOYMENT ============================================= Builds 14 county landing pages driven by ACF fields, each emitting its own RoofingContractor schema, from one Elementor template. REQUIRES WordPress 6.x · Advanced Custom Fields (free tier is enough) Elementor Pro (the form widget is Pro-only) WP All Import, or Import WP, for the CSV step Rank Math (optional — only the canonical filter depends on it) ORDER OF OPERATIONS — do not reorder steps 1 and 2 1. ACF → Tools → Import Field Groups → paste a1-acf-field-group.json The CSV columns map to these field NAMES. Import the CSV first and the values land nowhere. 2. functions.php → child theme, or a1-geo-silo plugin file Verify one page renders JSON-LD before continuing. 3. Templates → Saved Templates → Import → a1-county-template.json 4. Create one page per CSV row, apply the template, or map the template in your importer. Set post_name exactly as given so URLs stay stable. 5. Import a1_counties.csv, mapping: post_title → page title post_name → page slug geo_* → matching ACF field 6. Rank Math → Titles & Meta → set the page title pattern to %title% | A1 Hill Country and write a unique meta description per county. Do not template these; duplicate descriptions across 14 near-identical pages is the single most common way a county silo gets filtered out of the index. CONTACT DATA IN THIS EXPORT Phone 512-844-5900 (v1 shipped a placeholder demo number on all 14 rows; it is corrected throughout this export) Address 3618 Barrington St, San Antonio, TX 78217 Email office@a1hillcountry.com BEFORE YOU PUBLISH — read this part · Per-county email inboxes must exist or forward somewhere real. A silo pointing at a dead mailbox loses leads silently. · Do NOT invent a street address per county. Every page here publishes the one real office address and varies only areaServed. Fake local addresses are the fastest route to a Google Business Profile suspension. · Do NOT add aggregateRating markup until real, verifiable reviews exist on a first-party page. Self-serving rating markup is a manual-action risk. · Each county page needs at least one genuinely local paragraph — a real HOA, a real subdivision, an actual permitting quirk. Fourteen pages that differ only by a swapped county name are doorway pages by Google's own definition and get treated accordingly. · Replace the RCAT license number in site copy before launch. The founding year is confirmed as 2024 and is no longer a placeholder. WHAT CHANGED FROM v1 · Phone corrected on all 14 CSV rows and in the PHP fallback · Palette moved from navy #0F172A to the earth-tone system · Fonts moved from Outfit to Fraunces + Archivo · ACF field group is now included (v1 read fields it never shipped) · Schema gained per-community areaServed Place entries and a 7-item catalog · Added [a1_phone] shortcode as the single source of truth for the number · Added county-inbox routing for Elementor Pro form submissions · Template gained a GEO/AEO answer band and a closing CTA
Deployment order

Two of these steps cannot be swapped.

Import the field group before the CSV or the values land nowhere, and confirm the schema renders before you build 14 pages on top of it.

Import the ACF field group

ACF → Tools → Import Field Groups. Do this before the CSV; the import maps to these exact field names.

Install the PHP

Child theme functions.php, or save it as a small plugin so it survives a theme change. Confirm one page emits JSON-LD before continuing.

Import the Elementor template

Templates → Saved Templates → Import. Apply it to each county page, or map it in your importer.

Import the county CSV

Map post_title, post_name, and each geo_ column to the matching ACF field. Keep the slugs exactly as given.

Write 14 unique meta descriptions

Do not template them. Duplicate descriptions across near-identical pages is the most common reason a county silo gets filtered from the index.

Add one genuinely local paragraph per page

A real HOA, subdivision, or permitting quirk. Pages that differ only by a swapped county name meet Google's own definition of doorway pages.

What changed from v1

Five corrections, and why each one mattered.

The phone number is corrected on all 14 rows

Every county row in the v1 CSV carried the same placeholder demo number, and the PHP fallback repeated it. A landing page that ranks and then routes the call nowhere is worse than no landing page. This export uses 512-844-5900 throughout, and adds an [a1_phone] shortcode so the next change is one edit instead of fifteen.

Navy became limestone

The v1 Elementor hero was navy #0F172A with Outfit — a palette that reads as generic contractor and matches nothing on this site. The template now uses the same bark, limestone and desert-tan tokens and the same Fraunces/Archivo pairing, so the WordPress county pages and the main site cannot drift apart visually.

The missing ACF field group is included

v1's PHP called get_field('geo_city_name') and five siblings but never shipped a field group defining them. On a clean install the schema block silently never rendered and every hero came out blank. The definition is now part of the export and is step one of the deployment order.

One address, many service areas

The schema still publishes a single verifiable postal address on all 14 pages and varies only areaServed, which now includes every named community as its own Place entity. Minting a fake street address per county is the fastest way to lose a Google Business Profile.

Form submissions reach the county inbox

v1 defined a per-county lead email in the CSV and then never used it. An elementor_pro/forms/new_record hook now routes each submission to the inbox for the page it came from, with the main office address on Bcc so nothing depends on one mailbox being watched.

Silo inventory

The 14 county pages this builds.

Slugs are stable identifiers — changing one after launch costs you the page's history unless you redirect it.

PageSlugAnchor cityCountyLead inbox
Boerne Roofing /boerne-roofing/ Boerne Kendall County boerne@a1hillcountry.com
Fredericksburg Roofing /fredericksburg-roofing/ Fredericksburg Gillespie County fredericksburg@a1hillcountry.com
Comal County Roofing /comal-county-roofing/ New Braunfels Comal County comal@a1hillcountry.com
Kerr County Roofing /kerr-county-roofing/ Kerrville Kerr County kerr@a1hillcountry.com
Hays County Roofing /hays-county-roofing/ Dripping Springs Hays County hays@a1hillcountry.com
Lake Travis Luxury Roofing /lake-travis-roofing/ Lakeway West Travis County laketravis@a1hillcountry.com
Burnet County Roofing /burnet-county-roofing/ Marble Falls Burnet County burnet@a1hillcountry.com
Blanco County Roofing /blanco-county-roofing/ Johnson City Blanco County blanco@a1hillcountry.com
Bandera County Roofing /bandera-county-roofing/ Bandera Bandera County bandera@a1hillcountry.com
Llano County Roofing /llano-county-roofing/ Kingsland Llano County llano@a1hillcountry.com
Medina County Roofing /medina-county-roofing/ Castroville Medina County medina@a1hillcountry.com
Real County Roofing /real-county-roofing/ Leakey Real County real@a1hillcountry.com
Mason County Roofing /mason-county-roofing/ Mason Mason County mason@a1hillcountry.com
West Williamson Roofing /williamson-west-roofing/ Liberty Hill West Williamson County williamson@a1hillcountry.com

The per-county email addresses are carried forward from the v1 export and have not been verified as live mailboxes. Confirm each one exists or forwards to a monitored inbox before publishing the pages — a county page that ranks and then drops the lead is worse than no page at all.

Honest caveat

A template cannot make a page worth ranking.

What is above is scaffolding: correct schema, correct contact data, a palette that matches, and a form that routes. What it does not contain is local substance, and that is the part that decides whether these pages rank or get filtered. Each county needs at least one paragraph that could only have been written by someone who has worked there — the HOA that demands ARC submittals before a color change, the county where a re-roof triggers a permit, the subdivision plumbed for rainwater catchment where a Kynar finish stops being a preference and becomes a requirement. That work is manual and there is no shortcut for it.

Questions

About this export.

Why does a roofing site ship WordPress source code?

Because A1 already runs a WordPress county-silo build, and the v2.0 rebuild would otherwise leave it stranded on stale contact data and a palette that no longer matches. This page regenerates those artifacts against the current business facts so both properties agree on the phone number, the address, and the visual system.

Is a 14-page county silo still a good SEO strategy?

Only if each page earns its existence. Location pages work when they contain information that is genuinely specific to that place — the HOA that requires ARC submittals, the county that treats a re-roof as a permit trigger, the subdivision on a rainwater catchment system. Fourteen pages generated from one template with the county name swapped are doorway pages, and Google has both a policy and a classifier for those. The template here gives you the frame; the local substance is manual work nobody can automate for you.

Why not publish a separate address for each county?

Because it is not true, and because it is detectable. Google verifies addresses against postal records and business registrations, and a listing at an address without a staffed presence is grounds for suspension of the profile — which costs far more traffic than the local page ever earned. The honest structure is one real office plus explicit service areas, which is exactly what this schema emits.

Does the schema here include a star rating?

No, deliberately. Self-serving aggregateRating markup on your own site — rather than ratings collected and displayed as first-party review content — is a documented manual-action risk. Add it only once real reviews exist on a page that genuinely displays them.

What still has to be replaced before this goes live?

The founding year and RCAT license number that appear in site copy as bracketed placeholders, the per-county email inboxes (they must exist or forward somewhere real), and the logo path in the schema image field. Nothing in this export invents a credential on A1's behalf.

Code is provided as-is for A1 Hill Country's own deployment. Test on a staging site before touching production, and take a database backup before running any import. Plugin names are referenced for compatibility only and imply no affiliation or endorsement.

Get a real number before anyone climbs on your roof.

Satellite measurement, transparent price band, no obligation — then a written itemized scope.

Instant Quote Call Now