# Elementor Landing Page

> Build SEO landing pages for WordPress + Hello Elementor + Elementor that are pasted in from the WP admin (no FTP). Produces a scoped CSS file plus copy-paste-ready files with <style> tags. Use when creating or editing a WordPress/Elementor landing page, a "paste into Elementor" template, an HTML widget section, or Custom Code / Additional CSS for a client site.

- Skill: `zainsaeed615/elementor-landing-page` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add zainsaeed615/elementor-landing-page`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zainsaeed615/elementor-landing-page/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: zainsaeed615 (https://skillmd.com/u/zainsaeed615)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/zainsaeed615/elementor-landing-page

---


# WordPress + Elementor Landing Page Builder

Build modern, SEO-focused landing pages that the user pastes into WordPress
admin. The user has **no FTP/hosting access** — everything must be pasteable
from the Elementor editor (HTML widget + Custom Code) or Customizer (Additional
CSS).

## Golden rules (these caused real breakage before)

1. **`<style>` tags are mandatory** in any file pasted into an Elementor **HTML
   widget** or **Custom Code** box. Raw CSS pasted there renders as visible text
   and breaks the page.
2. **Raw CSS only** (no `<style>`) goes into **Appearance → Customize → Additional
   CSS** or Elementor **Advanced → Custom CSS**. Style tags there break it.
3. **Font `@import` must NOT be inside `<style>`** for paste files — use a
   `<link rel="stylesheet">` above the `<style>` block instead. Keep `@import`
   only in the raw `.css` source.
4. **Scope everything to `.slr-landing`** (or the project's wrapper id/class) and
   use `!important` on every rule to beat theme/Elementor styles.
5. **Never restyle the global header/footer.** The site already has Elementor
   Theme Builder header/footer. Only reset the page content wrapper
   (`main#content` / the landing HTML widget), never `.e-con`, `.elementor-section`,
   or `.elementor-location-header/footer` globally.
6. **No full-bleed `100vw` breakout** — it misaligns content with the global
   header/footer container. Keep content in a `.slr-container` (max-width ~1200px).

## Deliverables to produce

For each landing page, create these files in the project's templates folder:

| File | Purpose | Has `<style>`? |
|------|---------|----------------|
| `<slug>.css` | Source CSS, scoped, `@import` at top | No (raw) |
| `COPY-into-elementor-custom-code.html` | Paste whole file into Elementor **Custom Code → Head** | Yes |
| `<slug>-html-only.html` | One HTML widget: `<style>` + markup together | Yes |

The user copies one finished file and replaces — do not make them hand-edit.

## Workflow

```
- [ ] 1. Confirm slug, wrapper id (e.g. #slr-landing), keyword, location, brand colors
- [ ] 2. Write scoped <slug>.css (see structure below)
- [ ] 3. Write semantic HTML using <main id="..." class="..."> + .slr-container
- [ ] 4. Generate paste files with the script (style tags + <link> for font)
- [ ] 5. Give Elementor setup steps + "clear cache" reminder
```

### Step 2 — CSS structure

- Top: `@import url('...Inter...')` (raw file only).
- Reset: `.slr-landing *, ::before, ::after { box-sizing: border-box !important; }`
- Hide duplicate theme title: `body:has(#WRAPPER) .page-header, .entry-header, h1.entry-title { display:none !important; }`
- CSS variables on `.slr-landing` (colors, radius, shadow, `--slr-max: 1200px`).
- Content container `.slr-container { max-width: var(--slr-max) !important; margin: auto !important; padding: 0 24px !important; }`
- Layout reset scoped to content only:

```css
body:has(#WRAPPER) main#content.site-main,
body:has(#WRAPPER) main#content .page-content,
body:has(#WRAPPER) #content,
body:has(#WRAPPER) .site-content {
  padding: 0 !important; margin: 0 !important; max-width: 100% !important;
}
body:has(#WRAPPER) main#content .elementor-widget-html .elementor-widget-container,
body:has(#WRAPPER) main#content .e-con-inner:has(#WRAPPER) {
  padding: 0 !important; max-width: 100% !important;
}
```

- Responsive breakpoints: `1024px`, `768px`, `480px`.
- FAQ: use native `<details>/<summary>` (no JS).
- Gravity Forms: target `.slr-form-wrap .gform_wrapper`, inputs, `.gform_button`.

### Step 3 — HTML rules

- Root: `<main id="WRAPPER" class="WRAPPER" itemscope itemtype="https://schema.org/LocalBusiness">`.
- Every section wraps inner content in `<div class="slr-container">`.
- One `<h1>` only (in hero). Use real image URLs from the WP media library.
- Embed the form via shortcode inside the HTML: `[gravityform id="1" title="true"]`.
  If a widget strips shortcodes, fall back to a separate Elementor **Shortcode** widget.

### Step 4 — Generate paste files

Run the generator to wrap the raw CSS correctly (style tags + font link, no
`@import` inside `<style>`):

```bash
bash <skill_dir>/scripts/make-paste-files.sh <slug>.css <slug>-html-only.html
```

It writes `COPY-into-elementor-custom-code.html` (CSS only) and, if a
`<main ...>` HTML file is given, a combined `*-html-only.html`. See
[scripts/make-paste-files.sh](scripts/make-paste-files.sh).

If you prefer to do it by hand, the paste file must look exactly like:

```html
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" />

<style id="slr-landing-styles">
/* all CSS, all !important, no @import here */
</style>
```

## Elementor setup steps (give these to the user every time)

1. Edit page → Page Layout: **Default** (not Canvas/Elementor Full Width).
2. Page Settings → **Hide Title: Yes**.
3. Add a Section: **Full Width**, content width Full, padding 0.
4. Paste content:
   - **Option A (simplest):** paste `*-html-only.html` into one **HTML widget**.
   - **Option B:** paste `COPY-into-elementor-custom-code.html` into Elementor
     **Custom Code → Head** (this page only), and the markup into an HTML widget.
5. Save → **clear LiteSpeed / page cache** before checking the live page.

## Match file to field (pasting in the wrong field is the #1 break cause)

| Elementor field | Use file | Format |
|-----------------|----------|--------|
| Custom Code box / HTML widget | `COPY-into-elementor-custom-code.html` or `*-html-only.html` | with `<style>` |
| Advanced → Custom CSS / Customizer → Additional CSS | `<slug>.css` | raw, no `<style>` |

## CSS delivery format (also enforced by user rule)

When delivering CSS in chat, wrap it in `<style>` tags with a font `<link>` above
the block, all rules `!important`. Only give raw `.css` when the user explicitly
asks for an Additional-CSS-only file.

## Additional resources

- For the project conventions, colors, and a full section checklist, see
  [reference.md](reference.md).

