# Post Block Widget

> Grid / tiled / overlay-style post showcase. Two skin templates (default, overlay) under `includes/Template/Post-Block/` driven by a `grid_style` control. Posts loop via Lite's shared query helpers.

**Class file:** `includes/Elements/Post_Block.php` (1,546 lines)
**Slug:** `post-block` (widget id `eael-post-block`)
**Public docs:** <https://essential-addons.com/elementor/docs/post-block/>
**Pro-shared:** Pro-only. Reuses Lite's `Helper::get_query_args`, `Helper::get_dynamic_args`, load-more JS, post-grid CSS.

## Overview

Renders a WordPress post loop in a configurable grid. Two visual templates: `default` (image + title + meta + excerpt + read-more, stacked) and `overlay` (image background with text overlay). Two layout modes: `post-block-layout-block` (uniform grid) and `post-block-layout-tiled` (Pinterest-style sized blocks — requires specific post-per-page counts for the layout to balance). Pagination via numbered links or AJAX load-more (Lite-owned handler).

## Pro vs Lite

Pro-only. Heavy reuse of Lite — class composes `Essential_Addons_Elementor\Traits\Helper`, calls `HelperClass::fix_old_query`, `HelperClass::get_query_args`, `HelperClass::get_dynamic_args`. Lite owns the AJAX load-more handler.

## File Map

| File | Role |
| --- | --- |
| `includes/Elements/Post_Block.php` | Widget class — controls + render dispatch |
| `includes/Template/Post-Block/default.php` | Default template (stacked card) |
| `includes/Template/Post-Block/overlay.php` | Overlay template (image bg + text overlay) |
| `src/css/view/post-block.scss` → `assets/front-end/css/view/post-block.min.css` | Card styling |
| `src/css/view/post-block-overlay.scss` → `assets/front-end/css/view/post-block-overlay.min.css` | Overlay-specific styling |
| `EAEL_PLUGIN_PATH/assets/front-end/css/view/load-more.min.css` | Lite — pagination button |
| `EAEL_PLUGIN_PATH/assets/front-end/css/view/post-grid.min.css` | Lite — base post grid (shared with Lite Post_Grid widget) |
| `EAEL_PLUGIN_PATH/assets/front-end/js/view/load-more.min.js` | Lite — AJAX load-more handler |
| `config.php` entry `'post-block'` | 4 CSS + Lite JS (mixed Lite + Pro paths) |

## Architecture

- **Lite helper composition** — `use Essential_Addons_Elementor\Traits\Helper;` (line 17). `HelperClass::fix_old_query`, `get_query_args`, `get_dynamic_args` build `WP_Query` args. See [`_patterns.md § Helper imports`](_patterns.md#helper-imports).
- **Template dispatcher** — `render()` line 1505: maps `grid_style` value (`post-block-style-default` / `post-block-style-overlay`) to template name (`default` / `overlay`) and includes the matching PHP file from `includes/Template/Post-Block/`. `$this->get_template($template_name)` resolves the path.
- **Tiled layout requires N posts** — `post-block-layout-tiled` only renders correctly when `posts_per_page` matches the tile pattern (3, 4, or 5). The widget shows admin notices to guide the user but doesn't auto-enforce.
- **`fix_old_query`** — legacy query-format normalizer from Lite. Migrates pre-3.x widget settings to the current query-args shape. Always called first in `render()`.
- **Load-more uses Lite's CSS + JS** — pagination CSS via `EAEL_PLUGIN_PATH/load-more.min.css`, AJAX handler in Lite's `Ajax_Handler` trait. Pro doesn't own this surface.
- **FA4 → FA5 migration shim** for `eael_post_block_bg_hover_icon` (line 1473) — checks `__fa4_migrated` flag and falls back to the new icons-control value when present.

## Render Output (default template)

```html
<div id="eael-post-block-{element-id}" class="eael-post-block {grid_style} {layout_class}">
  <div class="eael-post-block-grid eael-post-appender eael-post-appender-{element-id} {tiled_preset} {tiled_column}">
    <!-- One block per post -->
    <article class="eael-grid-post">
      <div class="eael-grid-post-holder">
        <div class="eael-entry-media">
          <a href="{permalink}" {target} {nofollow}>
            <img src="{thumbnail}" alt="{title}" />
          </a>
        </div>
        <div class="eael-entry-wrapper">
          [?] <div class="eael-entry-meta">
            <span class="eael-author">By {author}</span>
            <span class="eael-date">{date}</span>
          </div>
          <h2 class="eael-entry-title">
            <a href="{permalink}">{title}</a>
          </h2>
          [?] <div class="eael-grid-post-excerpt">{excerpt}{expansion_indicator}</div>
          [?] <a class="eael-post-block-bg-hover-bg" href="{permalink}">
            <i class="{hover_icon}"></i>
          </a>
          [?] <a class="eael-post-elements-readmore-btn" href="{permalink}">Read More</a>
        </div>
      </div>
    </article>
  </div>
  [?] <a class="eael-load-more-button">Load More</a>
</div>
```

## Controls Reference

| Control id | Tab → Section | Type | Purpose |
| --- | --- | --- | --- |
| `grid_style` | Content → Layout | SELECT | `post-block-style-default` / `post-block-style-overlay` (template selector) |
| `eael_post_block_layout` | Content → Layout | CHOOSE | `post-block-layout-block` / `post-block-layout-tiled` |
| `eael_post_tiled_preset` | Content → Layout | SELECT | Tiled preset (visible when layout = tiled) |
| `eael_post_tiled_column` | Content → Layout | SELECT | Tiled column count |
| Post query (post_type, taxonomy, terms, etc.) | Content → Query | various | Standard Lite query controls |
| `posts_per_page` | Content → Query | NUMBER | Per-page count |
| `post_offset` | Content → Query | NUMBER | Skip-N offset |
| Load-more toggle | Content → Layout | SWITCHER | Enable AJAX pagination |
| Image link, title link, read-more link target / nofollow | Content → Links | various | Per-element link options |
| `eael_post_block_hover_animation` | Content → Layout | SELECT | Hover effect (zoom, fade, slide, etc.) |
| `eael_post_block_bg_hover_icon` / `_new` | Content → Layout | ICONS | Hover overlay icon (with FA4 shim) |
| `eael_show_read_more_button` | Content → Layout | SWITCHER | Read-more visibility |
| `excerpt_expanison_indicator` | Content → Excerpt | TEXT | "..." replacement |

## Conditional Dependencies

```text
grid_style = 'post-block-style-overlay'
  └── uses overlay template; overlay CSS active

eael_post_block_layout = 'post-block-layout-tiled'
  └── shows tiled_preset + tiled_column
  └── shows "use N posts per page" admin notice

load_more = 'yes'
  └── shows load-more pagination
```

## JavaScript Lifecycle

No widget-specific JS in `src/js/view/`. Load-more uses **Lite's** `load-more.min.js` enqueued from `EAEL_PLUGIN_PATH`. Lite's handler attaches to `.eael-load-more-button`, sends AJAX to `wp_ajax_*_eael_load_more`, appends returned HTML.

Cold-load + AJAX append both rely on the same template files — Lite re-includes `includes/Template/Post-Block/{template}.php` server-side in the load-more response.

## Hooks & Filters

Standard widget render. Load-more flow goes through Lite's hooks; Pro doesn't emit anything custom.

## Common Issues

| Symptom | Likely cause | Diagnose | Fix |
| --- | --- | --- | --- |
| Tiled layout looks broken | `posts_per_page` ≠ tile pattern (3/4/5) | Check `posts_per_page` value | Match per-page count to admin notice for selected preset |
| Load-more 404s | Lite AJAX handler not registered | Verify Lite is active and version compatible | Confirm Lite > 4.6.3; reactivate Lite if AJAX endpoint missing |
| FA4 hover icon missing glyph | Legacy icon class persisted from older Lite | Inspect `__fa4_migrated` flag in saved settings | Re-pick icon via FA5 ICONS control; widget falls back automatically |
| Excerpt empty on some posts | Post has no excerpt + content too short for auto-excerpt | Check `wp_trim_excerpt` output | Set explicit excerpt on the post, or adjust trim length |
| Overlay text unreadable | Image too light, no overlay gradient | Inspect computed CSS on `.eael-post-block-bg-hover-bg` | Add gradient overlay via Pro style controls |
| Pagination breaks after Pro version bump | Asset cache stale | Check `EAEL_ASSET_PATH` mtime | Trigger Pro's `Migration::plugin_upgrade_hook` (already wired) or manually clear cache |

## Known Limitations

- **Tiled layout has fixed presets** — only 3/4/5-post patterns supported; custom counts produce gaps
- **Load-more is Lite-owned** — debugging requires editing Lite, not Pro
- **No custom template loader hook** — adding a 3rd skin requires editing the `render()` switch and adding a new PHP file under `includes/Template/Post-Block/`
- **`fix_old_query` is Lite-coupled** — if Lite removes the helper, this widget breaks. See `/pro-lite-sync`
- **`excerpt_expanison_indicator` typo in id** — preserved (user data)
- **`post-block-bg-hover-icon_new` FA4 shim** — extra branch in render; flag for cleanup once FA4 migration is complete site-wide

## Cross-References

- Architecture: [`docs/architecture/pro-lite-bridge.md`](../architecture/pro-lite-bridge.md) — Lite helper reuse
- Shared patterns: [`_patterns.md`](_patterns.md)
- Skill: [`/pro-lite-sync`](../../.claude/skills/pro-lite-sync/SKILL.md)
