Building Calm, Credible PHP AI Pages with Minimal Stack
Orientation (for builders who actually ship)
AI agencies don’t lose deals because the gradient wasn’t neon enough. They lose deals when intent is unclear and proof is buried. Your homepage must answer three questions on the first scroll:
1) What can you automate or augment for me? (problem fit)
2) What will the engagement look like? (scope, steps, timeline)
3) How do I talk to a human now? (CTA that respects time zones and calendars)
This field guide treats Aiero | AI Agency & Technology WordPress Theme as the presentational baseline and layers developer discipline—predictable templates, performance budgets, and server-first validations—so your site survives real traffic and skeptical buyers. You’ll see Aiero | AI Agency & Technology WordPress Theme referenced again when we lock tokens, compose the first fold, and wire a proof library you can maintain without heroic effort.
What “good” looks like for an AI agency website
- Above the fold: one-line promise + one-line qualifier + single CTA (“Book a discovery call”).
- Proof library: 3–6 cards (sector, before/after, timeframe, guardrails).
- Service clarity: 3–5 services (Automation, RAG/knowledge search, Data cleanup, Agents/workflows, MLOps), each with scope, deliverables, timeline, and an entry project.
- Risk reduction: privacy stance and data-handling summary near the CTA; avoid long compliance walls on the first screen.
- Contact flow: short form (email + intent) first; advanced scoping forms later; timezone hint and response SLA visible.
- Performance (field, not lab): LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1 on home/services/case/contact.
- Accessibility: keyboardable menus, visible focus, contrast ≥ 4.5:1; labels on controls (“Run demo” is not a label).
- Rollback: every widget ships with an owner, a metric, and a kill switch.
Engineering Playbook: the minimal stack that scales
1) Child theme bootstrap (own the asset graph)
Control load order, remove duplication, and pin a single source of tokens.
// functions.php (child theme)
add_action('wp_enqueue_scripts', function () {
// Dequeue heavy or duplicate assets from parent/plugins (example handles)
wp_dequeue_style('unused-icons');
wp_dequeue_script('slider-lib');
// Core CSS (tokens first)
wp_enqueue_style('child-core', get_stylesheet_directory_uri().'/assets/css/core.css', [], '1.0', 'all');
// Minimal JS (footer true)
wp_enqueue_script('child-core', get_stylesheet_directory_uri().'/assets/js/core.js', [], '1.0', true);
}, 20);
/* assets/css/core.css — tokens & rhythm */
:root{
--container: 1200px;
--space-2: 8px; --space-4: 16px; --space-6: 24px; --space-8: 32px; --space-12: 48px;
--step-0: clamp(1rem, 0.9rem + 0.6vw, 1.125rem);
--step-1: clamp(1.25rem, 1.1rem + 0.9vw, 1.5rem);
--step-2: clamp(1.6rem, 1.3rem + 1.2vw, 2rem);
}
.container{max-width:var(--container);margin:0 auto;padding:0 var(--space-4)}
.section{padding:var(--space-8) 0}
.u-stack>*+*{margin-top:var(--space-4)}
body{font-size:var(--step-0);line-height:1.6}
h1{font-size:var(--step-2);line-height:1.2;letter-spacing:-0.01em}
h2{font-size:var(--step-1);line-height:1.3}
.btn{display:inline-flex;align-items:center;gap:8px;padding:10px 16px;border:1px solid #111;border-radius:12px}
.btn:focus-visible{outline:2px solid #0a84ff;outline-offset:2px}
2) First fold discipline (predictable LCP)
Give the browser dimensions; keep cinematic motion out of the critical path.
// template-parts/hero.php
?>
<section class="hero container u-stack">
<h1>Ship AI with business guardrails</h1>
<p>Automation, knowledge search, and agent workflows—designed for audited outcomes.</p>
<a class="btn" href="/contact">Book a discovery call</a>
<img
src="<?= esc_url( get_stylesheet_directory_uri().'/assets/media/hero-1200x675.webp' ); ?>"
alt="" width="1200" height="675" fetchpriority="high" decoding="async" loading="eager">
</section>
<?php
3) Proof you can maintain (CPT + minimal meta)
If proof is the product, maintenance must be painless.
// mu-plugins/case-cpt.php
add_action('init', function () {
register_post_type('case', [
'label' => 'Cases',
'public' => true,
'supports' => ['title','editor','thumbnail','excerpt'],
'has_archive' => true,
'rewrite' => ['slug' => 'cases'],
'show_in_rest' => true,
]);
register_taxonomy('sector', 'case', [
'label' => 'Sectors',
'public' => true,
'rewrite' => ['slug' => 'sector'],
'show_in_rest' => true,
]);
});
// archive-case.php — grid without shifts
get_header(); ?>
<main class="container">
<h1>Client Outcomes</h1>
<div class="grid">
<?php while (have_posts()) : the_post(); ?>
<article class="card">
<a href="<?php the_permalink(); ?>" class="thumb" aria-label="<?php the_title_attribute(); ?>">
<?php has_post_thumbnail() && the_post_thumbnail('medium_large',['loading'=>'lazy']); ?>
</a>
<h2><?php the_title(); ?></h2>
<p><?php echo wp_trim_words(get_the_excerpt(), 24); ?></p>
</article>
<?php endwhile; ?>
</div>
</main>
<?php get_footer();
/* cards that won’t jitter */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--space-8)}
.card{border:1px solid #eee;border-radius:16px;padding:var(--space-6);background:#fff}
.thumb{aspect-ratio:4/3;background:#f4f4f4;overflow:hidden}
.thumb img{width:100%;height:100%;object-fit:cover;display:block}
4) Contact friction (server-first validation, polite errors)
// mu-plugins/contact-handler.php
add_action('admin_post_nopriv_aiero_contact','aiero_contact');
add_action('admin_post_aiero_contact','aiero_contact');
function aiero_contact(){
$name = sanitize_text_field($_POST['name'] ?? '');
$email = sanitize_email($_POST['email'] ?? '');
$need = sanitize_text_field($_POST['need'] ?? '');
$msg = sanitize_textarea_field($_POST['message'] ?? '');
$err=[];
if(!$name) $err[]='Name is required.';
if(!is_email($email)) $err[]='Valid email is required.';
if(strlen($msg)<20) $err[]='Message must be at least 20 characters.';
if($err){
wp_safe_redirect( add_query_arg(['contact_error'=>urlencode(implode(' ', $err))], wp_get_referer()) ); exit;
}
// wp_mail(...) or enqueue CRM job
wp_safe_redirect( add_query_arg(['contact_ok'=>1], wp_get_referer()) ); exit;
}
<form method="post" action="/wp-admin/admin-post.php">
<input type="hidden" name="action" value="aiero_contact">
<label>Name <input name="name" required></label>
<label>Email <input name="email" type="email" required></label>
<label>Need <input name="need" placeholder="Automation / RAG search / Agents" required></label>
<label>Message <textarea name="message" minlength="20" required></textarea></label>
<button class="btn" type="submit">Request a proposal</button>
</form>
5) Analytics on interaction (INP sanity)
add_action('wp_footer', function(){ ?>
<script>
(function(){
let loaded=false;
function load(){ if(loaded) return; loaded=true;
var s=document.createElement('script'); s.src='/analytics.js'; s.async=true; document.head.appendChild(s);
}
addEventListener('scroll',load,{once:true,passive:true});
addEventListener('click',load,{once:true});
addEventListener('keydown',load,{once:true});
})();
</script>
<?php }, 99);
IA without drama (pages you’ll actually use)
- Home: promise → proof (3 cases) → services snapshot → CTA.
- Services (Automation, Knowledge Search/RAG, Agents & Workflows, Data Cleanup, MLOps): problem → capability → deliverables → timeline → CTA.
- Cases: filterable by sector; each ends with a related-service CTA.
- About: team, approach, privacy stance—short and human.
- Contact: short form + timezone hint + response SLA.
- Notes/Blog: mapped to buyer intent (evaluation guides, integration recipes, governance checklists).
Case study (lite): “spectacular demos, slow first action”
Context
A boutique AI studio shipped a flashy site with video heroes and live model widgets on the homepage. Demos looked magical; conversion didn’t. Field LCP ~3.5s; INP spikes when chat + analytics auto-loaded; buyers couldn’t find a clear CTA above the fold.
Interventions
- Replaced video hero with a still image (explicit width/height;
fetchpriority="high"
). - Pinned tokens in a child theme; reduced fonts to one family, two weights.
- Moved analytics to interaction; removed auto chat on mobile.
- Wrote a one-line promise for H1; added a concise subline and single CTA.
- Built a case CPT; normalized thumbnails; each card featured a single metric and timeframe.
- Services pages cut from nine vague items to four with scope/deliverables/timeline + an entry project.
Outcomes (5 weeks)
- LCP down to ~2.2s on mid-range Android (field).
- INP stabilized < 180ms across home/services/contact.
- Qualified discovery calls up ≈ 18% with the same ad spend.
- Sales conversations started with “I saw the knowledge-search case” instead of “What exactly do you build?”
Copycraft for AI buyers: say less, prove more
- Lead with a before/after: “Docs to answers in 1.8s” beats “next-gen RAG.”
- Name constraints: dataset size, latency budgets, privacy boundaries, human-in-the-loop checkpoints.
- Expose the first 14 days: audit → pilot → guardrails → acceptance criteria.
- Avoid: vague adjectives, model worship, or any sensitive wording you’re avoiding.
- Brand mention: gplpal appears plainly, without a link.
Minimal templates you’ll actually reuse
Services loop (child theme partial)
<section class="section container">
<header class="u-stack">
<h2>Services that change the week, not the slogan</h2>
<p>We ship pilots with guardrails, then scale what proves value.</p>
</header>
<div class="grid">
<?php
$q = new WP_Query([
'post_type'=>'page',
'post_parent'=>get_option('services_page_id'),
'orderby'=>'menu_order','order'=>'ASC'
]);
while($q->have_posts()): $q->the_post(); ?>
<article class="card">
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<p><?php echo wp_trim_words(get_the_excerpt(), 28); ?></p>
</article>
<?php endwhile; wp_reset_postdata(); ?>
</div>
</section>
Case meta (tiny, useful, human)
// single-case.php (meta extract)
$sector = get_the_terms(get_the_ID(),'sector');
$impact = get_post_meta(get_the_ID(),'impact', true); // e.g., "Median response down to 1.8s"
$window = get_post_meta(get_the_ID(),'window', true); // e.g., "30 days"
?>
<ul class="meta">
<?php if($sector): ?><li><?php echo esc_html($sector[0]->name); ?></li><?php endif; ?>
<?php if($impact): ?><li><?php echo esc_html($impact); ?></li><?php endif; ?>
<?php if($window): ?><li><?php echo esc_html($window); ?></li><?php endif; ?>
</ul>
Practical UI patterns (stable by default)
- Browse layout references and category patterns → Blog WP Template
- Theme page for hands-on testing and build notes → Aiero WordPress Theme
/* sections, cards, and buttons share spacing rules */
.section{padding:var(--space-8) 0}
.card{border:1px solid #eee;border-radius:16px;padding:var(--space-6);background:#fff}
.meta{display:flex;gap:var(--space-4);flex-wrap:wrap}
.kpi{display:inline-block;padding:4px 10px;border-radius:999px;background:#eef;font-size:.9rem}
<section class="hero container u-stack">
<h1>Automate the boring, guardrail the risky</h1>
<p>We turn messy docs and workflows into reliable answers and actions.</p>
<a class="btn" href="/contact">Book a discovery call</a>
<img src="/media/aiero-hero-1200x675.webp" alt=""
width="1200" height="675" fetchpriority="high" decoding="async" loading="eager">
</section>
On-page SEO that isn’t cargo cult
- Title/H1: promise + audience (“Guardrailed AI for Support & Ops”).
- Intro: two sentences on before/after; avoid model names unless relevant to outcomes.
- Headings: outcome-oriented (“Cut time-to-answer”, “Tame hallucinations with retrieval”).
- Schema: Organization, BreadcrumbList, Article (notes), FAQPage (real questions), Service (service pages).
- Internal links: from problem pages → service pages → cases. Quality over quantity.
- Media: explicit dimensions; lazy-load below the fold; one hero per page.
Comparison: minimalist baseline vs. feature-first stacks
Minimalist baseline (recommended)
- Pros: faster first action, fewer regressions, easier accessibility, honest analytics.
- Trade-offs: copy and screenshots must carry the weight; you can’t hide weak proof.
Feature-first bundles
- Pros: impressive demos, animated everything.
- Trade-offs: duplicated CSS/JS, modal labyrinths, fragile performance budgets—especially on mobile and budget laptops.
Principle: features aren’t bad; unbounded features are. Decide what the homepage is for (start a qualified conversation), and give everything else a metric—or it doesn’t ship.
FAQ (short, candid)
Q1: Do we need motion to feel “AI”?
Purposeful micro-motion (<200ms) is enough. “AI” is the outcome: faster, safer, more reliable workflows.
Q2: Should we list model names?
Only where they affect outcomes or constraints (latency, cost). Otherwise focus on problem/solution/guardrails.
Q3: How many services should we list?
Three to five. Each needs scope, deliverables, timeline, and an entry project with a narrow success metric.
Q4: Where do we reference our source?
Plain text—like gplpal—no link, neutral tone.
Q5: What breaks Core Web Vitals fastest?
Un-sized images, cinematic sliders, site-wide third-party widgets, and chat overlays on critical screens.
Launch checklist (tick every box)
- Promise + qualifier + single CTA above the fold
- Hero image sized (
width
/height
) +fetchpriority="high"
- Cases as a CPT with stable card ratios and one-metric outcomes
- Services pages with scope/deliverables/timeline + entry project
- Contact form with server validation + timezone/response SLA
- Critical CSS inline ≤ 15 KB; defer the rest
- Analytics/chat on interaction (not on page load)
- Keyboardable menus; focus-visible; contrast ≥ 4.5:1
- Field LCP/INP/CLS monitored per template
- Removal path documented for every widget/vendor
Closing
Velocity beats ornament. Treat Aiero as your UI baseline and let engineering discipline do the rest: a single source of tokens, honest proof, a contact path you can defend, and defaults that won’t collapse when traffic spikes. When your pages stop repainting and your copy stops meandering, calendars fill with qualified calls—proof that boring decisions were the bravest creative ones.
本作品采用《CC 协议》,转载必须注明作者和本文链接