diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f52a09..ab870a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to the Nynaeve theme will be documented in this file. For project-wide changes (infrastructure, tooling, cross-cutting concerns), see the [project root CHANGELOG.md](../../../../../CHANGELOG.md). +## [2.0.14] - 2025-11-24 + +### Added +- **Speed Optimization: Async CSS Loading** ([filters.php:77-110](app/filters.php#L77-L110)) + - Makes non-critical stylesheets non-render-blocking using `media='print' onload` technique + - Applies to classic WooCommerce styles, WooCommerce Blocks styles, and Slick carousel CSS + - **Impact**: Unblocks render on pages that use these styles + - Browser loads CSS without blocking first paint, then swaps to `media='all'` on load + +### Documentation +- Created `docs/nynaeve/SPEED-TWEAKS.md` - Comprehensive speed optimization guide with 6 optimization strategies + ## [2.0.13] - 2025-11-24 ### Removed diff --git a/app/filters.php b/app/filters.php index 83254f0..b2bef2a 100644 --- a/app/filters.php +++ b/app/filters.php @@ -73,3 +73,38 @@ function my_acf_json_save_point($path) * @return string Empty string to remove the legend */ add_filter('gform_required_legend', '__return_empty_string'); + +/** + * Make non-critical stylesheets non-render-blocking + * Uses the "print media" technique to load CSS asynchronously + * + * @param string $html The link tag HTML + * @param string $handle The stylesheet handle + * @return string Modified HTML + */ +add_filter('style_loader_tag', function ($html, $handle) { + // List of non-critical stylesheets to load asynchronously + $async_styles = [ + // Classic WooCommerce styles + 'woocommerce-layout', + 'woocommerce-smallscreen', + 'woocommerce-general', + 'wc-brands-styles', + // WooCommerce Blocks styles + 'wc-blocks-style', + 'wc-blocks-vendors-style', + // Other + 'slick-carousel', + ]; + + if (in_array($handle, $async_styles, true)) { + // Change media to print, swap to all on load + $html = str_replace( + "media='all'", + "media='print' onload=\"this.media='all'\"", + $html + ); + } + + return $html; +}, 10, 2); diff --git a/app/setup.php b/app/setup.php index 05f53e7..1643be2 100644 --- a/app/setup.php +++ b/app/setup.php @@ -204,6 +204,7 @@ */ if (class_exists('WooCommerce')) { // Theme support calls moved to 'after_setup_theme' hook above + // Note: WooCommerce CSS is made non-render-blocking via async loading in filters.php /** * Get WooCommerce mode from theme options diff --git a/docs/ACF-BLOCKS.md b/docs/ACF-BLOCKS.md deleted file mode 100644 index 41792b8..0000000 --- a/docs/ACF-BLOCKS.md +++ /dev/null @@ -1,527 +0,0 @@ -# ACF Composer Blocks Guide - -This guide covers creating and managing ACF Composer blocks in the Nynaeve theme. - -## Table of Contents - -- [When to Use ACF Composer Blocks](#when-to-use-acf-composer-blocks) -- [Creating ACF Blocks](#creating-acf-blocks) -- [Block Structure](#block-structure) -- [Field Definitions](#field-definitions) -- [Default Content Strategy](#default-content-strategy) -- [Blade Templates](#blade-templates) -- [Styling ACF Blocks](#styling-acf-blocks) -- [Troubleshooting](#troubleshooting) - -## When to Use ACF Composer Blocks - -ACF Composer blocks should only be used in **special cases** when InnerBlocks or Sage Native blocks won't work. - -**Use ACF Composer blocks when:** -- Need complex custom field types (repeaters, relationships, post queries) -- Server-side rendering is critical for performance -- Editing must be rigid/controlled (strict brand guidelines) -- Need to change visual order via CSS without changing DOM order (flexbox/grid reordering) -- Prefer PHP/Blade templating over React - -**Avoid ACF Composer blocks for:** -- Content blocks where users need flexibility (use InnerBlocks instead) -- Blocks where typography should be user-controlled (use InnerBlocks instead) -- Simple image/heading/text/button combinations (use InnerBlocks instead) - -## Creating ACF Blocks - -### Command - -All `wp acorn` commands must be run from the Trellis VM: - -```bash -# From Trellis VM -cd trellis -trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn acf:block MyBlock - -# OR from interactive VM shell -trellis vm shell -cd /srv/www/imagewize.com/current/web/app/themes/nynaeve -wp acorn acf:block MyBlock -``` - -### Files Created - -The command creates two files: - -1. **Block Controller** - `app/Blocks/MyBlock.php` - - Block registration and settings - - ACF field definitions - - Data processing in `with()` method - -2. **Blade Template** - `resources/views/blocks/my-block.blade.php` - - HTML/Blade markup - - Receives data from `with()` method - -## Block Structure - -### Block Controller Example - -```php - ['wide', 'full'], - 'anchor' => true, - 'mode' => 'preview', - 'jsx' => true, - ]; - - /** - * Data to be passed to the block before rendering. - */ - public function with(): array - { - $image = get_field('image') ?: []; - $heading = get_field('heading') ?: ''; - $description = get_field('description') ?: ''; - $button = get_field('button') ?: []; - - // IMPORTANT: Provide default content for both frontend and backend - // This allows quick testing and gives clients working placeholder content - if (empty($heading)) { - $heading = 'Default Heading'; - } - - if (empty($description)) { - $description = 'Default description text that appears on both frontend and backend.'; - } - - // Process image - $image_url = is_array($image) ? ($image['url'] ?? null) : null; - $image_alt = is_array($image) ? ($image['alt'] ?? '') : ''; - - // Default image if not set - if (empty($image_url)) { - $image_url = Vite::asset('resources/images/placeholder.jpg'); - $image_alt = 'Placeholder image'; - } - - // Process button link - $button_url = is_array($button) ? ($button['url'] ?? '#') : '#'; - $button_text = is_array($button) ? ($button['title'] ?? 'Learn More') : 'Learn More'; - $button_target = is_array($button) ? ($button['target'] ?? '_self') : '_self'; - - return [ - 'image_url' => $image_url, - 'image_alt' => $image_alt, - 'heading' => $heading, - 'description' => $description, - 'button_url' => $button_url, - 'button_text' => $button_text, - 'button_target' => $button_target, - ]; - } - - /** - * The block field group. - */ - public function fields(): array - { - $fields = FieldsBuilder::make('my_block'); - - $fields - ->addImage('image', [ - 'label' => 'Image', - 'return_format' => 'array', - 'preview_size' => 'medium', - ]) - ->addText('heading', [ - 'label' => 'Heading', - 'required' => 0, - ]) - ->addTextarea('description', [ - 'label' => 'Description', - 'rows' => 4, - 'required' => 0, - ]) - ->addLink('button', [ - 'label' => 'Button Link', - 'return_format' => 'array', - 'required' => 0, - ]); - - return $fields->build(); - } - - /** - * Assets enqueued when rendering the block. - */ - public function assets(array $block): void - { - // Enqueue block-specific styles - // wp_enqueue_style('my-block', get_stylesheet_directory_uri() . '/resources/css/blocks/my-block.css'); - } -} -``` - -## Field Definitions - -### Common Field Types - -ACF Composer uses [ACF Builder](https://github.com/StoutLogic/acf-builder) for field definitions. - -**Image Field:** -```php -->addImage('image', [ - 'label' => 'Image', - 'return_format' => 'array', // Returns array with url, alt, etc. - 'preview_size' => 'medium', -]) -``` - -**Text Field:** -```php -->addText('heading', [ - 'label' => 'Heading', - 'required' => 0, - 'maxlength' => 100, -]) -``` - -**Textarea:** -```php -->addTextarea('description', [ - 'label' => 'Description', - 'rows' => 4, - 'required' => 0, -]) -``` - -**Link Field:** -```php -->addLink('button', [ - 'label' => 'Button Link', - 'return_format' => 'array', // Returns url, title, target - 'required' => 0, -]) -``` - -**Repeater Field:** -```php -->addRepeater('items', [ - 'label' => 'Items', - 'min' => 1, - 'max' => 5, - 'layout' => 'block', - 'button_label' => 'Add Item', -]) - ->addText('item_title', [ - 'label' => 'Title', - ]) - ->addTextarea('item_description', [ - 'label' => 'Description', - ]) -->endRepeater() -``` - -**Post Object (Relationship):** -```php -->addPostObject('related_post', [ - 'label' => 'Related Post', - 'post_type' => ['post'], - 'return_format' => 'object', - 'multiple' => 0, -]) -``` - -## Default Content Strategy - -**IMPORTANT:** Always provide default content that loads on both frontend and backend. - -### Why Default Content Matters - -1. **Immediate Testing**: Block renders correctly on published pages without manual content entry -2. **User Experience**: Users see working examples before customizing -3. **Development Speed**: No need to add content just to see layout/styles -4. **Quality Assurance**: Catches rendering issues during development - -### Implementation - -**❌ Don't restrict defaults to preview mode only:** -```php -public function with(): array -{ - $is_preview = $block['is_preview'] ?? false; - - // ❌ WRONG - Only shows default in editor - $heading = get_field('heading') ?: ($is_preview ? 'Default Heading' : ''); - - return ['heading' => $heading]; -} -``` - -**✅ Provide defaults for both frontend and backend:** -```php -public function with(): array -{ - $heading = get_field('heading') ?: 'Default Heading'; // ✅ Works everywhere - $image = get_field('image') ?: []; - - // Provide default image - if (empty($image)) { - $image_url = Vite::asset('resources/images/placeholder.jpg'); - $image_alt = 'Placeholder image'; - } else { - $image_url = $image['url']; - $image_alt = $image['alt'] ?? ''; - } - - return [ - 'heading' => $heading, - 'image_url' => $image_url, - 'image_alt' => $image_alt, - ]; -} -``` - -## Blade Templates - -### Template Structure - -Blade templates receive data from the `with()` method. - -**Basic Template Example:** -```blade -
-
- @if($image_url) - {{ $image_alt }} - @endif - - @if($heading) -

{{ $heading }}

- @endif - - @if($description) -

{{ $description }}

- @endif - - @if($button_url) - - {{ $button_text }} - - @endif -
-
-``` - -### Using Repeater Fields - -```php -// In with() method -$items = get_field('items') ?: []; - -if (empty($items)) { - $items = [ - ['item_title' => 'Item 1', 'item_description' => 'Description 1'], - ['item_title' => 'Item 2', 'item_description' => 'Description 2'], - ]; -} - -return ['items' => $items]; -``` - -```blade -{{-- In Blade template --}} -@if(!empty($items)) -
- @foreach($items as $item) -
-

{{ $item['item_title'] }}

-

{{ $item['item_description'] }}

-
- @endforeach -
-@endif -``` - -## Styling ACF Blocks - -### CSS Organization - -Create block-specific CSS files in `resources/css/blocks/`: - -``` -resources/css/blocks/ -├── my-block.css -├── another-block.css -└── ... -``` - -### Enqueuing Styles - -**Option 1: In Block's `assets()` method** -```php -public function assets(array $block): void -{ - wp_enqueue_style( - 'my-block', - get_stylesheet_directory_uri() . '/resources/css/blocks/my-block.css' - ); -} -``` - -**Option 2: Import in `resources/css/app.css`** -```css -@import 'blocks/my-block.css'; -``` - -### Block CSS Structure - -Follow BEM naming convention: - -```css -.wp-block-imagewize-my-block { - padding: 5rem 0; /* Vertical only - no horizontal padding */ -} - -.my-block__container { - max-width: var(--wp--style--global--content-size, 55rem); - margin: 0 auto; -} - -.my-block__image { - width: 100%; - height: auto; -} - -.my-block__heading { - font-size: 2rem; - margin-bottom: 1rem; -} - -.my-block__description { - color: var(--wp--preset--color--main-accent); - margin-bottom: 2rem; -} - -.my-block__button { - display: inline-block; - padding: 0.75rem 1.5rem; - background-color: var(--wp--preset--color--primary); - color: white; - text-decoration: none; - border-radius: 0.25rem; -} - -/* Responsive */ -@media (max-width: 782px) { - .my-block__heading { - font-size: 1.5rem; - } -} -``` - -## Troubleshooting - -### Block Not Appearing in Editor - -1. **Clear ACF cache:** - ```bash - cd trellis - trellis vm shell - cd /srv/www/imagewize.com/current/web/app/themes/nynaeve - wp acorn acf:clear - ``` - -2. **Re-cache ACF fields:** - ```bash - wp acorn acf:cache - ``` - -3. **Check block registration:** - - Verify block file exists in `app/Blocks/` - - Ensure block extends `Log1x\AcfComposer\Block` - - Check category is `'imagewize'` - -### Fields Not Showing in Editor - -1. **Check field builder syntax:** - - Ensure `FieldsBuilder::make()` uses unique name - - Verify `->build()` is called at the end - - Check for syntax errors in field definitions - -2. **Clear WordPress transients:** - ```bash - wp transient delete --all - ``` - -### Content Not Displaying - -1. **Check `with()` method:** - - Verify `get_field()` uses correct field names - - Ensure defaults are provided - - Check return array structure - -2. **Check Blade template:** - - Verify variable names match `with()` return array - - Check for typos in variable names - - Ensure proper Blade syntax - -### Styles Not Loading - -1. **Check CSS file path:** - - Verify file exists in `resources/css/blocks/` - - Check import statement in `app.css` - - Ensure file is included in Vite build - -2. **Rebuild assets:** - ```bash - cd site/web/app/themes/nynaeve - npm run build - ``` - -## Additional Resources - -- [ACF Composer Documentation](https://github.com/Log1x/acf-composer) -- [ACF Builder Documentation](https://github.com/StoutLogic/acf-builder) -- [ACF Field Types Reference](https://www.advancedcustomfields.com/resources/) -- [Pattern to ACF Block Guide](PATTERN-TO-ACF-BLOCK.md) diff --git a/docs/BLOCK-PLUGINS-INTEGRATION.md b/docs/BLOCK-PLUGINS-INTEGRATION.md deleted file mode 100644 index 3e4b33e..0000000 --- a/docs/BLOCK-PLUGINS-INTEGRATION.md +++ /dev/null @@ -1,289 +0,0 @@ -# Block Plugins Integration Plan - -## Overview - -Convert standalone block plugins from Composer packages to native Sage blocks within the Nynaeve theme. - -**Current State:** -- Blocks loaded as separate Composer packages in `site/composer.json` -- Maintained as independent plugins -- Versioned and managed separately - -**Target State:** -- Blocks integrated directly into theme using `imagewize/sage-native-block` -- Managed within theme codebase -- Simplified dependency chain - -## Affected Blocks - -1. `imagewize/carousel-block` (^1.0.0) - Created with `@wordpress/create-block`, no ACF fields -2. `imagewize/reviews-block` (^1.1.0) - Created with `@wordpress/create-block`, no ACF fields -3. `imagewize/about-block` (^1.0.0) - Created with `@wordpress/create-block`, no ACF fields -4. `imagewize/services-block` (^1.0.0) -5. `imagewize/cta-block` (^1.0.0) - Created with `@wordpress/create-block`, no ACF fields - -**Note:** Most blocks were created with `@wordpress/create-block` and use native WordPress block attributes instead of ACF fields. These are JavaScript/React-based blocks. - -## Migration Strategy - -### Phase 1: Analysis & Preparation - -1. **Audit existing plugin blocks** - - Clone/download each plugin repository - - Document block features, attributes, and dependencies - - **Note:** Most blocks use native WordPress block attributes (created with `@wordpress/create-block`), not ACF fields - - Review custom styles and scripts - - Note any external dependencies (libraries, APIs) - - Check `block.json` for attribute definitions - -2. **Create migration checklist** - - List all block attributes and their types from `block.json` - - Document any ACF field groups and fields (if applicable) - - Identify custom CSS/JS assets - - Note any PHP block logic - - Check for block variations or patterns - - Review React/JSX component structure - -### Phase 2: Create Sage Native Blocks - -For each block: - -1. **Generate block scaffold** - ```bash - # From Trellis VM - cd trellis - trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn sage-native-block:create imagewize/[block-name] - ``` - -2. **Migrate block attributes/fields** - - **For native WordPress blocks:** Copy attribute definitions from plugin's `block.json` to new Sage block's `block.json` - - **For ACF blocks (if any):** Copy ACF field definitions to new block's `acf-block.json` - - Verify field/attribute keys are unique - - Update field group location rules if needed - -3. **Port block logic** - - **For JavaScript blocks:** Copy React/JSX components to block's JS entry point - - **For PHP blocks:** Copy rendering logic to `block.php` - - Migrate JavaScript functionality (edit.js, save.js, or view.js) - - Transfer styles to block's CSS file - - Update asset enqueuing if needed - - Ensure `block.json` configuration matches original functionality - -4. **Test block functionality** - - Verify all features work as expected - - Test in block editor - - Validate frontend rendering - - Check responsive behavior - -### Phase 3: Content Migration - -**IMPORTANT:** If block names remain identical during migration (recommended), no database migration is needed! - -1. **Backup database** - - Create full database backup before migration as a safety precaution - - **From Trellis VM** (NOT Vagrant - we use Trellis VM): - ```bash - # Create gzipped database backup (one-line command) - cd trellis - trellis vm shell --workdir /srv/www/imagewize.com/current -- bash -c "mkdir -p database_backup && BACKUP_FILE=\"database_backup/pre-block-migration-\$(date +%Y%m%d_%H%M%S).sql\" && wp db export \${BACKUP_FILE} --add-drop-table && gzip \${BACKUP_FILE} && ls -lh \${BACKUP_FILE}.gz" - - # OR from interactive VM shell - cd trellis - trellis vm shell - cd /srv/www/imagewize.com/current - mkdir -p database_backup - BACKUP_FILE="database_backup/pre-block-migration-$(date +%Y%m%d_%H%M%S).sql" - wp db export ${BACKUP_FILE} --add-drop-table - gzip ${BACKUP_FILE} - ls -lh ${BACKUP_FILE}.gz - ``` - - **Note:** Database files use `.gz` compression (single file). Directory backups use `.tar.gz` (multiple files). - - To restore: `gunzip backup.sql.gz && wp db import backup.sql` - -2. **Keep block names identical** (recommended approach) - - Register new Sage blocks with same names: `imagewize/carousel-block`, `imagewize/reviews-block`, etc. - - Ensure block attributes match original plugin blocks (same keys and types) - - WordPress will seamlessly use the theme blocks instead of plugin blocks - - **No database changes required** - existing content will just work - -3. **Alternative: Update block namespaces** (only if renaming blocks) - - If you choose different block names, run database search/replace to update block identifiers - - Old: `` - - New: `` - - Test on staging first - - **Not recommended** - adds unnecessary complexity - -4. **Verify content integrity** - - Check all pages/posts using migrated blocks - - Ensure attributes transferred correctly - - Validate media attachments still work - -### Phase 4: Cleanup - -1. **Remove Composer dependencies** - ```bash - cd site - composer remove imagewize/carousel-block - composer remove imagewize/reviews-block - composer remove imagewize/about-block - composer remove imagewize/services-block - composer remove imagewize/cta-block - ``` - -2. **Remove plugin files** - - Delete plugin directories from `site/web/app/plugins/` - - Verify no orphaned files remain - -3. **Update documentation** - - Update CLAUDE.md with new block locations - - Document any changes to block APIs - - Update deployment scripts if needed - -## Technical Considerations - -### Block Attribute Systems - -**Native WordPress Blocks (carousel, reviews, about, cta):** -- Use `block.json` for attribute definitions -- React-based with `edit.js` and `save.js` components -- Attributes stored in block markup -- Created with `@wordpress/create-block` - -**ACF Blocks (if any):** -- Sage native blocks use `acf-block.json` for field definitions -- Supports all ACF field types -- Automatic field group registration -- Block-scoped field namespacing - -### Asset Management - -- Blocks get individual CSS/JS bundles via Vite -- Automatic HMR during development -- Assets enqueued only when block is used - -### PHP vs JavaScript Blocks - -Current plugin blocks are primarily: -- **JavaScript-rendered** (carousel, reviews, about, cta): Created with `@wordpress/create-block` - - Use React components for editor and frontend - - Migrate JSX components to Sage native block structure - - May need to convert to dynamic blocks if server-side rendering is needed -- **PHP-rendered** (if any): Migrate to `block.php` with Blade templates - -### Block Name Strategy - -**Recommended: Keep block names identical** -- Register Sage blocks with exact same names as plugin blocks -- Uses `imagewize` text domain (already used for other theme blocks) -- Zero database migration needed -- Existing content works immediately after plugin removal - -Example block registration names: -- `imagewize/carousel-block` (not `imagewize/carousel`) -- `imagewize/reviews-block` (not `imagewize/reviews`) -- `imagewize/about-block` (not `imagewize/about`) -- `imagewize/services-block` (not `imagewize/services`) -- `imagewize/cta-block` (not `imagewize/cta`) - -### Database Migration Script (only if renaming blocks) - -**Note:** Only needed if you choose to rename blocks (not recommended) - -```php -// Example: Update block names in post_content -$old_blocks = [ - 'imagewize/carousel-block', - 'imagewize/reviews-block', - 'imagewize/about-block', - 'imagewize/services-block', - 'imagewize/cta-block', -]; - -foreach ($old_blocks as $block) { - $new_block = 'imagewize/' . str_replace('-block', '', $block); - // Run search/replace on wp_posts.post_content -} -``` - -## Rollback Plan - -If issues arise: - -1. **Keep plugin versions available** - - Don't delete plugin code immediately - - Maintain Composer lock file with working versions - -2. **Database rollback** - - Restore from pre-migration backup - - Revert block namespace changes - -3. **Composer restore** - ```bash - cd site - composer require imagewize/carousel-block:^1.0.0 - # ... restore other blocks - ``` - -## Benefits - -1. **Simplified dependency management** - - All blocks in theme repository - - Single build process - - Unified versioning - -2. **Better developer experience** - - HMR for all blocks during development - - Consistent block creation workflow - - Shared theme utilities and styles - -3. **Performance** - - Reduced plugin overhead - - Better asset optimization - - Fewer HTTP requests - -4. **Maintenance** - - Single codebase to maintain - - Easier to keep blocks in sync with design system - - Simplified deployment - -## Risks - -1. **Breaking changes** (mitigated by keeping block names identical) - - ~~Block namespace changes may break existing content~~ - **Not an issue if block names stay the same** - - ~~Requires careful database migration~~ - **Not needed if block names stay the same** - -2. **Feature parity** - - Must ensure all plugin features are preserved - - Must match block attributes exactly (same keys, types, and default values) - - Additional testing required - -3. **Migration complexity** - - Multiple blocks to migrate - - React/JSX component migration requires careful porting - - Must ensure `block.json` configurations match exactly - -## Timeline Estimate - -Per block (approximate): -- Analysis & prep: 1-2 hours -- Scaffold & migration: 2-4 hours -- Testing: 1-2 hours -- **Total per block: 4-8 hours** - -**Full migration: 20-40 hours** (5 blocks) - -Plus: -- Database migration script: 4-6 hours -- Testing & QA: 8-10 hours -- **Grand total: 32-56 hours** - -## Success Criteria - -- [ ] All 5 blocks migrated to Sage native blocks -- [ ] Existing content displays correctly with new blocks -- [ ] All block features work as expected -- [ ] No plugin dependencies remain in composer.json -- [ ] Build process completes without errors -- [ ] Documentation updated -- [ ] Staging environment validated -- [ ] Production deployment successful diff --git a/docs/BLOCKS.md b/docs/BLOCKS.md deleted file mode 100644 index 3ef8dd6..0000000 --- a/docs/BLOCKS.md +++ /dev/null @@ -1,433 +0,0 @@ -# Custom Blocks Library - -Nynaeve includes **17 professionally designed custom blocks** for building modern websites. All blocks are built with WordPress native InnerBlocks for maximum flexibility and user control. - -## Table of Contents - -- [Using Custom Blocks](#using-custom-blocks) -- [Hero & Banner Blocks](#hero--banner-blocks) -- [Content & Layout Blocks](#content--layout-blocks) -- [Pricing & Comparison Blocks](#pricing--comparison-blocks) -- [Dynamic Content Blocks](#dynamic-content-blocks) -- [Block Features](#block-features) - -## Using Custom Blocks - -### Adding Blocks to Your Pages - -1. **Open Block Editor**: Edit any page/post in WordPress -2. **Insert Block**: Click the "+" icon or type "/" to search -3. **Find Imagewize Blocks**: All custom blocks appear in the **"Imagewize"** category -4. **Insert Block**: Click to add block to your page -5. **Customize**: Use native WordPress block toolbar and settings panel to style - -**Block Category:** -All Nynaeve custom blocks are organized under the **"Imagewize"** category in the block inserter for easy discovery. You can also search by block name (e.g., "Feature List Grid", "Testimonial Grid"). - -**Customization Options:** -- **Toolbar** (top): Alignment, text formatting, block-specific options -- **Settings Panel** (right sidebar): Colors, spacing, typography, advanced options -- All blocks are fully customizable without code changes - -## Hero & Banner Blocks - -### About - -About section with image and content layout. Professional presentation for company information and team introductions. - -**Features:** -- Two-column layout with image and content -- Flexible content area with headings and text -- Responsive design with mobile stacking -- Customizable alignment options -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize About` block -2. Add image via WordPress native image block -3. Edit heading and paragraph content -4. Customize fonts, sizes, and colors via block toolbar -5. Columns automatically stack on mobile (≤782px) - -**Best For:** About pages, team introductions, company overview sections - -### Page Heading Blue - -Full-width gradient banner for secondary page headings with professional styling. - -**Features:** -- Professional blue gradient background (primary to primary-dark) -- Subtle radial pattern overlay -- Responsive tagline, heading, and intro text -- Full-width alignment with content constrained to 55rem -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize Page Heading Blue` block -2. Block defaults to full-width alignment with gradient background -3. Edit tagline, heading, and intro text directly in the editor -4. Customize fonts, sizes, and colors via block toolbar -5. All content editable - tagline (Montserrat), H2 heading, intro paragraph -6. Responsive padding adapts automatically for mobile/tablet - -**Best For:** Secondary page headers, service pages, about pages, landing pages - -**Documentation:** [PAGE-HEADING-BLUE-BLOCK.md](PAGE-HEADING-BLUE-BLOCK.md) - -## Content & Layout Blocks - -### Multi-Column Content - -Comprehensive statistics and CTA section with multiple layouts. Perfect for showcasing metrics, benefits, and calls-to-action. - -**Features:** -- Main section heading for statistics overview -- Two-column statistics layout with taglines and stat headings -- Center heading for section transitions -- Two-column CTA section with headings, descriptions, and buttons -- Three-column benefits section with checkmark SVG icons -- Tint background with constrained content (1040px max-width) -- Template with default maintenance service content -- Responsive: multi-column desktop → single column mobile -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize Multi-Column Content` block -2. Block defaults to wide alignment with tint background -3. Template includes 6 sections: main heading, statistics (2 cols), center heading, subheading, CTAs (2 cols), benefits (3 cols) -4. Edit all content directly - statistics, CTAs, buttons, benefits -5. Customize fonts, sizes, and colors via block toolbar -6. Benefits automatically display checkmark icons (theme SVG) -7. All columns stack to single column on mobile (≤782px) - -**Best For:** Service pages, maintenance plans, feature showcases, product benefits - -**Documentation:** [MULTI-COLUMN-CONTENT-BLOCK.md](MULTI-COLUMN-CONTENT-BLOCK.md) - -### Two Column Card - -Professional card grid layout with heading and text content. Elegant presentation for features, services, or benefits. - -**Features:** -- Main section heading (H3) above responsive 2-column grid -- Uses WordPress native Columns block for intuitive layout -- Automatic mobile stacking at 782px breakpoint -- Elegant white cards with borders and decorative heading underlines -- Template includes 4 default cards with real content (2 per column) -- Tint background with constrained content (1040px max-width) -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize Two Column Card` block -2. Block defaults to wide alignment with tint background -3. Main heading (H3) displays above the card grid -4. Default template includes 4 cards (2 per column) with real content -5. Edit headings, paragraphs, and styling via block toolbar -6. Add/remove/duplicate cards using WordPress block controls -7. Columns automatically stack to single column on mobile (≤782px) -8. All fonts, sizes, and colors editable - no code changes needed - -**Best For:** Feature lists, service offerings, team highlights, testimonials - -**Documentation:** [TWO-COLUMN-CARD.md](TWO-COLUMN-CARD.md) - -### Feature List Grid - -Comprehensive feature showcase in a 2-column grid layout with checkmark icons. Perfect for presenting service offerings, maintenance plans, or product features. - -**Features:** -- Main section heading (H2) above responsive 2-column grid -- 5 feature cards with headings and checkmark lists (3 left, 2 right) -- Professional card design with subtle borders -- Checkmark SVG icons for all feature list items (no bullets) -- Decorative blue underline on card headings -- Template includes real maintenance service content -- Responsive: stacks to single column on mobile (≤768px) -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize Feature List Grid` block -2. Block defaults to wide alignment (880px content width) -3. Template includes 5 pre-populated feature cards: - - Security & Protection - - Updates & Maintenance - - Backups & Recovery - - Performance & Monitoring - - Support & Reporting -4. Edit headings and feature lists directly in editor -5. Customize fonts, sizes, and colors via block toolbar -6. Checkmarks automatically appear on all list items (no bullets) -7. Mobile: columns stack to single column - -**Best For:** Service features, maintenance plans, product benefits, feature comparisons - -### Review Profiles - -Customer review profiles grid with photos, testimonials, and ratings. Professional display of customer feedback with visual impact. - -**Features:** -- Multi-column profile grid layout -- Profile photos with testimonial quotes -- Star ratings or metrics display -- Professional card design -- Responsive grid stacking -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize Review Profiles` block -2. Add profile photos via WordPress image blocks -3. Edit customer names, companies, and testimonial text -4. Customize fonts, sizes, and colors via block toolbar -5. Grid automatically adjusts for mobile devices - -**Best For:** Customer reviews, testimonials with photos, social proof sections, case studies - -### Testimonial Grid - -Customer testimonials in a professional 3-column grid with metrics and quotes. Showcase social proof and success stories. - -**Features:** -- Main section heading (H2) above 3-column grid -- Professional testimonial cards with quotes, attribution, and metrics -- Light blue background (primary-accent) for visual distinction -- Clean card design with rounded corners -- Metric display with border accent for emphasis -- Template includes 3 complete testimonials with real data -- Responsive: stacks to single column on mobile (≤782px) -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize Testimonial Grid` block -2. Block defaults to wide alignment with light blue background -3. Template includes 3 pre-populated testimonials: - - Security success (127 threats blocked) - - Performance improvement (57% faster) - - Downtime prevention ($15K saved) -4. Edit quotes, author names, companies, and metrics -5. Customize fonts, sizes, and colors via block toolbar -6. Metric text appears with top border accent -7. Mobile: columns stack, font sizes reduce - -**Best For:** Customer testimonials, case studies, success stories, social proof sections - -### CTA Columns - -Call-to-action columns layout with multiple CTA options. Present multiple action items in a clean, organized grid. - -**Features:** -- Multi-column layout for CTAs -- Heading, description, and button support -- Flexible spacing and alignment -- Responsive column stacking -- All typography editable via block toolbar - -**Usage Example:** - -1. Insert `Imagewize CTA Columns` block -2. Add headings and descriptions for each CTA -3. Configure button text and links -4. Customize fonts, sizes, and colors via block toolbar -5. Columns automatically stack on mobile - -**Best For:** Landing pages, service offerings, product features, conversion-focused sections - -### Content Image Text Card - -Flexible content cards with images, headings, text, and buttons. Perfect for feature highlights and call-to-action sections. - -**Features:** -- Image block integration (WordPress native) -- Heading and paragraph blocks (fully editable) -- Button block with customizable styles -- Responsive layout with flexible spacing -- Alignment controls via inspector panel - -**Usage Example:** - -1. Insert `Imagewize Content Image Text Card` block -2. Upload image via native WordPress image block -3. Edit heading, paragraph, and button text -4. Select button style from toolbar -5. Adjust spacing, colors, and alignment via inspector panel - -**Best For:** Product features, service highlights, portfolio items, promotional content - -### Carousel - -Dynamic image carousel with configurable slides and settings. Showcase multiple images with smooth transitions. - -**Features:** -- Multiple slide support via Slide block -- Configurable transition settings -- Responsive design -- Navigation controls -- Auto-play options - -**Best For:** Image galleries, portfolio showcases, client logos, testimonials - -### FAQ - -Accordion-style FAQ sections for support content. Clean, accessible interface for questions and answers. - -**Features:** -- Accordion-style interaction -- Expandable/collapsible sections -- Accessible keyboard navigation -- Semantic HTML structure -- Customizable styling - -**Best For:** Support pages, documentation, help centers, product information - -## Pricing & Comparison Blocks - -### Pricing (2-Column) - -Classic high-contrast pricing comparison with two side-by-side options. - -**Features:** -- Two-column layout -- High-contrast design -- Clear pricing display -- Feature lists with checkmarks -- CTA buttons with customizable styles - -**Best For:** Simple pricing comparison, basic/premium tiers, service packages - -### Pricing Tiers (3-Column) - -Professional pricing table with featured tier highlighting. Ideal for presenting multiple pricing options with a recommended plan. - -**Features:** -- Three-column layout -- Subtle blue accent backgrounds -- Checkmark SVG icons for features -- Hover effects and elevation -- "Most Popular" badge styling -- Responsive: stacks to single column on mobile - -**Usage Example:** - -1. Insert `Imagewize Pricing Tiers` block -2. Default template includes three columns: Basic → Featured → Premium -3. Featured center column has subtle blue background (#e6f4fb) -4. Edit pricing, features, and buttons directly in the editor -5. Select button styles via block toolbar (Default, Outline, Secondary, Light, Dark) -6. All styling controlled by user - no code changes needed - -**Best For:** Subscription plans, service tiers, product packages, membership levels - -**Documentation:** [MULTI-COLUMN-PRICING-TABLE.md](MULTI-COLUMN-PRICING-TABLE.md) - -## Dynamic Content Blocks - -### Related Articles - -Smart tag-based article recommendations. Automatically displays related content based on post tags. - -**Features:** -- Automatic tag-based filtering -- Configurable number of posts -- Excerpt display -- Featured image support -- Customizable layout - -**Best For:** Blog posts, news articles, resource pages - -### Slide - -Individual carousel slide component. Used within the Carousel block to create dynamic slideshows. - -**Features:** -- Image support -- Caption/text overlay -- Link support -- Flexible content areas - -**Best For:** Used within Carousel block (not standalone) - -## Block Features - -All Nynaeve custom blocks share these core features: - -### InnerBlocks Architecture -- Built with native WordPress blocks (Image, Heading, Paragraph, Button) -- No hardcoded content or styles -- Full flexibility and extensibility - -### User Control -- All styling via WordPress block toolbar -- Color, typography, and spacing controls -- Alignment options (wide, full, none) -- Background and text color customization -- No code changes required for customization - -### Color & Background Customization - -Most Nynaeve blocks support color customization via the WordPress block settings panel: - -**Background Color Support:** -- All section-level blocks support background color changes -- Choose from theme color palette or custom colors -- Perfect for creating visual variety across pages - -**Text Color Support:** -- Newer blocks (Feature List Grid, Testimonial Grid, Content Image Text Card) support text color overrides -- Allows accessibility adjustments (contrast ratios) -- Provides flexibility for different background colors -- Note: Older blocks (Two Column Card, Multi-Column Content, Pricing blocks) have fixed text colors for brand consistency - -**Accessing Color Controls:** -1. Select the block in the editor -2. Open the block settings panel (right sidebar) -3. Look for "Color" or "Background" sections -4. Choose from theme colors or set custom values - -### Alignment Options - -All container blocks support WordPress alignment controls: - -**Wide Alignment (Default):** -- Content centered at 880px width (`contentSize` from theme.json) -- Recommended for most content blocks -- Proper reading width for text-heavy content - -**Full Alignment:** -- Spans entire viewport width -- Perfect for hero sections, full-width images, testimonial backgrounds -- Use for visual impact sections - -**None Alignment:** -- Uses default content width -- Matches WordPress core block behavior - -**Changing Alignment:** -1. Select block in editor -2. Use alignment toolbar button (top toolbar) -3. Choose wide, full, or none - -### Responsive Design -- Mobile-first approach -- Automatic responsive behavior -- Breakpoint: 782px (mobile/tablet) - -### Accessibility -- Semantic HTML structure -- ARIA labels where appropriate -- Keyboard navigation support -- Screen reader friendly - -### Performance -- Minimal custom CSS (containers and hover effects only) -- Optimized for Core Web Vitals -- Fast loading times - -## Block Development - -Want to create your own custom blocks? See the [Developer Guide](DEV.md#block-development) and [Pattern to Native Block Guide](PATTERN-TO-NATIVE-BLOCK.md) for detailed instructions. diff --git a/docs/CONTENT-WIDTH-AND-LAYOUT.md b/docs/CONTENT-WIDTH-AND-LAYOUT.md deleted file mode 100644 index 83368d9..0000000 --- a/docs/CONTENT-WIDTH-AND-LAYOUT.md +++ /dev/null @@ -1,1121 +0,0 @@ -# Content Width & Layout System - -## Current Status (2025-10-22) - -### ✅ Implementation Complete - Hybrid Approach -We've successfully implemented a **hybrid layout system** combining WordPress-native layout with block-specific padding. - -**What's Working:** -- ✅ Theme-based custom blocks (two-column-card, multi-column-content, cta-columns, etc.) -- ✅ Core WordPress blocks (paragraphs, headings, lists, images) -- ✅ Standalone content gets horizontal padding from theme CSS (doesn't touch viewport edges) -- ✅ `.alignfull` and `.alignwide` blocks properly excluded from universal padding -- ✅ Full-width blocks with backgrounds handle their own padding (block-specific CSS) -- ✅ User-defined padding from block editor takes precedence (`:where()` zero specificity) -- ✅ No double/triple padding issues - -### 🎯 The Hybrid Solution Explained - -**The Challenge:** -WordPress blocks come in three incompatible patterns: -1. **Standalone content** - Paragraphs/images added directly (no wrapper) -2. **Blocks with inner wrappers** - Custom divs for full-width backgrounds (Page Heading Blue) -3. **Blocks with WordPress group patterns** - Using `.wp-block-group__inner-container` (About Block) - -**The Solution - Three-Pronged Approach:** - -**1. Universal CSS for Standalone Content (app.css lines 695-698)** -```css -:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide) { - padding-left: var(--wp--preset--spacing--50); - padding-right: var(--wp--preset--spacing--50); -} -``` -- Catches standalone paragraphs, headings, lists, images -- Uses `:where()` for zero specificity (user padding can override) -- Excludes `.alignfull` and `.alignwide` blocks - -**2. Override for Blocks with WordPress Group Wrappers (app.css lines 710-713)** -```css -.wp-block-imagewize-about .wp-block-group__inner-container > * { - padding-left: 0 !important; - padding-right: 0 !important; -} -``` -- Prevents double padding on About Block (uses WordPress's `.wp-block-group__inner-container`) -- WordPress core handles padding for this pattern -- Universal rule would add extra padding = override needed -- Add similar overrides here for any future blocks using WordPress group patterns - -**3. Block-Specific Padding (each block's style.css)** -- Blocks with full-width backgrounds add padding to their **inner content wrapper** -- Page Heading Blue: Padding on `.page-heading-blue__content` wrapper -- Multi-Column Content: Padding on direct children `> *` -- Each block controls its own padding = no conflicts - -**Why This Works:** -- Standalone content never touches viewport edges ✅ -- Full-width backgrounds extend edge-to-edge ✅ -- Inner content has proper padding ✅ -- About Block no longer has double padding (override prevents it) ✅ -- User-defined padding takes precedence ✅ - -### ❌ Known Issues with Plugin-Based Blocks - -**Problem Blocks (from composer.json):** -- `imagewize/about-block` - Partially working but text appears narrow -- `imagewize/services-block` - Content appears squashed/compressed -- `imagewize/cta-block` - Layout issues similar to services block -- `imagewize/reviews-block` - May have similar issues - -**Root Cause:** -These plugin-based blocks were built **before** the hybrid layout system was implemented. They: -1. Don't have proper alignment support configured -2. May have hardcoded internal padding that conflicts with theme CSS -3. Were not designed with `:not(.alignfull):not(.alignwide)` exclusion in mind -4. Need to be migrated to theme as proper Sage Native Blocks - -## The Original Problem (RESOLVED) - -We removed Tailwind container classes from page templates around `the_content()` to let WordPress handle layout natively. This approach **should** work because: - -- WordPress blocks use `is-layout-constrained` classes to self-manage layout -- Regular blocks should automatically center at `contentSize` (880px from theme.json) -- `.alignfull` blocks should automatically span full viewport width via WordPress core CSS - -**Initial Issues (NOW FIXED):** - -### Mobile Issue (FIXED ✅) -On mobile devices, standalone paragraphs, headings, and list items **touched the sides** with no padding. This created a poor reading experience. - -**Solution:** Added `:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide)` CSS rule with horizontal padding. - -### Desktop Issue (FIXED ✅) -On desktop, content appeared to be **full width** automatically, rather than centering at the expected `contentSize` (880px). - -**Solution:** WordPress core handles this automatically when using proper `.is-layout-constrained` wrapper. - -## Root Cause Analysis - -### Current theme.json Settings - -```json -"layout": { - "contentSize": "55rem", // 880px - "wideSize": "64rem" // 1024px -} -``` - -### Current CSS Approach - -In `app.css` (lines 684-698), we added padding to `.alignfull` blocks: - -```css -.alignfull { - padding-inline: var(--wp--preset--spacing--20, 1rem); -} - -@media (min-width: 640px) { - .alignfull { - padding-inline: var(--wp--preset--spacing--40, 2rem); - } -} - -@media (min-width: 1024px) { - .alignfull { - padding-inline: var(--wp--preset--spacing--50, 3rem); - } -} -``` - -**Problem**: This only fixes `.alignfull` blocks. Regular blocks without alignment (paragraphs, headings, lists) don't get this padding. - -### Why WordPress Native Layout Isn't Working - -WordPress's native layout system (`.is-layout-constrained`) should automatically: -1. Center content at `contentSize` (880px) -2. Add padding on mobile to prevent edge-touching -3. Allow `.alignfull` blocks to break out to full width - -**Why it's failing:** -- The layout classes may not be applied correctly to individual blocks -- WordPress expects a **container element** with `.is-layout-constrained` class -- When we removed Tailwind containers, we may have also removed the wrapper WordPress needs - -## Possible Solutions - -### Option 1: WordPress-Native Layout Container (RECOMMENDED) - -Add a WordPress-aware container that applies `.is-layout-constrained` to the content area. - -**Implementation:** -```php - -
- {!! the_content() !!} -
-``` - -**Pros:** -- Uses WordPress's native layout system exactly as block themes do -- Automatically handles `contentSize`, `wideSize`, and `.alignfull` -- No custom CSS needed - WordPress core handles everything -- Matches modern block theme approach (Twenty Twenty-Four, etc.) - -**Cons:** -- Requires template changes -- Need to test with all existing blocks/patterns - -**CSS Additions:** -```css -/* Support for WordPress layout system */ -.is-layout-constrained > * { - max-width: var(--wp--style--global--content-size, 55rem); - margin-left: auto !important; - margin-right: auto !important; - padding-left: var(--wp--preset--spacing--20, 1rem); - padding-right: var(--wp--preset--spacing--20, 1rem); -} - -.is-layout-constrained > .alignfull { - max-width: none !important; - width: 100vw; - margin-left: calc(50% - 50vw) !important; - margin-right: calc(50% - 50vw) !important; -} - -.is-layout-constrained > .alignwide { - max-width: var(--wp--style--global--wide-size, 64rem); -} - -@media (min-width: 640px) { - .is-layout-constrained > * { - padding-left: var(--wp--preset--spacing--40, 2rem); - padding-right: var(--wp--preset--spacing--40, 2rem); - } -} - -@media (min-width: 1024px) { - .is-layout-constrained > * { - padding-left: var(--wp--preset--spacing--50, 3rem); - padding-right: var(--wp--preset--spacing--50, 3rem); - } -} -``` - ---- - -### Option 2: Minimal Custom Container with Breakout Support - -Add a lightweight custom container that provides max-width and allows full-width blocks to break out. - -**Implementation:** -```php - -
- {!! the_content() !!} -
-``` - -**CSS:** -```css -/* Content container with breakout support */ -.content-container { - width: 100%; - max-width: 100vw; - overflow-x: hidden; -} - -.content-container > * { - max-width: 55rem; /* contentSize */ - margin-left: auto; - margin-right: auto; - padding-left: 1rem; - padding-right: 1rem; -} - -.content-container > .alignwide { - max-width: 64rem; /* wideSize */ -} - -.content-container > .alignfull { - max-width: none; - width: 100vw; - margin-left: calc(50% - 50vw); - margin-right: calc(50% - 50vw); - padding-left: 1rem; - padding-right: 1rem; -} - -/* Custom blocks that should be full-width */ -.content-container > [class*="wp-block-imagewize"] { - max-width: none; - width: 100%; - margin-left: 0; - margin-right: 0; -} - -@media (min-width: 640px) { - .content-container > * { - padding-left: 2rem; - padding-right: 2rem; - } - .content-container > .alignfull { - padding-left: 2rem; - padding-right: 2rem; - } -} - -@media (min-width: 1024px) { - .content-container > * { - padding-left: 3rem; - padding-right: 3rem; - } - .content-container > .alignfull { - padding-left: 3rem; - padding-right: 3rem; - } -} -``` - -**Pros:** -- Full control over layout behavior -- Easy to customize for specific blocks -- Can handle custom blocks differently than core blocks - -**Cons:** -- Not using WordPress's native system -- More CSS to maintain -- May conflict with future WordPress layout updates - ---- - -### Option 3: Universal Padding with Negative Margins for Full-Width - -Apply padding to all direct children of content areas, then use negative margins for full-width blocks. - -**Implementation:** -```php - -
- {!! the_content() !!} -
-``` - -**CSS:** -```css -/* Universal content padding */ -.entry-content > * { - padding-left: 1rem; - padding-right: 1rem; - max-width: 55rem; /* contentSize */ - margin-left: auto; - margin-right: auto; -} - -/* Wide blocks */ -.entry-content > .alignwide { - max-width: 64rem; /* wideSize */ -} - -/* Full-width blocks break out */ -.entry-content > .alignfull { - max-width: none; - width: 100vw; - margin-left: calc(50% - 50vw); - margin-right: calc(50% - 50vw); -} - -/* Responsive padding */ -@media (min-width: 640px) { - .entry-content > * { - padding-left: 2rem; - padding-right: 2rem; - } -} - -@media (min-width: 1024px) { - .entry-content > * { - padding-left: 3rem; - padding-right: 3rem; - } -} -``` - -**Pros:** -- Simple approach - padding on everything, breakout where needed -- Works with any content structure -- Easy to understand and debug - -**Cons:** -- Every element gets padding (may cause issues with nested blocks) -- Negative margins can be fragile -- Not using WordPress's intended layout system - ---- - -### Option 4: Use Tailwind + Breakout Utility Classes - -Keep using Tailwind containers but add utility classes to allow full-width breakouts. - -**Implementation:** -```php - -
- {!! the_content() !!} -
-``` - -**CSS:** -```css -/* Full-width breakout utility */ -.alignfull { - width: 100vw; - position: relative; - left: 50%; - right: 50%; - margin-left: -50vw; - margin-right: -50vw; -} -``` - -**Pros:** -- Uses familiar Tailwind utilities -- Explicit, predictable behavior -- Works well with existing Tailwind setup - -**Cons:** -- Goes against WordPress's native layout system -- Harder for users to understand alignment options -- Custom blocks need manual breakout CSS - ---- - -## How Twenty Twenty-Five Solves This - -The official WordPress theme Twenty Twenty-Five uses a **two-pronged approach**: - -### 1. Theme.json Configuration - -**Key Settings** (lines 53-56, 186, 194-198): - -```json -"layout": { - "contentSize": "645px", - "wideSize": "1340px" -}, -"useRootPaddingAwareAlignments": true -``` - -**Root-level padding** (in `styles.spacing`): -```json -"spacing": { - "blockGap": "1.2rem", - "padding": { - "left": "var:preset|spacing|50", - "right": "var:preset|spacing|50" - } -} -``` - -The `"useRootPaddingAwareAlignments": true` setting is **critical** - it tells WordPress that: -- The root element (body/main) has padding -- `.alignfull` blocks should extend **beyond** that padding to reach viewport edges -- Regular content respects the root padding automatically - -### 2. Template Structure - -**Page Template** (`templates/page.html`, line 9): -```html - -``` - -**Post Template** (`templates/single.html`, line 10): -```html - -``` - -**Key observations:** -- The `` block has `align="full"` -- But **also** has `layout={"type":"constrained"}` -- This creates a paradox that WordPress resolves intelligently: - - The post-content container itself is full-width - - But its **children** are constrained to `contentSize` - - Unless the children have their own alignment (wide/full) - -### 3. Minimal CSS - -Twenty Twenty-Five has **almost no custom layout CSS** - just 62 lines in `style.css`, mostly for focus states and typography enhancements. **WordPress handles all the layout automatically.** - ---- - -## Recommendation - -**Use the Twenty Twenty-Five Approach (WordPress-Native)** - -This approach: -1. ✅ Follows WordPress best practices (matches Twenty Twenty-Five theme) -2. ✅ Automatically handles all alignment options (default, wide, full) -3. ✅ Provides mobile padding out-of-the-box via root padding -4. ✅ Future-proof - works with WordPress layout updates -5. ✅ **ZERO custom layout CSS needed** - WordPress core does everything -6. ✅ User-friendly - alignment options in block toolbar "just work" -7. ✅ Uses `useRootPaddingAwareAlignments` for proper full-width breakouts - -## Implementation Steps (Twenty Twenty-Five Approach) - -### Step 1: Update theme.json - -Add these two critical settings to `theme.json`: - -```json -{ - "settings": { - "layout": { - "contentSize": "55rem", // Keep existing value (880px) - "wideSize": "64rem" // Keep existing value (1024px) - }, - "useRootPaddingAwareAlignments": true // ADD THIS! - }, - "styles": { - "spacing": { - "padding": { - "left": "var:preset|spacing|50", // ADD THIS! - "right": "var:preset|spacing|50" // ADD THIS! - } - } - } -} -``` - -**Note:** You'll need to define spacing presets if they don't exist. Based on your current CSS: -- `spacing|20` = 1rem (mobile) -- `spacing|40` = 2rem (tablet) -- `spacing|50` = 3rem (desktop) - -### Step 2: Update Template Structure - -Since you're using Blade templates (not block templates), you need to adjust how `the_content()` is rendered. - -**Option A: Add wrapper in Blade template** - -In files like `resources/views/partials/content-page.blade.php`: - -```php -
-
- {!! the_content() !!} -
-
-``` - -**Option B: Filter the_content() wrapper** - -Add to your theme's `functions.php` or a service provider: - -```php -add_filter('the_content', function($content) { - if (is_singular() && in_the_loop() && is_main_query()) { - return '
' - . $content . '
'; - } - return $content; -}); -``` - -### Step 3: Remove Custom Layout CSS - -**Delete or comment out** the custom `.alignfull` padding in `resources/css/app.css` (lines 684-698): - -```css -/* DELETE THIS - WordPress will handle it automatically */ -/* -.alignfull { - padding-inline: var(--wp--preset--spacing--20, 1rem); -} -... etc -*/ -``` - -### Step 4: Add Spacing Scale to theme.json - -If you don't have spacing presets defined, add this to `theme.json`: - -```json -"settings": { - "spacing": { - "spacingSizes": [ - { - "name": "Small", - "size": "clamp(1rem, 2vw, 1rem)", - "slug": "20" - }, - { - "name": "Medium", - "size": "clamp(1.5rem, 3vw, 2rem)", - "slug": "40" - }, - { - "name": "Large", - "size": "clamp(2rem, 4vw, 3rem)", - "slug": "50" - } - ] - } -} -``` - -### Step 5: Test Implementation - -Test with all existing content: -- [ ] Mobile: Regular content has padding (doesn't touch edges) -- [ ] Desktop: Regular content centers at 880px -- [ ] `.alignwide` blocks center at 1024px -- [ ] `.alignfull` blocks span full viewport width -- [ ] Custom blocks respect alignment settings -- [ ] No horizontal scrollbar appears -- [ ] Works on all page templates (page, post, archive) -- [ ] Block toolbar alignment options work correctly - -### Step 6: Update Documentation - -Update `CLAUDE.md` with the new approach so future development follows this pattern. - -## Reference Materials - -- [WordPress Layout Support](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#settings.layout) -- [useRootPaddingAwareAlignments Documentation](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/#settings.useRootPaddingAwareAlignments) -- [Twenty Twenty-Five Theme](https://github.com/WordPress/twentytwentyfive) - Reference implementation (recommended) -- [Twenty Twenty-Four Theme](https://github.com/WordPress/twentytwentyfour) - Alternative reference -- [Block Editor Layout Documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#layout) - ---- - -## Summary: The Magic of useRootPaddingAwareAlignments - -The key insight from Twenty Twenty-Five is that **you need minimal custom CSS** for layout management. Instead: - -1. **Set root padding** in theme.json (`styles.spacing.padding`) -2. **Enable `useRootPaddingAwareAlignments: true`** in theme.json -3. **Wrap content** in `
` -4. **Add minimal CSS** for standalone block padding (WordPress handles centering/max-width) - -This tells WordPress: -- "The body/main has padding" (from root padding) -- "Regular content should respect this padding and center at contentSize" -- "`.alignfull` blocks should ignore the padding and reach viewport edges" -- "`.alignwide` blocks should center at wideSize" - -**Result:** Near-perfect layout on all devices with minimal custom CSS. This is the modern WordPress way. - ---- - -## Path Forward: Plugin Block Migration Strategy - -### Current Situation Assessment - -**What We've Achieved:** -- ✅ WordPress-native layout system fully implemented -- ✅ Theme-based blocks working perfectly (two-column-card, multi-column-content, etc.) -- ✅ Core WordPress blocks working correctly -- ✅ Clean, maintainable CSS using `:where()` for zero specificity - -**What's Broken:** -- ❌ Plugin-based blocks (about-block, services-block, cta-block, reviews-block) -- ❌ These blocks appear squashed/compressed with narrow content areas -- ❌ Built before layout system changes, incompatible with current approach - -### Three Options for Moving Forward - -#### Option 1: Quick Fix - Add CSS Overrides for Plugin Blocks (SHORT-TERM) ⚠️ - -**Pros:** -- Fast implementation (1-2 hours) -- No code refactoring needed -- Gets site functional quickly - -**Cons:** -- Hacky solution, not maintainable long-term -- CSS overrides can be fragile -- Doesn't address root cause -- May break with plugin updates - -**Implementation:** -```css -/* Temporary fix for plugin blocks - NOT RECOMMENDED long-term */ -:where(.is-layout-constrained) > .wp-block-imagewize-about-block, -:where(.is-layout-constrained) > .wp-block-imagewize-services-block, -:where(.is-layout-constrained) > .wp-block-imagewize-cta-block, -:where(.is-layout-constrained) > .wp-block-imagewize-reviews-block { - padding-left: 0; - padding-right: 0; -} -``` - -Then ensure each block has `align="full"` or `align="wide"` set in the editor. - ---- - -#### Option 2: Update Plugin Blocks - Add Alignment Support (MEDIUM-TERM) ⚙️ - -**Pros:** -- Keeps blocks as separate plugins (portable, reusable) -- Proper solution for the blocks -- Can be versioned independently - -**Cons:** -- Requires modifying 4 separate plugin repositories -- Need to publish new versions to Packagist -- Requires testing across multiple sites -- Ongoing maintenance overhead - -**Implementation Steps:** -1. For each plugin (about-block, services-block, cta-block, reviews-block): - - Add `"align": ["wide", "full"]` to block.json supports - - Set default alignment to `"full"` in block.json attributes - - Update block CSS to work with alignment classes - - Remove conflicting internal padding - - Test with Nynaeve theme -2. Publish new versions to GitHub -3. Update Packagist -4. Update site/composer.json version constraints -5. Run `composer update` - -**Estimated Time:** 2-3 days per block = 8-12 days total - ---- - -#### Option 3: Migrate Blocks to Theme as Sage Native Blocks (RECOMMENDED) ✅ - -**Pros:** -- **Best long-term solution** -- Blocks live in theme, easier to maintain -- Consistent with other theme blocks -- No external dependencies -- Can be optimized specifically for this theme -- Single codebase for all blocks -- Faster iteration and testing - -**Cons:** -- Initial time investment (2-3 days per block) -- Blocks not portable to other projects (acceptable trade-off) -- Need to remove from composer.json - -**Implementation Steps:** - -1. **For each block, create Sage Native Block:** - ```bash - cd trellis - trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve - - # Create blocks using existing plugin code as reference - wp acorn sage-native-block:create about --template=basic --force - wp acorn sage-native-block:create services --template=basic --force - wp acorn sage-native-block:create cta --template=nynaeve-cta --force - wp acorn sage-native-block:create reviews --template=basic --force - ``` - -2. **Copy functionality from plugins:** - - Copy block.json attributes - - Copy and adapt React components - - Copy and adapt CSS (update for theme variables) - - Add proper alignment support (`"align": ["wide", "full"]`) - - Set `"default": "full"` for alignment - -3. **Update block.json for each:** - ```json - { - "supports": { - "align": ["wide", "full"], - "spacing": { - "margin": true, - "padding": true - } - }, - "attributes": { - "align": { - "type": "string", - "default": "full" - } - } - } - ``` - -4. **Remove plugins from composer.json:** - ```bash - cd site - composer remove imagewize/about-block - composer remove imagewize/services-block - composer remove imagewize/cta-block - composer remove imagewize/reviews-block - ``` - -5. **Update content in WordPress:** - - Blocks will need to be replaced in pages (WordPress will show deprecation warnings) - - Create migration script or manually update pages - -**Estimated Time:** -- About Block: 4-6 hours -- Services Block: 4-6 hours -- CTA Block: 2-3 hours (can use existing nynaeve-cta template) -- Reviews Block: 4-6 hours -- Testing & refinement: 4 hours -- **Total: 2-3 days** - ---- - -### Recommendation: Option 3 (Migrate to Theme) - -**Why this is the best choice:** - -1. **Aligns with existing pattern:** You've already migrated several blocks successfully (two-column-card, multi-column-content, testimonial-grid, etc.) - -2. **Single source of truth:** All blocks in one place, easier to maintain - -3. **Performance:** Fewer external dependencies, smaller Composer footprint - -4. **Consistency:** All blocks follow same patterns, use same CSS variables, same build process - -5. **Future-proof:** No worries about plugin compatibility or versioning - -6. **Developer experience:** Easier to iterate on blocks, faster testing - -**Migration Priority Order:** -1. **CTA Block** (easiest, can use existing template) -2. **About Block** (partially working, simple structure) -3. **Services Block** (more complex, icon support) -4. **Reviews Block** (most complex, may need testimonial-grid integration) - ---- - -### Alternative: Hybrid Approach - -If time is constrained: - -1. **Immediate:** Use Option 1 (CSS fix) to make site functional -2. **Within 1 week:** Migrate CTA Block (Option 3) -3. **Within 2 weeks:** Migrate About Block (Option 3) -4. **Within 1 month:** Migrate Services & Reviews Blocks (Option 3) - -This provides immediate relief while working toward the proper solution incrementally. - ---- - -### Implementation Checklist for Migration - -When migrating each block: - -- [ ] Create new Sage Native Block with appropriate template -- [ ] Copy attributes from plugin block.json -- [ ] Copy and adapt edit component (editor.jsx) -- [ ] Copy and adapt save component (save.jsx) -- [ ] Copy and adapt frontend styles (style.css) -- [ ] Copy and adapt editor styles (editor.css) -- [ ] Add alignment support (`"align": ["wide", "full"]`) -- [ ] Set default alignment to `"full"` -- [ ] Remove conflicting padding CSS -- [ ] Test in editor (block insertion, editing, saving) -- [ ] Test on frontend (mobile and desktop) -- [ ] Test with different alignment options -- [ ] Update documentation -- [ ] Create backup of pages using old block -- [ ] Replace old blocks in WordPress editor -- [ ] Delete old content (keep backup) -- [ ] Remove plugin from composer.json -- [ ] Run composer update -- [ ] Final testing across all pages - ---- - -## Discovered Issue: Double/Triple Padding on Mobile (2025-10-22) - -### Problem Summary - -Multiple blocks are experiencing **excessive padding on mobile devices** due to padding rules stacking on top of each other. This was discovered via Playwright screenshot testing of the production homepage. - -### Affected Blocks - -#### 1. About Block (`imagewize/about`) -**Symptoms:** Text content appears very narrow with excessive side padding - -**Root Cause - Double Padding:** -- **Layer 1 (Theme CSS)**: `:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide)` adds `3rem` padding -- **Layer 2 (Block CSS)**: `.wp-block-imagewize-about.alignfull .wp-block-group__inner-container` adds `1rem` padding - -**Total**: 4rem (64px) of padding on each side - way too much! - -**Location**: [resources/js/blocks/about/style.css:27-30](resources/js/blocks/about/style.css#L27-L30) - -**Conflict Code:** -```css -@media (max-width: 768px) { - .wp-block-imagewize-about.alignfull .wp-block-group__inner-container { - padding-left: 1rem; /* ❌ CONFLICTS with theme padding */ - padding-right: 1rem; /* ❌ CONFLICTS with theme padding */ - } -} -``` - -**Solution:** -```css -@media (max-width: 768px) { - /* Remove block-level padding - let WordPress handle it */ - .wp-block-imagewize-about.alignfull .wp-block-group__inner-container { - padding-left: 0; /* ✅ WordPress handles padding */ - padding-right: 0; /* ✅ WordPress handles padding */ - } -} -``` - -**Additional cleanup needed:** -- Lines 32-36: Remove padding from headings (redundant) -- Lines 38-42: Remove padding from paragraphs (redundant) -- Lines 44-47: Remove duplicate `.wp-block-group__inner-container` padding -- Lines 54-61: Remove heading/paragraph padding (redundant) - -The block should rely **entirely** on WordPress's layout system and theme padding. Only add padding when you need to **override** the defaults for a specific design reason. - ---- - -#### 2. Page Heading Blue Block (`imagewize/page-heading-blue`) -**Symptoms:** Content has excessive horizontal padding - -**Root Cause - Triple Padding:** -- **Layer 1 (WordPress Core)**: `.has-global-padding` adds `var(--wp--style--root--padding-right)` -- **Layer 2 (Theme CSS)**: `:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide)` adds `var(--wp--preset--spacing--50)` -- **Layer 3 (Block CSS)**: `.page-heading-blue__content` adds manual `1rem/1.25rem/1.5rem` padding - -**Location**: [resources/js/blocks/page-heading-blue/style.css:38-63](resources/js/blocks/page-heading-blue/style.css#L38-L63) - -**Conflict Code:** -```css -.page-heading-blue__content { - max-width: var(--wp--style--global--content-size, 55rem); - margin: 0 auto; - padding: 0 1.5rem; /* ❌ CONFLICTS - adds to theme padding */ - position: relative; - z-index: 1; -} - -@media (max-width: 768px) { - .page-heading-blue__content { - padding: 0 1.25rem; /* ❌ CONFLICTS */ - } -} - -@media (max-width: 480px) { - .page-heading-blue__content { - padding: 0 1rem; /* ❌ CONFLICTS */ - } -} -``` - -**Solution:** - -This block uses a **custom inner wrapper** (`.page-heading-blue__content`) to constrain content, which is correct for a full-width background block. However, it's manually adding padding when it should inherit from theme settings. - -**Two approaches:** - -**Option A - Remove manual padding (recommended):** -```css -.page-heading-blue__content { - max-width: var(--wp--style--global--content-size, 55rem); - margin: 0 auto; - padding: 0; /* ✅ Let children inherit theme padding */ - position: relative; - z-index: 1; -} - -/* Remove all media query padding overrides */ -``` - -**Option B - Use CSS variables from theme:** -```css -.page-heading-blue__content { - max-width: var(--wp--style--global--content-size, 55rem); - margin: 0 auto; - padding: 0 var(--wp--style--root--padding-right); /* ✅ Use theme padding */ - position: relative; - z-index: 1; -} -``` - ---- - -#### 3. Pricing Tiers Block (`imagewize/pricing-tiers`) -**Symptoms:** Similar excessive padding issues - -**Root Cause:** Same as Page Heading Blue - receiving both: -- `.has-global-padding` padding -- `:where(.is-layout-constrained)` padding -- Likely has internal padding in block CSS - -**Solution:** Audit block CSS and remove manual padding, rely on WordPress layout system. - ---- - -#### 4. Review Profiles Block (`imagewize/review-profiles`) -**Symptoms:** Custom padding calculation conflicts with theme - -**Root Cause:** Block manually calculates padding based on root padding - -**Location**: [resources/js/blocks/review-profiles/style.css:13-17](resources/js/blocks/review-profiles/style.css#L13-L17) - -**Conflict Code:** -```css -&.alignfull { - width: 100%; - padding: calc(0.5 * var(--wp--style--root--padding-right)) - var(--wp--style--root--padding-right); /* ❌ Math on top of theme padding */ -} -``` - -**Solution:** - -Since this block has `align="full"` default and `useRootPaddingAwareAlignments: true` is enabled, WordPress automatically handles the padding breakout. The block should **not** add its own padding. - -```css -&.alignfull { - width: 100%; - /* ✅ Remove manual padding - WordPress handles it via useRootPaddingAwareAlignments */ -} -``` - -The block's inner content will automatically receive proper padding from the theme's layout system. - ---- - -### Why This Happens - -The WordPress-native layout system (implemented in v2.0.0) uses: - -1. **Root padding** (`theme.json` → `styles.spacing.padding`) -2. **Root padding aware alignments** (`useRootPaddingAwareAlignments: true`) -3. **Constrained layout CSS** (`:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide)`) - -These three layers work together to automatically provide: -- Centered content at `contentSize` (55rem) -- Proper mobile/desktop padding -- Full-width breakouts for `.alignfull` blocks - -**When blocks add their own padding on top**, you get: -- **Double padding** (theme + block) -- **Triple padding** (WordPress core + theme + block) -- Inconsistent spacing across blocks - -### The Fix: Trust WordPress - -**Golden Rule:** Blocks should **remove all manual padding** and trust the WordPress layout system. - -**Only add padding when:** -1. You need a **specific design** that differs from theme defaults -2. You're creating **internal spacing** within a block component (not edge padding) -3. You're using a **full-width background** with constrained content (use theme variables, not hardcoded values) - -**Correct pattern for full-width blocks with backgrounds:** -```css -/* Outer container - full width with background */ -.wp-block-imagewize-my-block { - width: 100%; - background: blue; - /* ✅ NO padding here - WordPress handles it */ -} - -/* Inner content wrapper - constrained width */ -.my-block__content { - max-width: var(--wp--style--global--content-size, 55rem); - margin: 0 auto; - /* ✅ NO padding here either - children get it from theme */ -} - -/* Only add padding for INTERNAL spacing between elements */ -.my-block__element { - padding-top: 2rem; /* ✅ Vertical spacing is fine */ - padding-bottom: 2rem; /* ✅ Vertical spacing is fine */ - /* ❌ NO horizontal padding - theme handles it */ -} -``` - -### Action Items - -- [x] **About Block**: Remove all horizontal padding from mobile styles (Completed 2025-10-22) -- [x] **Page Heading Blue**: Remove manual padding from `.page-heading-blue__content` (Completed 2025-10-22) -- [x] **Pricing Tiers**: Audit and remove manual padding (No changes needed - already correct) -- [x] **Review Profiles**: Remove `calc()` padding from `.alignfull` (Completed 2025-10-22) -- [x] **Testimonial Grid**: Remove horizontal padding from container (Completed 2025-10-22) -- [x] **Two Column Card**: Remove horizontal padding (Completed 2025-10-22) -- [x] **CTA Columns**: Remove horizontal padding (Completed 2025-10-22) -- [x] **Multi Column Content**: Remove horizontal padding (Completed 2025-10-22) -- [x] **Feature List Grid**: Remove horizontal padding (Completed 2025-10-22) -- [x] **FAQ**: Remove horizontal padding (Completed 2025-10-22) -- [x] **Test all blocks**: Verify mobile/desktop padding looks correct (Completed 2025-10-22) -- [x] **Document pattern**: Add "Block Padding Best Practices" section to CLAUDE.md (Completed 2025-10-22) - -### Testing Checklist - -After fixes, verify with Playwright screenshots: - -```bash -# Test production homepage on mobile -npm run pw -- https://imagewize.com/ screenshot after-fix --mobile - -# Test on desktop -npm run pw -- https://imagewize.com/ screenshot after-fix --desktop -``` - -**Expected results:** -- **Mobile**: Consistent ~1-1.5rem padding on all blocks -- **Desktop**: Consistent ~2-3rem padding on all blocks -- **No blocks** should have noticeably more/less padding than others -- **Text content** should feel balanced - not too narrow, not too wide - ---- - -## Conclusion - -The WordPress-native layout system implementation was **successful** for theme-based blocks and core blocks. The issues with plugin-based blocks are **expected** and easily solvable through migration. - -**Next Steps:** -1. Review the three options above -2. Decide on approach (recommend Option 3) -3. Plan migration timeline -4. Execute migration block-by-block -5. Update this documentation as blocks are migrated - -The foundation is solid - we just need to bring the plugin blocks into alignment with the new system. - -**Latest Discovery (2025-10-22):** Even migrated blocks (About, Review Profiles, Page Heading Blue) have padding conflicts. The fix is to remove manual padding from block CSS and trust WordPress's layout system completely. - -**Resolution (2025-10-22):** All padding issues have been fixed across 10 blocks. All blocks now use vertical-only padding (top/bottom) and rely on the hybrid layout system for horizontal spacing. Tested with Playwright screenshots - padding is now consistent across all blocks on mobile and desktop. - -**Final Hybrid Solution (2025-10-22):** - -The solution combines two complementary approaches: - -**1. Universal Padding for Standalone Content (app.css lines 695-698)** -```css -:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide) { - padding-left: var(--wp--preset--spacing--50); - padding-right: var(--wp--preset--spacing--50); -} -``` -- Adds padding to standalone paragraphs, headings, lists, images -- Excludes `.alignfull` and `.alignwide` blocks (they handle their own layout) -- Zero specificity via `:where()` - user padding can override - -**2. Block-Specific Padding (each block's style.css)** -- Blocks with full-width backgrounds add padding to their inner wrappers -- CTA Columns: Padding on `.wp-block-imagewize-cta-columns.alignfull > *` -- Multi-Column-Content: Padding on `.wp-block-imagewize-multi-column-content.alignfull > *` -- Page Heading Blue: Padding on `.page-heading-blue__content` wrapper -- Each block controls its own padding = no conflicts - -**Why This Hybrid Approach Works:** -- Standalone content: Gets padding from universal CSS rule ✅ -- Full-width blocks: Handle padding in block CSS (no conflicts) ✅ -- No double/triple padding (blocks excluded from universal rule via `:not()`) ✅ -- Full-width backgrounds extend edge-to-edge ✅ -- Inner content properly padded ✅ -- Clean, maintainable, predictable ✅ - -This hybrid system works efficiently with minimal CSS (40 lines total) for the entire theme's layout system, while giving each block full control over its own padding needs. diff --git a/docs/DEV.md b/docs/DEV.md deleted file mode 100644 index 99aea17..0000000 --- a/docs/DEV.md +++ /dev/null @@ -1,482 +0,0 @@ -# Developer Guide - -This guide covers development workflows, architecture, and best practices for working with the Nynaeve theme. - -## Table of Contents - -- [Project Structure](#project-structure) -- [Development Commands](#development-commands) -- [Block Development](#block-development) -- [Code Quality](#code-quality) -- [Architecture](#architecture) -- [WP-CLI Usage](#wp-cli-usage) -- [Customization](#customization) - -## Project Structure - -``` -nynaeve/ -├── resources/ -│ ├── js/ -│ │ ├── blocks/ # Custom blocks (React/JavaScript) -│ │ ├── app.js # Main JavaScript entry -│ │ └── editor.js # Block editor scripts -│ ├── css/ -│ │ ├── app.css # Main stylesheet (Tailwind) -│ │ └── editor.css # Block editor styles -│ ├── images/ # Theme images and logos -│ └── views/ # Blade templates -│ ├── layouts/ # Layout templates -│ ├── sections/ # Reusable sections -│ └── partials/ # Partial templates -├── app/ -│ ├── Blocks/ # PHP blocks (legacy) -│ ├── Fields/ # ACF Composer field groups -│ ├── Providers/ # Service providers -│ └── View/ # View composers -├── docs/ # Documentation -├── public/ # Compiled assets (generated) -├── bud.config.js # Build configuration (Vite) -├── tailwind.config.js # Tailwind CSS configuration -└── theme.json # WordPress theme settings -``` - -## Development Commands - -### Theme Development - -```bash -# Navigate to theme directory -cd site/web/app/themes/nynaeve - -# Install dependencies -composer install && npm install - -# Start development server with HMR -npm run dev - -# Build for production -npm run build - -# Check code quality -composer pint -``` - -### Development Mode - -For theme development on Bedrock sites, enable development mode in `config/environments/development.php`: - -```php -Config::define('WP_DEVELOPMENT_MODE', 'theme'); -``` - -**Benefits:** -- Bypasses theme.json and block theme caching -- Pattern changes appear immediately -- Essential for block theme development - -**Note:** Only use in development - impacts performance in production. - -## Block Development - -### Philosophy - -**InnerBlocks First** - Our blocks prioritize user control: -- Built with native WordPress blocks (Image, Heading, Paragraph, Button) -- No hardcoded styles in templates -- Users select all styles via block toolbar/inspector -- Minimal custom CSS (containers and hover effects only) -- Full flexibility without code changes - -See [PATTERN-TO-NATIVE-BLOCK.md](PATTERN-TO-NATIVE-BLOCK.md) for detailed implementation guide. - -### Sage Native Block Troubleshooting - -**Problem**: `sage-native-block:create` shows "No templates found" or "Template 'basic' not found in configuration" - -**Solution for v2.0.0 (LEGACY - No Longer Needed)**: -Older versions (v2.0.0) required manual config publishing: -1. **Publish the config file** (creates `config/sage-native-block.php`): - ```bash - wp acorn vendor:publish --provider="Imagewize\SageNativeBlockPackage\Providers\SageNativeBlockServiceProvider" - ``` -2. **Clear all caches**: `wp acorn optimize:clear` -3. **Verify config**: `ls -la config/sage-native-block.php` - -**Current Version (v2.0.1+)**: -- Config publishing is **no longer required** -- Package now works out-of-the-box without manual setup -- Projects with previously published configs will continue to work -- If you encounter issues, update the package: `composer update imagewize/sage-native-block` - -### Custom Block Templates - -Create reusable block templates in the `block-templates/` directory - they automatically appear in the template selection menu when creating new blocks with `wp acorn sage-native-block:create`. - -**Template Structure:** -Each custom template should be a directory containing the standard block files: -- `block.json` -- `index.js` -- `editor.jsx` -- `save.jsx` -- `style.css` -- `editor.css` -- `view.js` - -The template name is automatically detected from the directory name. - -### Creating New Blocks - -All WP-CLI commands (including `wp acorn`) must be run from the Trellis VM: - -```bash -# From Trellis VM (using --workdir for single command) -cd trellis -trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn sage-native-block:create - -# OR from interactive VM shell -cd trellis -trellis vm shell -cd /srv/www/imagewize.com/current/web/app/themes/nynaeve -wp acorn sage-native-block:create -``` - -**Interactive template selection with four options:** -1. **Basic Block** - Simple default block -2. **Generic Templates** - InnerBlocks, two-column, statistics, CTAs -3. **Nynaeve Templates** - Production-ready examples -4. **Custom Templates** - Auto-detected from block-templates/ directory - -**Why Trellis VM?** -- Database connection is configured in the VM environment -- WordPress installation is accessible at `/srv/www/imagewize.com/current/` -- All Acorn commands require database access -- Local machine doesn't have correct database credentials -- If you have another database server (MySQL, MariaDB, PostgreSQL) running locally, it will conflict with the Trellis VM's database port - -### Block Registration - -Blocks are automatically registered during theme setup. New blocks created with `sage-native-block:create` are immediately available in the WordPress block editor. - -### Full-Width Block Styling - -**IMPORTANT:** When creating blocks that support full-width alignment (`align: ["full"]`), use WordPress's native layout system instead of custom viewport-based CSS. - -**✅ Correct approach:** -```css -.wp-block-myblock.alignfull { - width: 100%; -} -``` - -**❌ Incorrect approach (causes editor issues):** -```css -.wp-block-myblock.alignfull { - width: 100vw; - max-width: 100vw; - margin-left: calc(50% - 50vw); - margin-right: calc(50% - 50vw); -} -``` - -**Why the viewport approach fails:** -- `100vw` causes blocks to extend behind the editor sidebar -- Works on frontend but breaks in WordPress editor -- WordPress automatically handles full-width when you set `"align": ["full"]` in block.json -- The editor applies proper full-width behavior without custom CSS - -**Best practice:** -1. Set `"align": ["full"]` or `"align": ["wide", "full"]` in block.json -2. Use `width: 100%` in your CSS (optional - WordPress handles it) -3. Let WordPress's `.alignfull` class do the work -4. Style the container/background, not the width/positioning - -## Code Quality - -### PHP Standards - -```bash -# Format PHP code with Laravel Pint -composer pint - -# Check PHP coding standards (from site root) -cd site && composer test - -# Direct PHPCS -phpcs -``` - -### CSS/JavaScript - -- Follows Tailwind CSS best practices -- ESLint configuration for JavaScript -- Prettier for code formatting - -## Architecture - -### Laravel Integration (Acorn) - -Nynaeve uses Acorn to bring Laravel's powerful features to WordPress: - -- **Service Providers**: Bootstrap theme functionality -- **Blade Templates**: Clean, expressive templating -- **View Composers**: Bind data to views -- **Dependency Injection**: Modern PHP patterns - -### Asset Pipeline (Vite) - -- **Entry Points**: `resources/css/app.css`, `resources/js/app.js`, `resources/css/editor.css`, `resources/js/editor.js` -- **Build Output**: `public/build/` directory -- **HMR**: Hot Module Replacement for instant updates -- **WordPress Integration**: `theme.json` generated from Tailwind config - -### Design System - -**Color Palette:** -- Primary: `#017cb6` -- Primary Accent: `#e6f4fb` -- Main: `#171b23` -- Base: `#ffffff` - -**Typography:** -- Body: Open Sans -- Monospace: Menlo -- Accent: Montserrat - -**Layout (WordPress-Native):** -- Content Width: 880px (55rem - `contentSize` in theme.json) -- Wide Width: 1024px (64rem - `wideSize` in theme.json) -- Uses Twenty Twenty-Five approach: `useRootPaddingAwareAlignments: true` -- Root padding: `var(--wp--preset--spacing--50)` (responsive) -- **Minimal custom CSS** - Just 40 lines of CSS for entire layout system - - WordPress core handles centering/max-width automatically - - Theme adds padding via two complementary rules: - - `:where(.is-layout-constrained) > :not(.alignfull):not(.alignwide)` - for standalone blocks (paragraphs, headings, etc.) - - `:where(.is-layout-constrained) > .alignfull > *` - for content inside full-width blocks with custom inner wrappers -- Custom padding uses `:where()` for zero specificity (user-defined padding always wins) -- See `docs/CONTENT-WIDTH-AND-LAYOUT.md` for full documentation - -## WP-CLI Usage - -All WP-CLI commands must be run from the Trellis VM. - -### Common Commands - -```bash -# Enter Trellis VM -cd trellis && trellis vm shell - -# Navigate to theme -cd /srv/www/imagewize.com/current/web/app/themes/nynaeve - -# List Acorn commands -wp acorn list - -# Clear cache -wp acorn optimize:clear - -# List registered blocks -wp block-type list - -# Database operations (from site root) -cd /srv/www/imagewize.com/current - -# Backup database -wp db export /tmp/backup_$(date +%Y%m%d_%H%M%S).sql.gz --path=web/wp - -# Search-replace URLs -wp search-replace 'old-url.com' 'new-url.com' --all-tables --precise --path=web/wp - -# Import database -wp db import /tmp/backup.sql.gz --path=web/wp -``` - -### Trellis VM + Local Database Conflicts - -If you have a local MariaDB/MySQL (Homebrew) running, it conflicts with Trellis VM on port 3306. In this case, all development database operations must run inside the Trellis VM. - -## Customization - -### Theme Configuration - -**theme.json** - WordPress theme settings: -- Color palette -- Typography settings -- Layout settings -- Block supports - -**resources/css/app.css** - Tailwind CSS configuration: -- Custom utilities -- Component styles -- Theme variables - -**resources/views/** - Blade templates: -- Layout structure -- Template parts -- Component composition - -**app/** - PHP functionality: -- Custom post types -- Taxonomies -- REST API endpoints -- Theme options (ACF Composer) - -### Theme Options - -Configure theme behavior via **WordPress Admin → Theme Options**: -- WooCommerce mode (Quote/Standard/Catalog) -- Additional theme settings managed through ACF Composer - -### Adding Custom Functionality - -**Service Providers** (`app/Providers/`): -```php - $this->getData(), - ]; - } - - protected function getData() - { - return 'custom data'; - } -} -``` - -## Local Development Environments - -Nynaeve supports both Lando and Trellis VM (Lima-based) for local WordPress environments. - -**Note:** We use Trellis VM (NOT Vagrant) - access via `trellis vm shell` command. - -### Environment Configuration - -Environment-specific configuration with `.env` files: -- `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_HOST` -- `WP_HOME`, `WP_SITEURL` -- `WP_ENV` (development, staging, production) - -## CSS Best Practices - -### Full-Width Block Styling - -**Modern Approach (v1.14.0+):** -- Let WordPress handle `.alignfull` blocks natively - no custom CSS needed -- Remove Tailwind containers from page templates around `the_content()` -- WordPress blocks with `is-layout-constrained` self-manage centering at `contentSize` (880px) -- `.alignfull` blocks automatically span full viewport via WordPress core CSS -- This approach matches modern block themes (Ollie, Twenty Twenty-Four, etc.) - -**Legacy Issue (pre-v1.14.0):** -Custom CSS using `100vw` or `-50vw` margins caused problems: -- `100vw` includes scrollbar width (~15px on Windows/Linux) -- Double-wrapping (Tailwind + WordPress containers) prevented proper breakout -- Percentage-based margins (`-50%`) failed with constrained layouts - -**Current Solution:** -No custom CSS needed. WordPress core handles it correctly when you: -1. Don't wrap post content in theme containers -2. Let blocks use WordPress's native layout classes -3. Only use `overflow-x: hidden` for specific cases like carousels - -**For Custom Full-Width Layouts (Non-Block Editor):** -If you need full-width outside of block editor content: -```css -.custom-full-width { - width: 100vw; - margin-left: calc(50% - 50vw); - margin-right: calc(50% - 50vw); -} -``` -But avoid this for block editor content - use WordPress's native system instead. - -### Block Padding Best Practices - -**Internal Component Spacing:** -Only add horizontal padding for: -1. **Internal spacing** within block components (cards, buttons) -2. **Internal component layout** (not edge padding) - -**Example - Full-width block with background:** -```css -/* Outer container - full width with background */ -.wp-block-imagewize-my-block { - width: 100%; - background: var(--wp--preset--color--tertiary); - padding: 5rem 0; /* ✅ Vertical only */ -} - -/* Inner wrapper - constrained width */ -.my-block__content { - max-width: var(--wp--style--global--content-size, 55rem); - margin: 0 auto; - /* ✅ NO horizontal padding - theme handles it */ -} - -/* Internal card padding is fine */ -.my-block__card { - padding: 2rem 1.5rem; /* ✅ Internal spacing */ -} -``` - -See [CONTENT-WIDTH-AND-LAYOUT.md](CONTENT-WIDTH-AND-LAYOUT.md) for comprehensive documentation. - -## File Conventions - -### Naming Standards - -- **PHP Classes**: PascalCase (e.g., `HeroBlock.php`) -- **Blade Templates**: kebab-case (e.g., `hero-block.blade.php`) -- **CSS/JS Files**: kebab-case (e.g., `hero-block-style.css`) -- **Block Names**: namespace/block-name (e.g., `imagewize/hero-block`) - -### Organization Principles - -- Keep related files together (block files in same directory) -- Follow Sage 11 conventions (app/, resources/, public/ structure) -- Use appropriate directories for file types -- Maintain consistent structure across components -- Block-specific CSS in `resources/css/blocks/` or imported in main CSS -- Block JavaScript in `resources/js/blocks/{block-name}/` - -## Additional Resources - -- [Sage Documentation](https://roots.io/sage/docs/) -- [Acorn Documentation](https://roots.io/acorn/docs/) -- [Tailwind CSS Documentation](https://tailwindcss.com/docs) -- [Vite Documentation](https://vitejs.dev/) -- [WordPress Block Editor Handbook](https://developer.wordpress.org/block-editor/) diff --git a/docs/PAGE-STYLE-GUIDE.md b/docs/PAGE-STYLE-GUIDE.md deleted file mode 100644 index 706d6a2..0000000 --- a/docs/PAGE-STYLE-GUIDE.md +++ /dev/null @@ -1,1083 +0,0 @@ -# Page Style Guide - Nynaeve Theme - -## Overview - -This guide provides recommendations for creating visually engaging, well-structured pages in the Nynaeve theme. Based on analysis comparing the home page (rich custom blocks) vs. the maintenance page (native blocks), these guidelines help maintain visual consistency and hierarchy across the site. - ---- - -## Typography & Hierarchy - -### Current Typography Issues - -The current typography hierarchy doesn't provide enough visual differentiation: - -- **H2** at `1.25rem` (xl) is too small for main section headings -- **H3** at `1.125rem` (lg) is barely larger than body text (1rem) -- **Line height** of `1.2` on headings feels cramped -- Not enough contrast between heading levels - -### Recommended Typography Scale - -```css -H1: 3xl (1.875rem) - Hero/page titles -H2: 3xl-4xl (1.875rem - 2.25rem) - Main section headers ⬆️ INCREASE -H3: 2xl (1.5rem) - Subsection headers ⬆️ INCREASE -H4: xl (1.25rem) - Card/feature titles -H5: lg (1.125rem) - Minor headings -H6: base (1rem) - Smallest headings - -Body: base (1rem) - Paragraph text -Line-height: 1.3-1.4 - Headings (improve from 1.2) -Line-height: 1.8 - Body text (current is good) -``` - -### Typography Implementation - -**Current app.css values:** -```css -h2 { - font-weight: 700; - font-size: var(--wp--preset--font-size--xl); /* 1.25rem - TOO SMALL */ - line-height: 1.2; /* TOO TIGHT */ -} - -h3 { - font-weight: 600; - font-size: var(--wp--preset--font-size--lg); /* 1.125rem - TOO SMALL */ - line-height: 1.3; -} -``` - -**Recommended changes:** -```css -h2 { - font-weight: 700; - font-size: var(--wp--preset--font-size--3xl); /* 1.875rem or 4xl: 2.25rem */ - line-height: 1.3; /* More breathing room */ -} - -h3 { - font-weight: 600; - font-size: var(--wp--preset--font-size--2xl); /* 1.5rem */ - line-height: 1.4; -} -``` - -### Font Weights for Emphasis - -Use font weights strategically from the Tailwind config: - -- **800-900 (extrabold/black)**: H1, major CTAs, hero text -- **700 (bold)**: H2, important statistics -- **600 (semibold)**: H3, button text, labels -- **500 (medium)**: H4, emphasized body text -- **400 (normal)**: Body paragraphs, lists - ---- - -## Color System & Contrast - -### Available Theme Colors - -From `theme.json` and `tailwind.config.js`: - -``` -Primary Colors: -- primary: #017cb6 (Brand Blue) -- primary-accent: #e6f4fb (Light Blue - backgrounds) -- primary-dark: #026492 (Dark Blue - CTAs) - -Neutral Colors: -- main: #171b23 (Near Black - dark sections) -- main-accent: #465166 (Dark Gray - body text) -- base: #ffffff (White - base) -- secondary: #98999a (Light Gray - subtle text) -- tertiary: #f5f5f6 (Very Light Gray - backgrounds) - -Borders: -- border-light: #ebeced -- border-dark: #cbcbcb -``` - -### Color Contrast Issues - -**Problem:** Too much white/light gray without enough visual breaks - -**Current paragraph color** (`secondary: #98999a`) is too light against white backgrounds, reducing readability. - -**Recommended text colors:** -- **Headings**: `main` (#171b23) - dark, strong contrast -- **Body text**: `main-accent` (#465166) - better readability than `secondary` -- **Subtle text**: `secondary` (#98999a) - only for captions, meta info -- **Links**: `primary` (#017cb6) with `primary-dark` on hover - -### Background Color Strategy - -Create visual rhythm by alternating section backgrounds: - -``` -Section 1: White (base) -Section 2: Light Blue (primary-accent: #e6f4fb) -Section 3: White (base) -Section 4: Dark Blue (primary-dark: #026492) with white text -Section 5: Near Black (main: #171b23) with white text -``` - -**Example WordPress block markup:** -```html - -
-

Section Title

-

Body text with good contrast

-
- - -
-

Section Title

-

Body text

-
- - -
-

Section Title

-

White text on dark background

-
-``` - ---- - -## Spacing & Rhythm - -### Vertical Spacing Issues - -Pages built with native blocks often lack consistent vertical rhythm and breathing room. - -### Recommended Spacing Scale - -**Between major sections:** -- Desktop: `padding-top: 4rem-6rem; padding-bottom: 4rem-6rem;` -- Mobile: `padding-top: 3rem-4rem; padding-bottom: 3rem-4rem;` - -**Between heading and body:** -- `margin-bottom: 2rem` on section headings -- `margin-bottom: 1.5rem` on subsection headings - -**Between content blocks:** -- Use WordPress Spacer blocks: `3rem-4rem` between distinct content areas -- `2rem` between related content (like list items and next paragraph) - -**Within cards/features:** -- `padding: 2rem` (mobile) to `3rem` (desktop) for card interiors -- `gap: 2rem` between columns - -### WordPress Block Spacing - -Use the block editor's spacing controls: - -``` -Group/Section blocks: -- Padding Top: 4rem (64px) -- Padding Bottom: 4rem (64px) -- Padding Left/Right: Handled by alignfull/constrained - -Heading blocks: -- Margin Bottom: 2rem (32px) for H2 -- Margin Bottom: 1.5rem (24px) for H3 - -Spacer blocks: -- Use 3rem-4rem between major sections -- Use 2rem between related content -``` - ---- - -## Visual Hierarchy Best Practices - -### Section Structure Template - -Every major section should follow this hierarchy: - -``` -1. Background color (alternating pattern) -2. Generous padding (4rem-6rem top/bottom) -3. Section heading (H2, 3xl-4xl size, main color) -4. Optional subheading/intro (larger paragraph, 1.5rem spacing below) -5. Content (cards, columns, lists) -6. Optional CTA button -``` - -### Card/Feature Design - -For feature cards and content boxes: - -```html -
-

Feature Title

-

Description text with good contrast

-
-``` - -**Design elements:** -- Border radius: `8px-12px` for modern feel -- Box shadow: `0 2px 8px rgba(0,0,0,0.08)` for subtle depth -- Hover effects: `transform: translateY(-5px)` with shadow increase -- Icon colors: Use `primary` blue for brand consistency - -### List Styling - -**Plain lists are visually weak.** Enhance with: - -- **Checkmark icons** before list items (use SVG or Unicode ✓) -- **Color the icons** with `primary` blue -- **Larger line height** (1.8-2.0) for scanning -- **Card backgrounds** for grouped lists - -```html - -``` - -Or add custom CSS for styled checkmarks: -```css -.feature-list li::before { - content: "✓"; - color: var(--color-primary); - font-weight: bold; - margin-right: 0.5rem; -} -``` - ---- - -## Component-Specific Guidelines - -### Testimonials / Success Stories - -**Visual hierarchy:** -1. Section background: `primary-accent` light blue -2. Quote cards: White background with `border-radius: 12px` -3. Box shadow: `0 4px 12px rgba(0,0,0,0.06)` -4. Quote text: Italic, `main-accent` color, 1.125rem (lg) -5. Author name: Bold, `primary` blue, 1rem -6. Company info: `secondary` gray, 0.875rem (sm) -7. Results/metrics: Bold, `primary-dark` or green color - -**Example structure:** -```html -
-

Client Success Stories

- -
-
-
-

- "Quote text here" -

-

Author Name

-

Company Info

-

- Results: Metric here -

-
-
-
-
-``` - -### Statistics Section - -**Make numbers the hero:** - -```html -
- -
-
-

850+

-

Sites Maintained

-

- Trusted across US & Europe -

-
-
-
-``` - -**Key principles:** -- Numbers: **5xl-7xl** (3rem - 4.5rem), bold (700-800 weight) -- Numbers color: `primary` or white (on dark backgrounds) -- Label text: 1rem-1.25rem, white or `main-accent` -- Subtext: 0.875rem (sm), `secondary` or muted white - -### Pricing Tables - -**Already styled in app.css** but ensure: - -- Badge visibility: Bright background (`primary-accent`), bold text -- Card hover effects: `transform: translateY(-5px)` with shadow -- Price emphasis: Large (2xl-3xl), bold, `primary` or `main` color -- Feature lists: Checkmarks, good spacing, clear hierarchy -- CTA buttons: High contrast, clear hover states - -### FAQ / Accordion Sections - -**Ensure readability:** - -- Question headings: H3 (2xl), semibold (600), `main` color -- Answer text: 1rem-1.125rem, `main-accent` color -- Spacing: 1.5rem-2rem between FAQ items -- Dividers: `border-light` color for separation -- Background: Alternate white and `tertiary` light gray - ---- - -## Page Audit Checklist - -Use this checklist when reviewing pages: - -### Typography ✓ -- [ ] H2 headings are 3xl-4xl (not xl) -- [ ] H3 headings are 2xl (not lg) -- [ ] Heading line-height is 1.3-1.4 -- [ ] Body text uses `main-accent` color (not `secondary`) -- [ ] Clear size differentiation between heading levels - -### Color & Contrast ✓ -- [ ] Alternating section backgrounds (white → accent → white → dark) -- [ ] Text has sufficient contrast against backgrounds -- [ ] Brand blue (`primary`) used consistently for CTAs and highlights -- [ ] Dark sections use white or light text -- [ ] Links use `primary` color with `primary-dark` hover - -### Spacing ✓ -- [ ] Major sections have 4rem-6rem top/bottom padding -- [ ] 2rem margin below section headings -- [ ] 3rem-4rem spacers between distinct content areas -- [ ] Cards/features have 2rem-3rem internal padding -- [ ] No cramped text blocks - -### Visual Elements ✓ -- [ ] Cards have border-radius (8px-12px) -- [ ] Subtle shadows on elevated elements -- [ ] Hover effects on interactive elements -- [ ] Icons/visuals use brand colors -- [ ] Lists use checkmarks or styling (not plain bullets) - -### Content Hierarchy ✓ -- [ ] Clear page flow: intro → features → social proof → CTA -- [ ] One clear primary CTA per section -- [ ] Statistics are large and prominent -- [ ] Testimonials have author attribution and metrics -- [ ] Each section has a clear purpose - ---- - -## Maintenance Page Specific Recommendations - -### Hero Section Improvements - -**Current:** "we keep your website secure, fast, and up-to-date" - -**Recommended options:** -- "Sleep Better. Your WordPress Site is Protected 24/7" -- "Enterprise-Grade WordPress Maintenance for Growing Businesses" -- "Never Worry About WordPress Updates, Security, or Backups Again" - -**Style:** -- Font size: 3xl-4xl (1.875rem - 2.25rem) -- Font weight: 700-800 -- Color: `main` on light background or white on dark -- Line height: 1.2-1.3 - -### "Why SMEs Need" Section - -**Content improvements:** -- Security Threats → "Hackers Target WordPress. We Stop Them." -- Technical Complexity → "We Handle the Tech. You Focus on Business." -- Time Investment → "Save 4+ Hours Every Month" -- Costly Downtime → "99.9% Uptime Guaranteed" - -**Style improvements:** -- H4 headings → Use H3 styling (2xl, semibold) -- Add icons above each heading (shield, gear, clock, chart) -- Card backgrounds: White with subtle shadow -- On hover: Lift effect with increased shadow - -### "Complete Coverage" Lists - -**Transform plain lists into visual features:** - -```html -
-
-
-

- 🛡️ Security & Protection -

-
    -
  • ✓ Real-time malware scanning
  • -
  • ✓ Security plugin management
  • - -
-
-
-
-``` - -### Success Stories Enhancement - -**Add specific metrics:** -- "Blocked 127 malware attempts in 2024" -- "Page load time: 4.2s → 1.8s (57% improvement)" -- "Prevented $15K in potential downtime losses" - -**Visual treatment:** -- Quote cards with `primary-accent` background -- Larger quote text (1.25rem, italic) -- Author name in bold `primary` color -- Metrics in bold `primary-dark` or green - -### Statistics Section Redesign - -**Make numbers huge:** -```html -

850+

-

Sites Maintained

-

Trusted by SMEs across US & Europe

-``` - -**Enhanced statistics:** -- 200+ Sites → **850+ Sites** (if accurate) -- 99.9% Uptime → **99.97% Actual Uptime** -- 0 Breaches → **Zero Breaches Since 2009** -- 2-Hour Response → **< 2 Hour Average Response** - ---- - -## Quick Implementation Wins - -Easiest high-impact changes to make first: - -1. **Typography**: Change H2 from xl to 3xl in WordPress editor -2. **Text color**: Update paragraphs from `secondary` to `main-accent` -3. **Backgrounds**: Add `primary-accent` background to every other section -4. **Padding**: Increase section padding from 2rem to 4rem -5. **Headings spacing**: Add 2rem margin-bottom to all H2 elements -6. **Card styling**: Add border-radius and box-shadow to feature cards -7. **List icons**: Add checkmarks to feature lists -8. **Statistics**: Increase number size from 2xl to 5xl-6xl - ---- - -## Resources - -**Theme files:** -- Colors: `site/web/app/themes/nynaeve/theme.json` (lines 58-69) -- Typography: `site/web/app/themes/nynaeve/resources/css/app.css` (lines 96-150) -- Tailwind config: `site/web/app/themes/nynaeve/tailwind.config.js` - -**WordPress editor:** -- Font sizes available: xs, sm, base, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, 8xl, 9xl -- Color palette: Primary, Primary Accent, Primary Dark, Main, Main Accent, Base, Secondary, Tertiary, Border Light, Border Dark - -**External references:** -- [WordPress Block Editor Spacing](https://wordpress.org/documentation/article/styles-overview/) -- [Tailwind CSS Typography Scale](https://tailwindcss.com/docs/font-size) -- [Material Design Elevation](https://material.io/design/environment/elevation.html) - for shadow inspiration - ---- - -## Implementation Phases - -This section documents the phased approach to implementing the style guide recommendations on the maintenance page and across the theme. - -### Phase 1: Navigation & Typography Fixes (COMPLETED) - -**Objective:** Fix navigation color issues and improve global typography hierarchy for better readability. - -#### Navigation Template Fix - -**Problem:** Navigation was using `text-secondary` (light gray #98999a) which had poor contrast on dark backgrounds. Additionally, Tailwind's `@layer base` was setting all anchor tags to `color: inherit`, overriding class-based colors. - -**Solution:** -1. **Updated navigation template** (`resources/views/components/navigation.blade.php`): - - Changed `text-secondary hover:text-white` → `text-white` (line 35) - - Changed submenu `text-sm text-secondary` → `text-sm text-white` (line 57) - -2. **Added CSS override** (`resources/css/app.css`): - ```css - /* Navigation links - override Tailwind base layer */ - #menu a { - color: #ffffff; - text-decoration: none; - } - ``` - -**Why both changes were needed:** -- Template change: Sets white color via Tailwind classes -- CSS override: Ensures anchor tags don't inherit from Tailwind's base layer -- Using `#menu` selector provides specificity without `!important` - -**Removed redundant CSS:** -```css -/* REMOVED - No longer needed */ -nav a, .navigation a, header a, footer a, .menu a, .wp-block-navigation a { - color: inherit !important; - text-decoration: inherit !important; -} - -#logo a.brand { - color: #ffffff !important; - text-decoration: none !important; -} -``` - -**Result:** -- ✅ Navigation text is crisp white with excellent contrast -- ✅ No `!important` declarations needed -- ✅ Cleaner, more maintainable code - -#### Typography Improvements - -**Problem:** Heading hierarchy was too flat with insufficient visual differentiation. - -**Changes made:** - -1. **H2 headings** (`app.css` line 104-110): - - Font size: `xl (1.25rem)` → `3xl (1.875rem)` (50% increase) - - Line height: `1.2` → `1.3` (better readability) - -2. **H3 headings** (`app.css` line 112-118): - - Font size: `lg (1.125rem)` → `2xl (1.5rem)` (33% increase) - - Line height: `1.3` → `1.4` (better readability) - -3. **Paragraph & list text color** (`app.css` lines 145-165): - - Changed from `secondary (#98999a)` → `main-accent (#465166)` - - Improved contrast ratio for better readability - -**Impact:** -- Section headings now have significantly stronger visual hierarchy -- Body text is more readable with improved color contrast -- Better spacing reduces visual cramping -- More professional, modern appearance across all pages - -#### Files Modified -- `resources/views/components/navigation.blade.php` (2 lines) -- `resources/css/app.css` (typography: 6 lines, navigation: 4 lines, cleanup: removed 15 lines) - ---- - -### Phase 2: Custom Blocks & Visual Enhancements - -**Objective:** Replace native block groups with reusable custom Sage Native Blocks that implement Phase 2 styling. This creates sustainable, reusable components for all secondary pages. - -**Strategy:** -- Build 2-3 new custom blocks using InnerBlocks approach (following existing patterns) -- Enhance existing 4 custom blocks with Phase 2 styling improvements -- Replace native WordPress group blocks with custom blocks -- Create reusable components for future secondary pages - -#### Current Maintenance Page Analysis - -**Existing Custom Blocks (4):** -1. **`imagewize/page-heading-blue`** - Hero section (already good) -2. **`imagewize/two-column-card`** - "Why SMEs Need" section -3. **`imagewize/pricing-tiers`** - Pricing comparison (3-column) -4. **`imagewize/multi-column-content`** - Statistics + CTAs - -**Native Block Groups (2):** -1. **"Complete WordPress Maintenance Coverage"** - Feature lists (5 categories) -2. **"WordPress Maintenance Success Stories"** - Testimonials (3 cards) - -#### 2.1 New Custom Blocks Needed - -**Block 1: Feature List Grid (for "Complete Coverage")** - -Replaces the native block group with 5 feature list categories. - -**Purpose:** Reusable feature showcase block for secondary pages - -**Structure (InnerBlocks template):** -```jsx -- Heading (H2) - Main section title -- Columns (2-col, stacks mobile) - - Column 1: - - Group (card 1): - - Heading (H4) with icon - - List (6 items with checkmarks) - - Group (card 2): - - Heading (H4) with icon - - List (6 items with checkmarks) - - Group (card 3): - - Heading (H4) with icon - - List (6 items with checkmarks) - - Column 2: - - Group (card 4): - - Heading (H4) with icon - - List (6 items with checkmarks) - - Group (card 5): - - Heading (H4) with icon - - List (6 items with checkmarks) -``` - -**Phase 2 Styling:** -- Background: `tertiary` (#f5f5f6) or white -- Padding: 5rem top/bottom -- Cards: White with border-radius 12px, subtle shadow -- Checkmarks: SVG via CSS (like pricing-tiers block) -- Heading underlines: Decorative primary blue accent -- Hover: Card lift effect - -**File structure:** -``` -resources/js/blocks/feature-list-grid/ -├── block.json -├── index.js -├── editor.jsx (InnerBlocks template) -├── save.jsx () -├── style.css (Phase 2 card styling) -├── editor.css -└── view.js -``` - -**Block 2: Testimonial Grid (for "Success Stories")** - -Replaces the native block group with 3 testimonial cards. - -**Purpose:** Reusable testimonial showcase for secondary pages - -**Structure (InnerBlocks template):** -```jsx -- Heading (H2) - "Client Success Stories" -- Columns (3-col, stacks mobile) - - Column (testimonial card 1): - - Paragraph (quote, italic, lg) - - Paragraph (author name, bold, primary color) - - Paragraph (company, sm, secondary color) - - Paragraph (results/metrics, bold, primary-dark) - - Column (testimonial card 2): [same] - - Column (testimonial card 3): [same] -``` - -**Phase 2 Styling:** -- Section background: `primary-accent` (#e6f4fb) -- Padding: 4rem top/bottom -- Cards: White, border-radius 12px, shadow -- Hover: translateY(-3px) with increased shadow -- Quote: Italic, 1.125rem (lg), main-accent color -- Author: Bold, primary blue -- Metrics: Bold, primary-dark color - -**File structure:** -``` -resources/js/blocks/testimonial-grid/ -├── block.json -├── index.js -├── editor.jsx (InnerBlocks template) -├── save.jsx () -├── style.css (Phase 2 card styling with hover) -├── editor.css -└── view.js -``` - -**Block 3 (Optional): Statistics Hero** - -Enhanced statistics block with dark background variant (alternative to modifying multi-column-content). - -**Purpose:** Dramatic statistics showcase for secondary pages - -**Structure (InnerBlocks template):** -```jsx -- Heading (H2) - Optional section title -- Columns (4-col, stacks 2x2 on tablet, single on mobile) - - Column (stat 1): - - Paragraph (number, 7xl, extrabold, primary or white) - - Paragraph (label, 2xl, semibold, white) - - Paragraph (subtext, sm, secondary) - - Column (stat 2-4): [same structure] -``` - -**Phase 2 Styling:** -- Background: `main` (#171b23) DARK -- Padding: 6rem top/bottom -- Numbers: 6xl-7xl size, weight 800, primary blue or white -- Labels: 2xl, weight 600, white -- Subtext: sm, secondary gray -- High contrast, bold typography - -**Decision:** Either create this OR enhance multi-column-content block with background options. - -#### 2.2 Enhancements to Existing Blocks - -**`imagewize/page-heading-blue`** - Already excellent, keep as-is ✓ - -**`imagewize/two-column-card`** - Minor styling tweaks - -**Current:** Good structure, needs Phase 2 polish - -**Enhancements:** -- Increase section padding: 4rem → 5rem top/bottom -- Add hover effect to cards (translateY + shadow) -- Ensure heading underline is primary blue -- Update default content with Phase 2 punchy headings - -**CSS changes (style.css):** -```css -/* Add hover effect */ -.two-column-card__card { - transition: transform 0.3s ease, box-shadow 0.3s ease; -} - -.two-column-card__card:hover { - transform: translateY(-3px); - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1); -} -``` - -**Template changes (editor.jsx):** -- Update heading content with punchier alternatives from Phase 2 -- Increase padding in block wrapper - -**`imagewize/pricing-tiers`** - Already has Phase 2 styling ✓ - -**Current:** Already implements checkmarks, shadows, hover effects - -**Minor enhancements:** -- Verify padding is 5rem top/bottom -- Ensure featured tier background is `primary-accent` (#e6f4fb) - -**`imagewize/multi-column-content`** - Needs dark variant option - -**Current:** Statistics + CTAs with white/bordered cards - -**Enhancement Options:** - -**Option A (Simpler):** Add CSS class variant for dark background -```css -/* Add to style.css */ -.multi-column-content.is-style-dark { - background-color: var(--wp--preset--color--main); - padding-top: 6rem; - padding-bottom: 6rem; -} - -.multi-column-content.is-style-dark .multi-column-content__main-heading { - color: var(--wp--preset--color--base); -} - -/* Enlarge statistic numbers */ -.multi-column-content__statistics .wp-block-heading { - font-size: var(--wp--preset--font-size--7-xl); - font-weight: 800; - line-height: 1; - color: var(--wp--preset--color--primary); -} -``` - -**Option B (Better):** Create separate `imagewize/statistics-hero` block with dark styling baked in - -**Recommendation:** Option A for speed, Option B for long-term reusability - -#### 2.3 Implementation Roadmap - -**Phase 2A: Create New Custom Blocks** (3-4 hours) - -1. **Create `imagewize/feature-list-grid` block** (1.5 hours) - ```bash - cd trellis - trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn sage-native-block:create - # Select "Generic Templates" or "Custom Templates" - # Or manually create following two-column-card pattern - ``` - - Build InnerBlocks template with 2 columns, 5 feature cards - - Add CSS for checkmarks (SVG like pricing-tiers) - - Add hover effects to cards - - Include real content from maintenance page - -2. **Create `imagewize/testimonial-grid` block** (1.5 hours) - - Build InnerBlocks template with 3 columns - - Add CSS for card shadows and hover - - Style quote/author/metrics typography - - Include real testimonials from maintenance page - -3. **Optional: Create `imagewize/statistics-hero` block** (1 hour) - - 4-column layout with huge numbers - - Dark background variant baked in - - 7xl numbers, white/primary blue colors - - OR skip and use Option A for multi-column-content - -**Phase 2B: Enhance Existing Blocks** (1-2 hours) - -4. **Enhance `imagewize/two-column-card`** (30 mins) - - Add hover effects to CSS - - Update default content with punchy headings - - Increase padding - -5. **Enhance `imagewize/multi-column-content`** (30 mins) - - Add dark variant CSS (Option A) - - OR skip if creating statistics-hero block - -6. **Verify `imagewize/pricing-tiers`** (15 mins) - - Check padding is 5rem - - Verify all Phase 2 styles present - -**Phase 2C: Replace Native Blocks on Maintenance Page** (30 mins) - -7. **Replace "Complete Coverage" section** - - Remove native Group blocks - - Insert `imagewize/feature-list-grid` block - - Verify content migrated correctly - -8. **Replace "Success Stories" section** - - Remove native Group blocks - - Insert `imagewize/testimonial-grid` block - - Verify testimonials migrated correctly - -9. **Update Statistics section** (if using dark variant) - - Apply dark style to multi-column-content block - - OR replace with statistics-hero block - - Enlarge numbers to 7xl - - Update content with Phase 2 improvements - -**Total Time: 4.5-6 hours** - -#### 2.4 Checkmark SVG Implementation (Reusable Pattern) - -Reference implementation from `imagewize/pricing-tiers` block: - -**CSS for SVG checkmarks (style.css):** -```css -/* Feature list checkmarks - SVG approach */ -.feature-list-grid__list { - list-style: none; - padding-left: 0; -} - -.feature-list-grid__list li { - position: relative; - padding-left: 2rem; - margin-bottom: 0.75rem; - line-height: 1.8; -} - -.feature-list-grid__list li::before { - content: ''; - position: absolute; - left: 0; - top: 0.35rem; - width: 1.25rem; - height: 1.25rem; - background-image: url('data:image/svg+xml;utf8,'); - background-size: contain; - background-repeat: no-repeat; -} -``` - -**Why SVG over Unicode:** -- Consistent rendering across browsers/fonts -- Precise color control (primary blue #017cb6) -- Scalable and crisp on all screens -- Follows existing pricing-tiers pattern - -**Apply to:** -- `imagewize/feature-list-grid` block (new) -- Keep existing implementation in `imagewize/pricing-tiers` block - -#### 2.5 Visual Design Reference - -**Alternating Section Backgrounds Pattern:** - -| Section | Block | Background | Padding | -|---------|-------|------------|---------| -| Hero | `imagewize/page-heading-blue` | Blue gradient | Built-in | -| Intro | Native Group | `primary-accent` (#e6f4fb) | 4rem | -| Why SMEs Need | `imagewize/two-column-card` | White / `tertiary` | 5rem | -| Complete Coverage | `imagewize/feature-list-grid` | White / `tertiary` | 5rem | -| Pricing | `imagewize/pricing-tiers` | White | 5rem | -| Success Stories | `imagewize/testimonial-grid` | `primary-accent` (#e6f4fb) | 4rem | -| Statistics | `imagewize/multi-column-content` (dark) or `imagewize/statistics-hero` | `main` (#171b23) **DARK** | 6rem | -| Final CTA | Native Group | `primary-dark` (#026492) **DARK** | 5rem | - -**Visual rhythm pattern:** -``` -Blue Gradient → Light Blue → White → White → White → Light Blue → Dark → Dark Blue -``` - -**Consistent Design Elements Across Blocks:** - -- **Card hover effects:** `translateY(-3px)` + shadow increase -- **Border radius:** 12px (0.75rem) for all cards -- **Box shadow:** `0 4px 12px rgba(0, 0, 0, 0.06)` default -- **Box shadow (hover):** `0 8px 20px rgba(0, 0, 0, 0.1)` -- **Checkmarks:** SVG with primary blue #017cb6 -- **Card padding:** 2.5rem - 3rem internal -- **Section padding:** 4-6rem top/bottom -- **Typography:** Montserrat headings, Open Sans body - -#### 2.6 Content Updates - -**Hero Tagline:** - -| Current | Recommended | -|---------|-------------| -| "we keep your website secure, fast, and up-to-date" | "Never Worry About WordPress Security, Updates, or Backups Again" | - -**Why:** -- Proper capitalization -- Direct benefit-focused -- Addresses specific pain points -- Action-oriented language - -**Statistics Content:** - -| Current | Updated | Reasoning | -|---------|---------|-----------| -| 200+ Sites Maintained | **850+ Sites Maintained** | Bigger number = more social proof (if accurate) | -| 99.9% Average Uptime | **99.97% Actual Uptime** | More specific = more credible | -| 0 Major Security Breaches | **Zero Breaches in 15+ Years** | Emphasizes impressive timeline | -| 2-Hour Average Response | **< 2 Hour Average Response** | "Under 2 hours" feels faster | - -**"Why SMEs Need" Section Headings:** - -| Current | Punchy Alternative | -|---------|-------------------| -| Security Threats | Hackers Target WordPress. We Stop Them. | -| Technical Complexity | We Handle the Tech. You Focus on Business. | -| Time Investment | Save 4+ Hours Every Month | -| Costly Downtime | 99.9% Uptime Guaranteed | - -#### Phase 2 Summary - -**Approach:** Custom Sage Native Blocks using InnerBlocks pattern - -**Time estimate:** 4.5-6 hours total - -**New blocks created:** 2-3 -1. `imagewize/feature-list-grid` - Feature showcase with checkmarks -2. `imagewize/testimonial-grid` - Professional testimonial cards -3. `imagewize/statistics-hero` (optional) - Dramatic stats with dark background - -**Existing blocks enhanced:** 3-4 -1. `imagewize/two-column-card` - Add hover effects, update content -2. `imagewize/multi-column-content` - Dark variant CSS (or skip if creating statistics-hero) -3. `imagewize/pricing-tiers` - Verification only -4. `imagewize/page-heading-blue` - Keep as-is ✓ - -**Benefits of custom blocks approach:** -- **Reusable** - Use on other secondary pages (About, Services, etc.) -- **Maintainable** - Update block CSS affects all instances -- **Consistent** - Phase 2 styling baked into blocks -- **Flexible** - Users can still edit content via WordPress editor -- **Professional** - Hover effects, shadows, typography all built-in - -**Expected outcome:** -- Dramatically improved visual appeal with reusable components -- Professional, modern aesthetic across all secondary pages -- Better content hierarchy baked into blocks -- Increased trust and credibility -- Higher conversion potential -- Sustainable codebase for long-term maintenance - ---- - -## Implementation Checklist - Phase 2 - -Use this when implementing Phase 2 with custom blocks: - -### Phase 2A: Create New Custom Blocks ✓ - -**`imagewize/feature-list-grid` Block:** -- [ ] Created block using `wp acorn sage-native-block:create` -- [ ] Built InnerBlocks template with 2 columns, 5 feature cards -- [ ] Added checkmark SVG CSS (following pricing-tiers pattern) -- [ ] Added card hover effects (translateY + shadow) -- [ ] Added heading underline decoration (primary blue) -- [ ] Included real maintenance page content in template -- [ ] Tested in WordPress editor -- [ ] Verified mobile responsiveness (stacks to single column) - -**`imagewize/testimonial-grid` Block:** -- [ ] Created block using `wp acorn sage-native-block:create` -- [ ] Built InnerBlocks template with 3 columns -- [ ] Added CSS for card shadows and hover effects -- [ ] Styled quote typography (italic, lg, main-accent) -- [ ] Styled author name (bold, primary blue) -- [ ] Styled company info (sm, secondary) -- [ ] Styled metrics/results (bold, primary-dark) -- [ ] Included real testimonials in template -- [ ] Tested in WordPress editor -- [ ] Verified mobile responsiveness - -**`imagewize/statistics-hero` Block (Optional):** -- [ ] Created block OR decided to use multi-column-content dark variant -- [ ] Built 4-column layout with huge numbers -- [ ] Added dark background (#171b23) styling -- [ ] Sized numbers to 7xl, weight 800 -- [ ] Colored numbers primary blue or white -- [ ] Added padding 6rem top/bottom -- [ ] Tested in WordPress editor - -### Phase 2B: Enhance Existing Blocks ✓ - -**`imagewize/two-column-card` Enhancements:** -- [ ] Added hover effect CSS (translateY + shadow) -- [ ] Updated default content with Phase 2 punchy headings -- [ ] Increased section padding to 5rem -- [ ] Verified heading underline is primary blue -- [ ] Tested changes in WordPress editor - -**`imagewize/multi-column-content` Enhancements:** -- [ ] Added dark variant CSS (if not creating statistics-hero) -- [ ] Increased statistic number sizes to 7xl -- [ ] Added padding 6rem for dark variant -- [ ] Tested dark variant in WordPress editor - -**`imagewize/pricing-tiers` Verification:** -- [ ] Verified padding is 5rem top/bottom -- [ ] Confirmed featured tier background is `primary-accent` -- [ ] Confirmed checkmarks are displaying correctly -- [ ] Confirmed hover effects are working - -### Phase 2C: Update Maintenance Page ✓ - -**Replace Native Blocks:** -- [ ] Removed "Complete Coverage" native Group blocks -- [ ] Inserted `imagewize/feature-list-grid` block -- [ ] Migrated all 5 feature categories with content -- [ ] Verified checkmarks display correctly -- [ ] Removed "Success Stories" native Group blocks -- [ ] Inserted `imagewize/testimonial-grid` block -- [ ] Migrated all 3 testimonials with content -- [ ] Verified card styling and hover effects - -**Update Statistics Section:** -- [ ] Applied dark style to multi-column-content OR replaced with statistics-hero -- [ ] Enlarged numbers to 7xl -- [ ] Updated content with Phase 2 statistics (850+ sites, 99.97% uptime, etc.) -- [ ] Verified contrast on dark background - -**Content Updates:** -- [ ] Updated hero tagline (if desired) -- [ ] Updated "Why SMEs Need" headings with punchier alternatives (optional) -- [ ] Updated statistics numbers and labels -- [ ] Verified all content is accurate - -**Final Verification:** -- [ ] Tested all blocks on mobile (≤782px) -- [ ] Tested all hover effects -- [ ] Verified alternating background rhythm -- [ ] Checked section padding consistency -- [ ] Ran `npm run build` for production assets -- [ ] Tested on staging environment -- [ ] Published to production diff --git a/docs/PATTERN-TO-ACF-BLOCK.md b/docs/PATTERN-TO-ACF-BLOCK.md deleted file mode 100644 index 2badd0d..0000000 --- a/docs/PATTERN-TO-ACF-BLOCK.md +++ /dev/null @@ -1,430 +0,0 @@ -# Converting Moiraine Patterns to ACF Composer Blocks - -## Overview - -This document outlines the process for converting PHP/CSS patterns from the Moiraine theme to ACF Composer blocks in Nynaeve. This approach is superior to pure WordPress block patterns because: - -- **Preserves Styling**: Maintains the polished CSS and design from Moiraine patterns -- **Avoids Parser Issues**: Bypasses Gutenberg markup parser complexities and freeform block problems -- **Dynamic Content**: Provides proper UI for content editing via ACF fields -- **Better UX**: Clean field interface instead of editing block markup -- **Consistent Architecture**: Matches existing ACF Composer blocks in Nynaeve - -## Source Patterns (Moiraine) - -Located at: `~/code/moiraine/patterns/` - -Priority patterns to convert: -1. **Content Image Text** - Image and text card layout -2. **Hero CTA** - Hero section with call-to-action -3. **Blog Grid** - Grid layout for blog posts/content -4. **Testimonial Card** - Testimonial display - -## Conversion Process - -### Step 1: Analyze Moiraine Pattern - -1. Open the source pattern file in `~/code/moiraine/patterns/` -2. Identify: - - Dynamic content areas (what should be ACF fields) - - Static styling and layout structure - - CSS classes and custom styles - - Image requirements and text areas - - Button/link functionality - -### Step 2: Create ACF Composer Block - -**Command:** -```bash -# From Trellis VM (using --workdir for single command) -trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn acf:block BlockName - -# OR from interactive VM shell -cd /srv/www/imagewize.com/current/web/app/themes/nynaeve -wp acorn acf:block BlockName -``` - -**Note:** ACF Composer blocks contain their own field definitions, so you don't need to create a separate field group file. The `wp acorn acf:block` command creates both the block class and Blade template. - -**Files created:** -- `app/Blocks/BlockName.php` - Block controller with field definitions -- `resources/views/blocks/block-name.blade.php` - Blade template - -**Important:** ACF Composer v3.0.19+ automatically generates `block.json` files when you run `wp acorn acf:cache`. These are cached at `web/app/cache/acorn/framework/cache/acf-composer/blocks/` and contain all block metadata from your PHP properties. You do NOT need to manually create `block.json` files - just define everything in your PHP class properties. - -### Step 3: Define Fields in Block Class - -**Location:** `app/Blocks/BlockName.php` (already created in Step 2) - -Edit the generated block file to: -- Configure block metadata (name, description, category, icon, keywords) -- Define fields in the `fields()` method using Builder -- Configure block supports (alignment, spacing, colors, etc.) -- Add field processing logic in the `with()` method -- **IMPORTANT**: Add default content that loads on both frontend and backend for quick testing and better client experience - -**Example field definition in the `fields()` method:** -```php -public function fields(): array -{ - $fields = Builder::make('content_card'); - - $fields - ->addImage('image', [ - 'label' => 'Card Image', - 'return_format' => 'array', - 'preview_size' => 'medium', - ]) - ->addText('heading', [ - 'label' => 'Heading', - 'default_value' => 'Card Title', - ]) - ->addTextarea('body_text', [ - 'label' => 'Body Text', - 'rows' => 4, - ]) - ->addLink('button', [ - 'label' => 'Button Link', - 'return_format' => 'array', - ]); - - return $fields->build(); -} -``` - -**Default Content in `with()` Method:** - -Always provide default content that appears on both frontend and backend. This allows for quick testing and gives clients working placeholder content: - -```php -public function with(): array -{ - // Get field values - $image = get_field('image') ?: []; - $heading = get_field('heading') ?: ''; - $body_text = get_field('body_text') ?: ''; - $button = get_field('button') ?: null; - - // Default values (for both preview and frontend) - if (empty($heading)) { - $heading = 'Card Title'; - } - if (empty($body_text)) { - $body_text = 'Add your descriptive text here. This placeholder helps you visualize the layout.'; - } - - // Handle image with default - $image_url = is_array($image) ? ($image['url'] ?? null) : null; - $image_alt = is_array($image) ? ($image['alt'] ?? '') : ''; - - if (empty($image_url)) { - $image_url = Vite::asset('resources/images/placeholder.jpg'); - $image_alt = 'Placeholder image'; - } - - // Default button if not set - if (empty($button) || !is_array($button) || empty($button['url'])) { - $button = [ - 'url' => '#', - 'title' => 'Learn More', - 'target' => '', - ]; - } - - return [ - 'image_url' => $image_url, - 'image_alt' => $image_alt, - 'heading' => $heading, - 'body_text' => $body_text, - 'button' => $button, - ]; -} -``` - -**Benefits of Default Content:** -- Blocks render immediately with sensible placeholder content -- Easier to test layouts and styling -- Better user experience - clients see working examples -- Faster development workflow - -### Step 4: Edit Block Template - -**Location:** `resources/views/blocks/block-name.blade.php` (already created in Step 2) - -**Process:** -1. Copy HTML structure from Moiraine pattern -2. Replace hardcoded content with variables from the `with()` method: - - `{{ $field_name }}` for text - - `{!! $wysiwyg_field !!}` for HTML content - - `{{ $image_alt }}` -3. Preserve all CSS classes from Moiraine -4. Use `{!! $attributes !!}` for WordPress block wrapper classes - -**Example:** -```blade -
- @if($image) -
- {{ $image['alt'] }} -
- @endif - -
- @if($heading) -

{{ $heading }}

- @endif - - @if($content) -
{!! $content !!}
- @endif - - @if($button) - - {{ $button['title'] }} - - @endif -
-
-``` - -### Step 5: Port CSS Styles and Handle Alignment - -**Location:** `resources/css/blocks/block-name.css` - -1. Create new CSS file in `resources/css/blocks/` directory -2. Copy CSS from Moiraine pattern's stylesheet -3. Adapt to use WordPress CSS variables (e.g., `var(--wp--preset--spacing--large)`) -4. **IMPORTANT: Match font sizes to Moiraine pattern using theme presets** (see below) -5. Maintain BEM naming convention for classes -6. Add responsive styles -7. **IMPORTANT: Handle alignment explicitly in CSS** (see below) -8. Enqueue the CSS in the block's `assets()` method - -```php -public function assets(array $block): void -{ - wp_enqueue_style( - 'block-name', - get_template_directory_uri().'/resources/css/blocks/block-name.css', - [], - null - ); -} -``` - -**Critical: Font Size Matching** - -When converting Moiraine patterns, use browser DevTools or Playwright to compare computed font sizes, line heights, and button dimensions between the Moiraine pattern and your ACF block. Always use theme font size presets (`--wp--preset--font-size--*`) instead of hardcoded pixel values: - -**Available theme font size presets** (see `resources/css/app.css`): -- `--wp--preset--font-size--xs`: 0.75rem (12px) -- `--wp--preset--font-size--sm`: 0.875rem (14px) -- `--wp--preset--font-size--base`: 1rem (16px) -- `--wp--preset--font-size--lg`: 1.125rem (18px) -- `--wp--preset--font-size--xl`: 1.25rem (20px) -- `--wp--preset--font-size--2xl`: 1.5rem (24px) -- `--wp--preset--font-size--3xl`: 1.875rem (30px) -- `--wp--preset--font-size--4xl`: 2.25rem (36px) -- `--wp--preset--font-size--5xl`: 3rem (48px) - -**Example comparison workflow:** -```javascript -// Use Playwright or browser DevTools to compare styles -// Moiraine pattern styles: -{ - heading: { fontSize: "25.94px", lineHeight: "38.91px" }, - body: { fontSize: "18.47px", lineHeight: "27.71px" }, - button: { fontSize: "18.47px", height: "44.93px" } -} - -// Match to closest theme presets in your CSS: -.block-heading { - font-size: var(--wp--preset--font-size--2xl, 1.5rem); /* 24px, close to 25.94px */ - line-height: 1.5; /* ~36px at 24px font, adjust to match */ -} - -.block-body { - font-size: var(--wp--preset--font-size--lg, 1.125rem); /* 18px, matches 18.47px */ - line-height: 1.55; -} - -.block-button { - font-size: var(--wp--preset--font-size--lg, 1.125rem); /* 18px */ - padding: 0.7em 1em; /* Adjust padding to achieve target height */ -} -``` - -**Benefits:** -- Maintains consistency with theme design system -- Easier to maintain and adjust globally -- Respects user's font size preferences -- Better accessibility - -**Critical: Alignment Handling** - -ACF Composer blocks need explicit CSS to handle WordPress alignment classes. Unlike native WordPress blocks or patterns wrapped in Group blocks, ACF blocks don't automatically get `is-layout-constrained` class behavior. You must handle alignment in your CSS: - -```css -/* Default: constrained to content width */ -.your-block-class { - max-width: var(--wp--style--global--content-size, 880px); - margin-left: auto; - margin-right: auto; - width: 100%; -} - -/* Wide alignment */ -.your-block-class.alignwide { - max-width: var(--wp--style--global--wide-size, 1260px); -} - -/* Full alignment */ -.your-block-class.alignfull { - max-width: none; - margin-left: 0; - margin-right: 0; -} -``` - -**Block Configuration for Alignment:** - -In your block's `$supports` array, enable alignment: - -```php -public $supports = [ - 'align' => ['wide', 'full'], // Enables wide and full alignment options - 'anchor' => true, - 'mode' => true, - 'multiple' => true, - 'jsx' => false, - 'color' => [ - 'background' => true, - 'text' => true, - ], - 'spacing' => [ - 'padding' => true, - 'margin' => true, - ], -]; -``` - -**Template Considerations:** - -Use `$attributes->merge()` in your Blade template to properly combine WordPress classes with your custom class: - -```blade -
merge(['class' => 'your-block-class']) !!}> - {{-- Block content --}} -
-``` - -This ensures WordPress alignment classes (`.alignwide`, `.alignfull`, `.alignnone`) are properly added to your block element. - -### Step 6: Test and Refine - -1. **Cache ACF Fields:** - ```bash - # From Trellis VM - trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn acf:cache - - # This will discover and cache your new block - ``` - -2. **Test in Block Editor:** - - Insert block and verify it appears - - Fill in all fields and preview - - Test different content variations - - Check responsive layouts - - Verify in frontend - -3. **Refinements:** - - Adjust field settings (required, conditional logic) - - Fine-tune CSS and spacing - - Add field validation if needed - - Add block preview/example - -### Step 7: Documentation - -Update block documentation: -- Add to `CLAUDE.md` if significant -- Document field structure and options -- Note any special requirements or limitations -- Add screenshots/examples if helpful - -## Conversion Checklist - -For each pattern conversion: - -- [ ] Analyze Moiraine pattern structure and styling -- [ ] Create ACF Composer block (`wp acorn acf:block BlockName`) -- [ ] Define fields in block's `fields()` method with proper types -- [ ] Configure block metadata (name, category, icon, keywords) -- [ ] Add field processing logic in block's `with()` method -- [ ] Edit Blade template with Moiraine HTML structure -- [ ] Replace hardcoded content with variables from `with()` method -- [ ] Create CSS file in `resources/css/blocks/` directory -- [ ] Port CSS styles from Moiraine (adapt to WordPress CSS variables) -- [ ] Enqueue CSS in block's `assets()` method -- [ ] Cache ACF fields (`wp acorn acf:cache`) -- [ ] Test in block editor with various content -- [ ] Test responsive layouts -- [ ] Verify frontend rendering -- [ ] Add field validation if needed -- [ ] Document any special notes - -## Pattern-Specific Notes - -### Content Image Text Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/content-image-text.php` -- **Fields Needed:** Image, heading, content (WYSIWYG), button link -- **Layout Options:** Image left/right, alignment variations -- **Styling:** Card with shadow, rounded corners, responsive image - -### Hero CTA Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/hero-cta.php` -- **Fields Needed:** Background image, heading, subheading, CTA buttons (multiple) -- **Layout Options:** Text alignment, overlay opacity, height variations -- **Styling:** Full-width hero with background image, gradient overlay - -### Blog Grid Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/blog-grid.php` -- **Fields Needed:** Post selection/query, grid columns, show excerpts -- **Layout Options:** 2/3/4 column layouts, card styles -- **Styling:** Responsive grid with post cards - -### Testimonial Card Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/testimonial-card.php` -- **Fields Needed:** Quote text, author name, author title, author image, rating -- **Layout Options:** Card variations, with/without image -- **Styling:** Quote styling, author attribution, star ratings - -## Benefits Summary - -| Aspect | Block Patterns | ACF Composer Blocks | -|--------|---------------|---------------------| -| Styling | Lost in conversion | Fully preserved | -| Content Editing | Edit block markup | Clean field interface | -| Parser Issues | Yes (tight tags, freeform blocks) | None | -| Dynamic Content | Limited | Full PHP/ACF power | -| Maintainability | Difficult | Easy to update | -| User Experience | Complex | Intuitive | -| Consistent with Theme | No | Yes (existing ACF blocks) | - -## Resources - -- **ACF Composer Documentation:** https://github.com/Log1x/acf-composer -- **Moiraine Patterns:** `~/code/moiraine/patterns/` -- **Nynaeve ACF Blocks:** `site/web/app/themes/nynaeve/app/Blocks/` -- **Nynaeve ACF Fields:** `site/web/app/themes/nynaeve/app/Fields/` -- **Nynaeve Block Templates:** `site/web/app/themes/nynaeve/resources/views/blocks/` -- **WordPress ACF Documentation:** https://www.advancedcustomfields.com/resources/ - -## Next Steps - -1. Start with **Content Image Text** pattern (simplest) -2. Create as proof of concept -3. Refine workflow based on learnings -4. Convert remaining 3 priority patterns -5. Consider converting any other useful Moiraine patterns \ No newline at end of file diff --git a/docs/PATTERN-TO-NATIVE-BLOCK.md b/docs/PATTERN-TO-NATIVE-BLOCK.md deleted file mode 100644 index 90da5eb..0000000 --- a/docs/PATTERN-TO-NATIVE-BLOCK.md +++ /dev/null @@ -1,1316 +0,0 @@ -# Converting Moiraine Patterns to Sage Native Blocks - -## Overview - -This document outlines the process for converting PHP/CSS patterns from the Moiraine theme to React/JavaScript blocks using the **`imagewize/sage-native-block`** package in Nynaeve. This approach is superior to ACF Composer blocks when you need: - -- **Native WordPress Controls**: Font size picker, font family selector, typography controls -- **Button Variants**: Easy size/style variants (small, medium, large, outline, solid) -- **Better UX**: Familiar WordPress block controls instead of ACF field sidebars -- **Design System Integration**: Direct use of theme.json settings (colors, spacing, typography) -- **More Maintainable**: Standard WordPress block patterns and component structure -- **Full Customization**: Complete control over styling, typography, and layout options - -## When to Use Sage Native Blocks vs ACF Composer - -### Use Sage Native Blocks When: -- You need customizable typography (font sizes, font families) -- You need button size/style variants -- You want native WordPress block toolbar controls -- You need complex styling options exposed to users -- The block requires dynamic frontend JavaScript - -### Use ACF Composer Blocks When: -- You need complex custom field types (repeaters, relationships, etc.) -- Server-side rendering is critical -- The block is primarily content-focused with minimal styling options -- You prefer PHP/Blade templating over React - -## InnerBlocks vs Custom Controls Architecture - -**PREFERRED APPROACH: Use InnerBlocks with Native WordPress Blocks** - -When creating Sage Native Blocks, prioritize using WordPress's native InnerBlocks system over custom controls whenever possible. This approach provides: - -### Benefits of InnerBlocks Architecture: -- **Cleaner Sidebar**: No inspector controls cluttering the sidebar -- **Direct Editing**: Edit content directly in the editor using familiar WordPress controls -- **Native Block Controls**: Each element uses its own toolbar controls (image, heading, paragraph, button blocks) -- **Modular Design**: Each component maintains its own settings and functionality -- **Better UX**: Users can focus on content without navigating complex sidebar panels -- **Consistency**: Leverages WordPress's existing block patterns and behaviors - -### When to Use InnerBlocks: -- **Content-focused blocks** where structure is more important than complex settings -- **Card layouts** with image + heading + paragraph + buttons -- **Hero sections** with background + heading + paragraph + buttons -- **Multi-component blocks** that can be broken into logical native block pieces -- **Layout blocks** that primarily arrange other content types - -### When to Use Custom Controls: -- **Complex styling options** that native blocks don't provide -- **Advanced layout controls** (grid configurations, animations, etc.) -- **Settings that affect the entire block** (alignment, spacing between sections) -- **Custom functionality** not available in native blocks - -### InnerBlocks Implementation Example: - -```jsx -// PREFERRED: InnerBlocks approach -import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; - -export default function Edit() { - const blockProps = useBlockProps({ - className: 'image-text-card', - }); - - const TEMPLATE = [ - ['core/image', { className: 'image-text-card__image' }], - ['core/group', { className: 'image-text-card__content' }, [ - ['core/heading', { level: 3, placeholder: 'Card title...' }], - ['core/paragraph', { placeholder: 'Card description...' }], - ]], - ['core/group', { className: 'image-text-card__buttons', layout: { type: 'flex' } }, [ - ['core/button', { text: 'Primary Action' }], - ['core/button', { text: 'Secondary Action' }], - ]], - ]; - - return ( -
- -
- ); -} -``` - -```jsx -// Save component for InnerBlocks -import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; - -export default function Save() { - const blockProps = useBlockProps.save({ - className: 'image-text-card', - }); - - return ( -
- -
- ); -} -``` - -### InnerBlocks Configuration Options: - -- **`template`**: Predefined structure with default content and settings -- **`templateLock`**: - - `"all"`: Users can edit content but not add/remove/move blocks - - `"insert"`: Users can't add/remove blocks but can move them - - `false`: Full flexibility to add/remove/move blocks -- **`allowedBlocks`**: Restrict which block types can be used -- **`orientation`**: `"vertical"` (default) or `"horizontal"` layout - -## Source Patterns (Moiraine) - -Located at: `~/code/moiraine/patterns/` - -Priority patterns to convert: -1. **Content Image Text** - Image and text card layout ✓ (Completed as native block) -2. **Hero CTA** - Hero section with call-to-action -3. **Blog Grid** - Grid layout for blog posts/content -4. **Testimonial Card** - Testimonial display - -## Consistency Requirements Across All Blocks - -**These requirements came from comparing content-image-text-card with existing blocks (related-articles, faq, pricing):** - -### 1. Textdomain Must Be "imagewize" -- **Wrong**: `"textdomain": "sage"` -- **Correct**: `"textdomain": "imagewize"` -- **Why**: Enables proper internationalization and matches all other blocks - -### 2. className Attribute Required -All blocks MUST include this attribute: -```json -"className": { - "type": "string", - "default": "wp-block-imagewize-block-name" -} -``` -**Why**: Ensures WordPress properly adds the block wrapper class for consistent styling and JavaScript targeting - -### 3. Default Alignment Strategy -- **Don't set** `"default": "full"` in attributes unless you want the block to always start wide/full-width -- **Omit default alignment** for normal content-width blocks (like content-image-text-card) -- **Set default alignment** for full-width blocks (like faq, pricing) - -### 4. Translation String Consistency -When using `__()` for translations: -- In blocks with `"textdomain": "imagewize"`, use: `__('Text', 'imagewize')` -- Update existing `__('Text', 'sage')` to `__('Text', 'imagewize')` - -## Critical Missing Information - -### 1. Block Naming Conventions - -**Use short class names in your CSS:** -- Block class names should match the pattern: `.block-name` (not `.wp-block-namespace-block-name`) -- WordPress automatically adds the full block class `.wp-block-namespace-block-name` to the wrapper -- Use shorter class names in your CSS for cleaner, more maintainable code -- Example: For `imagewize/content-image-text-card`, use `.image-text-card` not `.wp-block-imagewize-content-image-text-card` -- Only use the full WordPress class in `editor.css` for editor-specific styles - -### 2. Required Dependencies - -**Install @wordpress/icons package:** -```bash -cd site/web/app/themes/nynaeve -npm install @wordpress/icons --save-dev -``` - -This package is required if you use toolbar icons from `@wordpress/icons`. - -### 3. block.json Configuration Additions - -**Always include these fields:** -```json -{ - "version": "1.0.0", // For cache busting - "example": {}, // Enables block preview in inserter - "viewScript": "file:./view.js", // Even if not used initially - "textdomain": "imagewize", // MUST be "imagewize" not "sage" for consistency - "supports": { - "html": false // Prevent users from editing HTML directly - }, - "attributes": { - "className": { - "type": "string", - "default": "wp-block-imagewize-block-name" // REQUIRED for proper WordPress styling - } - // ... other attributes - } -} -``` - -**Critical Configuration Requirements:** -1. **textdomain**: Must be `"imagewize"` (not `"sage"`) to match other blocks and enable proper translations -2. **className attribute**: Required for WordPress to properly apply block wrapper classes and styling -3. **Default alignment**: Do NOT set a default alignment unless you want the block to always start wide/full. Omit for normal content-width default. - -**Button target attributes:** -- Use string type, not boolean: `"type": "string"` -- Default to empty string: `"default": ""` -- Store as `"_blank"` or `""` (not `true`/`false`) - - -### 4. Editor Component Best Practices - -**Import all needed components:** -```jsx -import { - useBlockProps, - RichText, - MediaUpload, - MediaUploadCheck, // Always wrap MediaUpload - InspectorControls, // Sidebar controls - BlockControls // Toolbar controls -} from '@wordpress/block-editor'; - -import { - PanelBody, - Button, - SelectControl, - TextControl, - ToggleControl, // For boolean toggles - ToolbarGroup, // For toolbar - ToolbarButton // For toolbar buttons -} from '@wordpress/components'; - -import { __ } from '@wordpress/i18n'; -import { image } from '@wordpress/icons'; // Requires @wordpress/icons package -``` - -**MediaUpload must be wrapped:** -```jsx - - ( - - )} - /> - -``` - -**Add BlockControls for toolbar:** -```jsx - - - - ( - - )} - /> - - - -``` - -**ToggleControl for "open in new tab":** -```jsx - setAttributes({ primaryButtonTarget: value ? '_blank' : '' })} -/> -``` - -### 5. Save Component Critical Details - -**Always use fallbacks for optional attributes:** -```jsx -// Default image fallback -const displayImageUrl = imageUrl || '/app/themes/nynaeve/resources/images/placeholder.jpg'; - -// Default href fallback -href={primaryButtonUrl || '#'} - -// Default alt text fallback -alt={imageAlt || 'Card image'} -``` - -**Conditional rendering for optional sections:** -```jsx -// Only render if has content -{displayImageUrl && ( -
- {imageAlt -
-)} - -// Only render buttons if text exists (URL is optional) -{primaryButtonText && ( - - {primaryButtonText} - -)} -``` - -**External link security:** -```jsx -{...(primaryButtonTarget && { - target: primaryButtonTarget, - rel: 'noopener noreferrer' -})} -``` - -### 6. CSS Best Practices - -**Target Native WordPress Blocks in InnerBlocks:** -```css -/* Style native blocks within your container */ -.image-text-card .wp-block-image img { - width: 100%; - border-radius: 3px; -} - -.image-text-card .wp-block-heading { - font-size: var(--wp--preset--font-size--2-xl, 1.5rem); - margin: 0 0 var(--wp--preset--spacing--small, 1rem) 0; -} - -.image-text-card .wp-block-paragraph { - margin: 0 0 var(--wp--preset--spacing--medium, 2rem) 0; -} - -.image-text-card .wp-block-button .wp-block-button__link { - border-radius: 5px; - padding: 0.7em 1em; -} - -/* Container styling - buttons use WordPress style variants selectable in block toolbar */ -.image-text-card .image-text-card__buttons { - display: flex; - gap: var(--wp--preset--spacing--small, 1rem); - flex-wrap: wrap; -} - -/* Note: Individual button styles are controlled via WordPress button style variants */ -/* Users can select: Default, Outline, Secondary Button, Light Button, Dark Button */ -/* Button styles are defined globally in app.css and available theme-wide */ -``` - -**Use theme CSS custom properties:** -```css -/* Font sizes from theme.json */ -font-size: var(--wp--preset--font-size--2-xl, 1.5rem); - -/* Colors from theme.json */ -background-color: var(--wp--preset--color--main, #1E1E26); - -/* Spacing from theme.json */ -padding: var(--wp--preset--spacing--large, 3rem); -gap: var(--wp--preset--spacing--small, 1rem); - -/* Layout sizes from theme.json */ -max-width: var(--wp--style--global--content-size, 55rem); -``` - -**Alignment support:** -```css -/* Default: constrained to content width */ -.image-text-card { - max-width: var(--wp--style--global--content-size, 55rem); - margin-left: auto; - margin-right: auto; - width: 100%; -} - -/* Wide alignment */ -.image-text-card.alignwide { - max-width: var(--wp--style--global--wide-size, 64rem); -} - -/* Full alignment */ -.image-text-card.alignfull { - max-width: none; - margin-left: 0; - margin-right: 0; -} -``` - -### 7. Editor CSS Additions - -**Use full WordPress class for editor-only styles:** -```css -/* Editor-only border to make block visible */ -.wp-block-imagewize-content-image-text-card { - border: 2px dashed #007cba; -} - -/* Disable interactions in editor */ -.editor-styles-wrapper .image-text-card__button { - pointer-events: none; -} - -/* Style placeholder content */ -.wp-block-imagewize-content-image-text-card p:first-of-type { - color: #757575; - font-style: italic; -} -``` - -### 8. Development Workflow - -**Trellis VM Requirements:** -1. All `wp acorn` commands must run from Trellis VM (database access required) -2. Access site via HTTP (`http://imagewize.test/`) not HTTPS for HMR to work -3. If local database server is running, it will conflict with VM port 3306 - -**Testing checklist additions:** -- [ ] Test default placeholder image/content displays -- [ ] Test buttons without URLs (should default to `#`) -- [ ] Test "open in new tab" functionality -- [ ] **Re-save existing blocks in editor** to apply save.jsx fixes -- [ ] Test toolbar controls (quick image change) -- [ ] Verify MediaUploadCheck permissions work correctly - -## Conversion Process - -### Step 1: Analyze Moiraine Pattern - -1. Open the source pattern file in `~/code/moiraine/patterns/` -2. Identify: - - Dynamic content areas (what should be block attributes) - - Static styling and layout structure - - CSS classes and custom styles - - Image requirements and text areas - - Button/link functionality - - Typography requirements (font sizes, families, weights) - - Color scheme options - - Spacing/layout variations - -### Step 2: Create Sage Native Block - -**Command:** -```bash -# From Trellis VM -cd trellis -trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn sage-native-block:create - -# Interactive template selection - choose from: -# 1. Basic Block - Simple default block -# 2. Generic Templates - InnerBlocks, two-column, statistics, CTAs -# 3. Nynaeve Templates - Production-ready examples from this theme -# 4. Custom Templates - Auto-detected from block-templates/ directory -``` - -**Files created:** -``` -resources/js/blocks/block-name/ -├── block.json # Block configuration and attributes -├── index.js # Block registration -├── editor.jsx # Editor component (React) -├── save.jsx # Save component (React) - frontend markup -├── style.css # Frontend styles -├── editor.css # Editor-specific styles -└── view.js # Frontend JavaScript (optional, for interactivity) -``` - -**Automatic registration:** The block is automatically registered via `ThemeServiceProvider.php` - no manual registration needed. - -### Step 3: Configure block.json - -**Location:** `resources/js/blocks/block-name/block.json` - -Configure block metadata and attributes: - -```json -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 3, - "name": "imagewize/content-image-text-card", - "version": "1.0.0", - "title": "Content Image Text Card", - "category": "text", - "icon": "index-card", - "description": "A card with image, heading, body text, and optional buttons", - "keywords": ["card", "image", "text", "cta"], - "textdomain": "imagewize", - "example": {}, - "editorScript": "file:./index.js", - "editorStyle": "file:./editor.css", - "style": "file:./style.css", - "viewScript": "file:./view.js", - "supports": { - "align": ["wide", "full"], - "anchor": true, - "spacing": { - "padding": true, - "margin": true - }, - "color": { - "background": true, - "text": true - }, - "typography": { - "fontSize": true, - "lineHeight": true - }, - "html": false - }, - "attributes": { - "className": { - "type": "string", - "default": "wp-block-imagewize-content-image-text-card" - }, - "imageId": { - "type": "number" - }, - "imageUrl": { - "type": "string" - }, - "imageAlt": { - "type": "string", - "default": "" - }, - "heading": { - "type": "string", - "default": "Card Title" - }, - "bodyText": { - "type": "string", - "default": "Add your descriptive text here. This placeholder helps you visualize the layout." - }, - "primaryButtonText": { - "type": "string", - "default": "Learn More" - }, - "primaryButtonUrl": { - "type": "string", - "default": "" - }, - "primaryButtonTarget": { - "type": "string", - "default": "" - }, - "primaryButtonSize": { - "type": "string", - "default": "medium" - }, - "secondaryButtonText": { - "type": "string", - "default": "" - }, - "secondaryButtonUrl": { - "type": "string", - "default": "" - }, - "secondaryButtonTarget": { - "type": "string", - "default": "" - }, - "secondaryButtonSize": { - "type": "string", - "default": "medium" - } - } -} -``` - -**Key Configuration Points:** -- `textdomain`: Must be "imagewize" (not "sage") -- `className`: Required attribute for proper WordPress styling -- `supports`: Enables WordPress native controls (typography, spacing, colors) -- `attributes`: Define all customizable content and settings -- `default`: Provide sensible defaults for immediate preview -- `html`: Set to false to prevent HTML editing - -### Step 4: Build Editor Component (editor.jsx) - -**Location:** `resources/js/blocks/block-name/editor.jsx` - -Create the React component for the block editor: - -```jsx -import { - useBlockProps, - RichText, - MediaUpload, - MediaUploadCheck, - InspectorControls, - BlockControls -} from '@wordpress/block-editor'; -import { - PanelBody, - Button, - SelectControl, - TextControl, - ToggleControl, - ToolbarGroup, - ToolbarButton -} from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { image } from '@wordpress/icons'; - -export default function Edit({ attributes, setAttributes }) { - const { - imageId, - imageUrl, - imageAlt, - heading, - bodyText, - primaryButtonText, - primaryButtonUrl, - primaryButtonTarget, - primaryButtonSize, - secondaryButtonText, - secondaryButtonUrl, - secondaryButtonTarget, - secondaryButtonSize, - } = attributes; - - const blockProps = useBlockProps({ - className: 'image-text-card', - }); - - const onSelectImage = (media) => { - setAttributes({ - imageId: media.id, - imageUrl: media.url, - imageAlt: media.alt, - }); - }; - - const buttonSizeOptions = [ - { label: __('Small', 'imagewize'), value: 'small' }, - { label: __('Medium', 'imagewize'), value: 'medium' }, - { label: __('Large', 'imagewize'), value: 'large' }, - ]; - - // Default image fallback for preview - const displayImageUrl = imageUrl || '/app/themes/nynaeve/resources/images/placeholder.jpg'; - - return ( - <> - - - - ( - - )} - /> - - - - - - - - ( - - )} - /> - - {imageUrl && ( - setAttributes({ imageAlt: value })} - /> - )} - - - -

{__('Primary Button', 'imagewize')}

- setAttributes({ primaryButtonText: value })} - /> - setAttributes({ primaryButtonUrl: value })} - type="url" - /> - setAttributes({ primaryButtonTarget: value ? '_blank' : '' })} - /> - setAttributes({ primaryButtonSize: value })} - /> - -

{__('Secondary Button', 'imagewize')}

- setAttributes({ secondaryButtonText: value })} - placeholder={__('Optional', 'imagewize')} - /> - setAttributes({ secondaryButtonUrl: value })} - type="url" - /> - setAttributes({ secondaryButtonTarget: value ? '_blank' : '' })} - /> - setAttributes({ secondaryButtonSize: value })} - /> -
-
- -
- {displayImageUrl && ( -
- {imageAlt -
- )} - -
- setAttributes({ heading: value })} - placeholder={__('Card Title', 'imagewize')} - /> - - setAttributes({ bodyText: value })} - placeholder={__('Add your descriptive text here...', 'imagewize')} - /> - -
- {primaryButtonText && ( - - {primaryButtonText} - - )} - {secondaryButtonText && ( - - {secondaryButtonText} - - )} -
-
-
- - ); -} -``` - -**Key Features:** -- `BlockControls`: Toolbar controls for quick image change -- `InspectorControls`: Sidebar controls for advanced settings -- `RichText`: Inline editing for heading and body text -- `MediaUpload` wrapped with `MediaUploadCheck`: Native WordPress media library integration -- `SelectControl`: Dropdown for button size variants -- `ToggleControl`: For "open in new tab" functionality -- Typography controls come from `supports.typography` in block.json - -### Step 5: Build Save Component (save.jsx) - -**Location:** `resources/js/blocks/block-name/save.jsx` - -Create the React component that generates frontend markup: - -```jsx -import { useBlockProps, RichText } from '@wordpress/block-editor'; - -export default function Save({ attributes }) { - const { - imageUrl, - imageAlt, - heading, - bodyText, - primaryButtonText, - primaryButtonUrl, - primaryButtonTarget, - primaryButtonSize, - secondaryButtonText, - secondaryButtonUrl, - secondaryButtonTarget, - secondaryButtonSize, - } = attributes; - - const blockProps = useBlockProps.save({ - className: 'image-text-card', - }); - - // Default image fallback - const displayImageUrl = imageUrl || '/app/themes/nynaeve/resources/images/placeholder.jpg'; - - return ( -
- {displayImageUrl && ( -
- {imageAlt -
- )} - -
- - - - -
- {primaryButtonText && ( - - {primaryButtonText} - - )} - {secondaryButtonText && ( - - {secondaryButtonText} - - )} -
-
-
- ); -} -``` - -**Important:** -- The save component must output clean, semantic HTML that matches the editor preview -- Always use fallback values for optional attributes -- Include security attributes for external links -- Use conditional rendering for optional sections - -### Step 6: Port CSS Styles (style.css) - -**Location:** `resources/js/blocks/block-name/style.css` - -Port CSS from Moiraine pattern and add responsive styles: - -```css -/* Default: constrained to content width */ -.image-text-card { - max-width: var(--wp--style--global--content-size, 55rem); - margin-left: auto; - margin-right: auto; - width: 100%; - border: 1px solid var(--wp--preset--color--border, #e5e7eb); - border-radius: 0.5rem; - overflow: hidden; - background: var(--wp--preset--color--white, #fff); -} - -/* Wide alignment */ -.image-text-card.alignwide { - max-width: var(--wp--style--global--wide-size, 64rem); -} - -/* Full alignment */ -.image-text-card.alignfull { - max-width: none; - margin-left: 0; - margin-right: 0; - border-radius: 0; -} - -/* Image */ -.image-text-card__image { - width: 100%; - aspect-ratio: 16 / 9; - overflow: hidden; -} - -.image-text-card__image img { - width: 100%; - height: 100%; - object-fit: cover; -} - -/* Content */ -.image-text-card__content { - padding: var(--wp--preset--spacing--large, 3rem); -} - -/* Heading - use theme font size presets */ -.image-text-card__heading { - font-size: var(--wp--preset--font-size--2-xl, 1.5rem); - font-weight: 700; - margin-bottom: var(--wp--preset--spacing--small, 1rem); - line-height: 1.3; -} - -/* Body text */ -.image-text-card__body { - font-size: var(--wp--preset--font-size--base, 1rem); - line-height: 1.6; - margin-bottom: var(--wp--preset--spacing--medium, 1.5rem); - color: var(--wp--preset--color--text, #374151); -} - -/* Buttons */ -.image-text-card__buttons { - display: flex; - gap: var(--wp--preset--spacing--small, 1rem); - flex-wrap: wrap; -} - -/* Button base styles */ -.btn { - display: inline-block; - text-decoration: none; - border-radius: 0.375rem; - font-weight: 600; - text-align: center; - transition: all 0.2s ease; -} - -/* Button sizes */ -.btn--small { - padding: 0.5rem 1rem; - font-size: var(--wp--preset--font-size--sm, 0.875rem); -} - -.btn--medium { - padding: 0.75rem 1.5rem; - font-size: var(--wp--preset--font-size--base, 1rem); -} - -.btn--large { - padding: 1rem 2rem; - font-size: var(--wp--preset--font-size--lg, 1.125rem); -} - -/* Button variants */ -.btn--primary { - background-color: var(--wp--preset--color--primary, #3b82f6); - color: #fff; -} - -.btn--primary:hover { - background-color: var(--wp--preset--color--primary-dark, #2563eb); -} - -.btn--secondary { - background-color: transparent; - color: var(--wp--preset--color--primary, #3b82f6); - border: 2px solid var(--wp--preset--color--primary, #3b82f6); -} - -.btn--secondary:hover { - background-color: var(--wp--preset--color--primary, #3b82f6); - color: #fff; -} - -/* Responsive */ -@media (max-width: 768px) { - .image-text-card__content { - padding: var(--wp--preset--spacing--medium, 1.5rem); - } - - .image-text-card__buttons { - flex-direction: column; - } - - .btn { - width: 100%; - } -} -``` - -**Benefits of Using Theme Presets:** -- Maintains consistency with theme design system -- Easier to maintain and adjust globally -- Respects user's font size preferences -- Better accessibility -- Uses short class names for cleaner CSS - -### Step 7: Add Editor Styles (editor.css) - -**Location:** `resources/js/blocks/block-name/editor.css` - -Add editor-specific styles to match frontend appearance: - -```css -/* Editor-only border to make block visible */ -.wp-block-imagewize-content-image-text-card { - border: 2px dashed #007cba; -} - -/* Disable interactions in editor */ -.editor-styles-wrapper .image-text-card__button { - pointer-events: none; -} - -/* Style placeholder content */ -.wp-block-imagewize-content-image-text-card p:first-of-type { - color: #757575; - font-style: italic; -} - -/* Ensure proper preview in editor */ -.editor-styles-wrapper .image-text-card { - /* Additional editor-specific styles if needed */ -} -``` - -**Note:** Use the full WordPress class name for editor-specific styles, not the short class name. - -### Step 8: Test and Refine - -1. **Build assets:** - ```bash - cd site/web/app/themes/nynaeve - npm run dev # For development with HMR - # or - npm run build # For production - ``` - -2. **Test in Block Editor:** - - Insert block and verify it appears - - Test all controls (image upload, text editing, buttons) - - Test typography controls (font size, line height) - - Test spacing controls (padding, margin) - - Test color controls (background, text) - - Test alignment options (default, wide, full) - - Preview on frontend - -3. **Refinements:** - - Adjust CSS and spacing - - Add more button variants if needed - - Fine-tune responsive breakpoints - - Test across browsers - -### Step 9: Documentation - -Update documentation: -- Update `CLAUDE.md` with block usage notes -- Update `CHANGELOG.md` with version notes -- Document any special features or requirements -- Add examples/screenshots if helpful - -## Updated Conversion Checklist - -**Setup:** -- [ ] Analyze Moiraine pattern structure and styling -- [ ] **DECISION**: Choose InnerBlocks vs Custom Controls approach - - [ ] **InnerBlocks**: For content-focused blocks with image + heading + paragraph + buttons - - [ ] **Custom Controls**: For complex styling/layout options not available in native blocks -- [ ] Create Sage Native Block from Trellis VM: `wp acorn sage-native-block:create` (select appropriate template) - - [ ] Choose Generic Template if pattern matches pre-built options (InnerBlocks, two-column, etc.) - - [ ] Choose Basic Block for custom implementation -- [ ] Install any required npm packages (e.g., `@wordpress/icons`) - -**Configuration (block.json):** -- [ ] **CRITICAL**: Set `"textdomain": "imagewize"` (NOT "sage") -- [ ] **CRITICAL**: Add `className` attribute with default `"wp-block-imagewize-block-name"` -- [ ] **InnerBlocks**: Remove custom attributes, keep only `className` -- [ ] **Custom Controls**: Define all custom attributes with proper defaults -- [ ] Add `version` field for cache busting -- [ ] Include `viewScript: "file:./view.js"` even if not used initially -- [ ] Add descriptive `keywords` for discoverability -- [ ] Include `example: {}` for block preview -- [ ] Set `"html": false` in supports -- [ ] Do NOT set default alignment unless you want wide/full - omit for normal content-width - -**Development Choice:** - -**Option A: InnerBlocks Approach (PREFERRED for content blocks):** -- [ ] **editor.jsx**: Import `InnerBlocks`, define `TEMPLATE` with native blocks -- [ ] **save.jsx**: Use `` only -- [ ] **CSS**: Target `.block-name .wp-block-*` for styling native blocks -- [ ] **Template**: Define structure with `core/image`, `core/heading`, `core/paragraph`, `core/button` -- [ ] **Template Lock**: Set to `"all"` to maintain structure while allowing content editing -- [ ] **Allowed Blocks**: Restrict to relevant block types -- [ ] **No Inspector Controls**: Let native blocks handle their own settings - -**Option B: Custom Controls Approach (for complex blocks):** -- [ ] Import all needed components including `BlockControls`, `MediaUploadCheck`, `ToggleControl` -- [ ] Import icons from `@wordpress/icons` if using toolbar buttons -- [ ] Wrap `MediaUpload` with `MediaUploadCheck` -- [ ] Add `BlockControls` with toolbar buttons -- [ ] Add `InspectorControls` with sidebar settings -- [ ] Add `ToggleControl` for "open in new tab" functionality -- [ ] Use fallback values for optional attributes in preview -- [ ] Use correct textdomain in `__()` calls: `__('Text', 'imagewize')` -- [ ] Add fallback values for all optional attributes (`||` operator) -- [ ] Use `href={url || '#'}` for buttons without URLs -- [ ] Include `rel="noopener noreferrer"` for external links -- [ ] Use conditional rendering (`&&`) for optional sections -- [ ] Provide alt text fallbacks for images - -**Styling:** -- [ ] **InnerBlocks**: Use CSS targeting `.block-name .wp-block-*` selectors -- [ ] **Custom Controls**: Use short class names (`.block-name` not `.wp-block-namespace-block-name`) -- [ ] Use CSS custom properties from theme (`var(--wp--preset--*)`) -- [ ] Add alignment support (default, wide, full) -- [ ] Use full WordPress class in `editor.css` for editor-only styles -- [ ] **InnerBlocks**: Add visual guides for editor structure -- [ ] **Custom Controls**: Add visual boundaries (borders) for editing clarity -- [ ] **Custom Controls**: Disable pointer events on interactive elements in editor - -**Testing:** -- [ ] Build: `npm run dev` (HTTP only for HMR) or `npm run build` -- [ ] **InnerBlocks**: Test inline editing of each component (image, heading, paragraph, buttons) -- [ ] **InnerBlocks**: Test native block toolbar controls for each element -- [ ] **Custom Controls**: Test all controls, responsive, alignment -- [ ] Test default placeholder content -- [ ] **Both**: Test alignment options and responsive design -- [ ] **InnerBlocks**: Verify template lock prevents structural changes -- [ ] **Custom Controls**: Test buttons without URLs and "open in new tab" - -## Content Image Text Card - Complete Feature List - -**Two Implementation Approaches Available:** - -### v1.15.0: Custom Controls Approach (Legacy) -**Completed block:** `imagewize/content-image-text-card` (custom attributes version) - -**Features:** -- Image upload with default placeholder fallback -- Toolbar button for quick image change -- RichText inline editing for heading and body text -- Primary button with text, URL, size (small/medium/large), and "open in new tab" -- Secondary button with text, URL, size (small/medium/large), and "open in new tab" -- Buttons render even without URLs (default to `#`) -- Inspector Controls in sidebar for all button settings -- Native WordPress controls: Typography, spacing, colors, alignment - -### v1.15.1: InnerBlocks Approach (CURRENT - PREFERRED) -**Updated block:** `imagewize/content-image-text-card` (InnerBlocks version) - -**Features:** -- **Native Image Block**: Full WordPress image controls (upload, alt text, size, etc.) -- **Native Heading Block**: Direct editing with typography toolbar controls -- **Native Paragraph Block**: Direct editing with formatting toolbar -- **Native Button Blocks**: Two individual button blocks with separate URL, text, and styling controls -- **Clean Sidebar**: No inspector controls - everything editable directly in editor -- **Modular Components**: Each element maintains its own WordPress settings -- **Template Structure**: Predefined layout with Image → Content Group → Button Group -- **Template Lock**: Maintains structure while allowing full content editing - -**Key Differences:** -- **Editing**: Direct inline editing vs sidebar controls -- **User Experience**: Native WordPress block toolbar controls vs custom inspector panels -- **Maintenance**: InnerBlocks uses WordPress core functionality vs custom implementation -- **Flexibility**: Each component fully customizable vs block-level settings -- **Clean Interface**: No sidebar clutter vs organized inspector panels - -**When to Use Each:** -- **InnerBlocks**: Content-focused blocks, simpler editing, native WordPress experience -- **Custom Controls**: Complex styling options, advanced settings, custom functionality - -**Migration:** Existing custom control blocks can coexist; new content should use InnerBlocks approach. - -**Key Lessons:** -- **PREFERRED**: Use InnerBlocks approach for content-focused blocks -- Must install `@wordpress/icons` package if using custom toolbar buttons -- InnerBlocks approach eliminates need for custom attributes and fallback values -- Use `templateLock: "all"` to maintain structure while allowing content editing -- CSS should target `.block-name .wp-block-*` for styling native blocks within container -- **Avoid hardcoded classes in templates** - let users select styles via block toolbar -- Button styles controlled by WordPress button filter (5 variants: Default, Outline, Secondary, Light, Dark) -- Template defines default content and block structure -- **CRITICAL**: Use `"textdomain": "imagewize"` not "sage" -- **CRITICAL**: Include `className` attribute in block.json for WordPress styling - -**InnerBlocks Structure:** -``` -resources/js/blocks/content-image-text-card/ -├── block.json # Minimal attributes (className only), template configuration -├── index.js # Standard registerBlockType -├── editor.jsx # InnerBlocks with TEMPLATE and templateLock -├── save.jsx # Simple wrapper -├── style.css # Targets native WordPress blocks (.wp-block-*) -├── editor.css # Visual guides for editor structure -└── view.js # Placeholder for future interactivity -``` - -**Template Structure:** -```jsx -const TEMPLATE = [ - ['core/image', { className: 'image-text-card__image' }], - ['core/group', { className: 'image-text-card__content' }, [ - ['core/heading', { level: 3 }], - ['core/paragraph', {}], - ]], - ['core/group', { className: 'image-text-card__buttons', layout: { type: 'flex' } }, [ - ['core/button', { text: 'Primary Action' }], - ['core/button', { text: 'Secondary Action' }], - ]], -]; -``` - -## Pattern-Specific Notes - -### Content Image Text Pattern ✓ -- **Moiraine Location:** `~/code/moiraine/patterns/content-image-text.php` -- **Completed:** Converted to Sage Native Block `imagewize/content-image-text-card` -- **Features:** Image upload, heading, body text, primary/secondary buttons, button size variants, "open in new tab" -- **Controls:** Typography (font size, line height), spacing (padding, margin), colors (background, text) -- **Key Implementation Details:** - - Uses fallback image and default href values - - Includes toolbar controls for quick image change - - Supports external link security attributes - - Uses theme CSS custom properties - -### Hero CTA Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/hero-cta.php` -- **Attributes Needed:** Background image, heading, subheading, CTA buttons (multiple), text alignment, overlay opacity -- **Controls:** Typography, colors, spacing, alignment options -- **Button Variants:** Size variants (small, medium, large), style variants (primary, secondary, outline) - -### Blog Grid Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/blog-grid.php` -- **Attributes Needed:** Post query settings, grid columns (2/3/4), show excerpts toggle, featured image toggle -- **Controls:** Layout controls (columns, gap), typography for headings/excerpts -- **Dynamic:** May require server-side rendering or REST API integration - -### Testimonial Card Pattern -- **Moiraine Location:** `~/code/moiraine/patterns/testimonial-card.php` -- **Attributes Needed:** Quote text, author name, author title, author image, rating -- **Controls:** Typography for quote/author, colors, spacing -- **Layout Options:** Card variations (with/without image, alignment options) - -## Benefits Summary - -| Aspect | ACF Composer Blocks | Custom Controls Native Blocks | InnerBlocks Native Blocks | -|--------|---------------------|-------------------------------|---------------------------| -| Typography Controls | Limited (hardcoded in CSS) | Full (font size picker, line height, font family) | Full (native block typography controls) | -| Button Variants | Hard to add | Easy (size/style variants) | Native button block controls | -| Content Editing | ACF sidebar fields | RichText + sidebar | Direct inline editing | -| Design System | Indirect | Direct (theme.json integration) | Direct (theme.json integration) | -| Maintainability | PHP/Blade templates | React components with custom logic | Simple React + WordPress core | -| User Experience | ACF field interface | Custom WordPress controls | Native WordPress block interface | -| Styling Flexibility | Limited to developer | Users can customize via inspector | Users can customize each element natively | -| Frontend JavaScript | Difficult to add | Easy (view.js file) | Easy (view.js file) | -| Development Complexity | Low (PHP/Blade) | High (custom attributes + controls) | Low (template definition) | -| Sidebar Cleanliness | Clean (single ACF panel) | Cluttered (multiple panels) | Clean (no custom controls) | -| Block Toolbar Usage | Limited | Custom toolbar buttons | Full native toolbar per element | - -## Resources - -- **Sage Native Block Package:** https://github.com/imagewize/sage-native-block -- **Moiraine Patterns:** `~/code/moiraine/patterns/` -- **Nynaeve Native Blocks:** `site/web/app/themes/nynaeve/resources/js/blocks/` -- **WordPress Block Editor Handbook:** https://developer.wordpress.org/block-editor/ -- **Block Registration:** https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/ - -## Next Steps - -1. ✓ Convert **Content Image Text** pattern to Sage Native Block (completed) -2. Evaluate ACF Composer blocks in theme - consider converting those needing typography/button controls -3. Convert remaining priority Moiraine patterns as Sage Native Blocks -4. Document learned patterns and best practices -5. Create reusable button components for consistent styling across blocks diff --git a/docs/WOOCOMMERCE.md b/docs/WOOCOMMERCE.md deleted file mode 100644 index 91b550e..0000000 --- a/docs/WOOCOMMERCE.md +++ /dev/null @@ -1,254 +0,0 @@ -# WooCommerce Integration - -Nynaeve includes flexible WooCommerce integration with three distinct modes to support different business models. Perfect for B2B businesses, custom products, and lead generation. - -## Table of Contents - -- [Operating Modes](#operating-modes) -- [Configuration](#configuration) -- [Quote Mode (Default)](#quote-mode-default) -- [Standard Mode](#standard-mode) -- [Catalog Mode](#catalog-mode) -- [Customization](#customization) - -## Operating Modes - -The theme supports three WooCommerce operating modes, configurable via Theme Options: - -| Mode | Prices | Add to Cart | Checkout | Best For | -|------|--------|-------------|----------|----------| -| **Quote Mode** | Hidden | "Request Quote" button | Disabled | B2B, custom products, lead generation | -| **Standard Mode** | Visible | Standard buttons | Enabled | Traditional e-commerce | -| **Catalog Mode** | Visible | Hidden | Disabled | Product showcases, price transparency | - -## Configuration - -### Theme Options - -Configure WooCommerce mode via **WordPress Admin → Theme Options**: - -1. Navigate to **Appearance → Theme Options** (or wherever your ACF Options page is located) -2. Find the **WooCommerce Settings** section -3. Select your desired mode from the dropdown: - - Quote Mode - - Standard Mode - - Catalog Mode -4. Save changes - -Changes take effect immediately - no cache clearing required. - -## Quote Mode (Default) - -**Best for:** B2B businesses, custom products, services requiring consultation, lead generation - -### Features - -- **Hide Prices**: Product prices are hidden throughout the site -- **Request Quote Buttons**: Replaces "Add to Cart" with "Request Quote" buttons on single product pages -- **Cart/Checkout Disabled**: Users are redirected away from cart and checkout pages -- **REST API Protection**: Checkout requests are intercepted and prevented -- **Lead Generation Focus**: Encourages direct contact with potential customers - -### How It Works - -**On Product Archives (Shop, Category, Tag pages):** -- Products display without prices -- No add-to-cart buttons visible -- Users must visit product page for details - -**On Single Product Pages:** -- Product details visible (images, description, attributes) -- Price section hidden -- "Request Quote" button displayed instead of "Add to Cart" -- Button links to contact page or quote request form - -**Cart/Checkout Protection:** -- Direct access to cart page redirects to shop or home -- Checkout page redirects to shop or home -- REST API checkout endpoint returns error response -- No accidental purchases possible - -### Use Cases - -- **Custom Manufacturing**: Products require specifications before pricing -- **B2B Sales**: Pricing varies by volume or customer relationship -- **Services**: Consultation required before quoting -- **Complex Products**: Multiple variables affect final price -- **Lead Generation**: Capture customer information before revealing pricing - -## Standard Mode - -**Best for:** Traditional e-commerce, retail businesses, standard product sales - -### Features - -- **Full WooCommerce**: All standard WooCommerce functionality enabled -- **Visible Prices**: Product prices displayed everywhere -- **Add to Cart**: Standard add-to-cart buttons and functionality -- **Cart & Checkout**: Full shopping cart and checkout process -- **Payment Gateways**: All configured payment methods available - -### How It Works - -Standard WooCommerce behavior with no restrictions. Perfect for traditional online stores. - -## Catalog Mode - -**Best for:** Product showcases, dealer locators, price transparency without direct sales - -### Features - -- **Visible Prices**: Product prices displayed for transparency -- **No Add to Cart**: Add-to-cart functionality hidden -- **No Checkout**: Cart and checkout pages disabled -- **Product Information**: Full product details visible -- **Price Discovery**: Customers can see pricing without purchasing - -### How It Works - -**On Product Archives:** -- Products display with prices -- No add-to-cart buttons -- Users can browse and see pricing - -**On Single Product Pages:** -- Full product details visible -- Prices displayed -- No purchase buttons -- May include dealer locator or contact information - -**Use Cases:** -- **Dealer Networks**: Show products but direct to local dealers -- **Wholesale Only**: Display catalog but require dealer account -- **Coming Soon**: Show products before launch -- **Price Transparency**: Display pricing without enabling sales - -## Customization - -### Changing Button Text - -To customize the "Request Quote" button text in Quote Mode: - -**Via Filter (recommended):** - -```php -// In app/filters.php or a custom service provider -add_filter('nynaeve_quote_button_text', function($text) { - return 'Get a Quote'; // or 'Contact Us', 'Request Pricing', etc. -}); -``` - -### Custom Redirects - -To change where cart/checkout pages redirect in Quote Mode: - -```php -// Redirect to custom quote form page -add_filter('nynaeve_quote_mode_redirect_url', function($url) { - return home_url('/request-quote/'); -}); -``` - -### Quote Button Styling - -The "Request Quote" button inherits WooCommerce button styles by default. To customize: - -```css -/* In resources/css/app.css */ -.single-product .request-quote-button { - @apply bg-primary text-white hover:bg-primary-dark; - /* Add your custom styles */ -} -``` - -### Per-Product Quote Buttons - -To hide the quote button on specific products: - -```php -// In app/filters.php -add_filter('nynaeve_show_quote_button', function($show, $product_id) { - $hide_on = [123, 456]; // Product IDs to hide button - return !in_array($product_id, $hide_on); -}, 10, 2); -``` - -### Custom REST API Responses - -To customize the checkout API error message in Quote Mode: - -```php -add_filter('nynaeve_checkout_api_error', function($error) { - return new WP_Error( - 'checkout_disabled', - 'Please contact us for a quote.', - ['status' => 403] - ); -}); -``` - -## Developer Notes - -### Code Location - -WooCommerce integration is handled in: -- `app/setup.php` - Mode detection and setup -- `app/filters.php` - WooCommerce filter customizations -- `app/View/Composers/` - Product view composers - -### Conditional Logic - -Check current mode in templates: - -```php -$mode = get_field('woocommerce_mode', 'option'); - -if ($mode === 'quote') { - // Quote mode logic -} elseif ($mode === 'catalog') { - // Catalog mode logic -} else { - // Standard mode logic -} -``` - -### Testing - -When testing mode changes: -1. Change mode in Theme Options -2. Visit a product page (not cached) -3. Test cart/checkout access -4. Clear object cache if using persistent caching - -### Known Limitations - -- Quote mode does not support variable products (simple products only recommended) -- Cart widget and mini-cart should be hidden in quote/catalog modes -- Some WooCommerce extensions may not respect quote mode restrictions - -## Troubleshooting - -### Prices Still Visible in Quote Mode - -1. Check Theme Options setting is saved correctly -2. Clear any page caching (WP Rocket, W3 Total Cache, etc.) -3. Check for plugin conflicts (other WooCommerce customization plugins) -4. Verify theme is up to date - -### Cart Still Accessible - -1. Confirm redirect functionality is not disabled by plugin -2. Check for caching issues -3. Test in incognito/private browsing mode - -### Quote Button Not Appearing - -1. Verify product type is "Simple" (not Variable) -2. Check product visibility settings -3. Confirm no conflicting plugins hiding the button area - -## Additional Resources - -- [WooCommerce Documentation](https://woocommerce.com/documentation/) -- [WooCommerce Template Structure](https://github.com/woocommerce/woocommerce/wiki/Template-structure) -- [Sage Theme Development](https://roots.io/sage/docs/) diff --git a/docs/blocks/ABOUT-BLOCK.md b/docs/blocks/ABOUT-BLOCK.md deleted file mode 100644 index dc9a43e..0000000 --- a/docs/blocks/ABOUT-BLOCK.md +++ /dev/null @@ -1,873 +0,0 @@ -# About Block Migration Plan - -## Migration Status - -✅ **COMPLETED** - October 21, 2025 - -The About Block has been successfully migrated from a standalone Composer plugin to a Sage Native Block within the Nynaeve theme. - -**Migration Summary**: -- ✅ Block scaffold created at `resources/js/blocks/about/` -- ✅ Block metadata (block.json) updated with original configuration -- ✅ Edit component migrated with InnerBlocks template -- ✅ Save component migrated with attribute handling -- ✅ Styles migrated (both frontend and editor) -- ✅ Profile image asset copied to block directory -- ✅ Theme build successful -- ⏳ **NEXT STEP**: Test in WordPress editor and update existing content - -## Overview - -Migrating the `imagewize/about-block` plugin (v1.0.1) to a Sage Native Block in the Nynaeve theme called **About Block** (`imagewize/about`). - -**Original Location**: Composer plugin at `site/web/app/plugins/about-block/` -**New Location**: Theme block at `site/web/app/themes/nynaeve/resources/js/blocks/about/` -**Primary Colors**: Gray background (#ebeced/border-light), secondary text (#98999a/secondary) - -## Why Migrate to Theme? - -Following the content width and layout improvements documented in [CONTENT-WIDTH-AND-LAYOUT.md](../CONTENT-WIDTH-AND-LAYOUT.md): - -1. **Consistency**: All blocks managed in one place (theme) with unified design system -2. **Maintainability**: Easier updates alongside theme changes -3. **Performance**: Reduces plugin dependencies, consolidates asset loading -4. **Design System Integration**: Direct access to Tailwind CSS 4 and theme utilities -5. **Simplified Workflow**: No separate plugin repository to maintain - -## Current Plugin Analysis - -### Block Structure (Original - Uses Group + Columns) - -The current plugin uses a **Group block** containing **2-column layout** with asymmetric widths (20% image / 80% text): - -``` -About Block (full width, #ebeced background) -├── Group (constrained layout, gray background) -│ ├── Spacer (60px) -│ ├── Columns (constrained, 2 columns) -│ │ ├── Column 1 (20% width - profile image) -│ │ │ └── Image (rounded border, 8px solid gray) -│ │ └── Column 2 (80% width - text content) -│ │ ├── Heading (h2, 3xl, black, Open Sans) -│ │ ├── Paragraph (lg, gray #98999a, line-height 1.6) -│ │ └── Paragraph (base, gray #98999a, line-height 2) -│ └── Spacer (60px) -``` - -### Improved Structure (Using Group - Simplified) - -Since this is a **two-column layout** (image + text), we should keep the columns but simplify the wrapper: - -``` -About Block (full width, #ebeced background) -├── Group (constrained width, centered, vertical padding) -│ └── Columns (2 columns: 20% / 80%) -│ ├── Column 1 (20% - Profile Image) -│ │ └── Image (rounded, bordered) -│ └── Column 2 (80% - Text Content) -│ ├── Heading (3xl, black) -│ ├── Paragraph (lg, gray) -│ └── Paragraph (base, gray) -``` - -**Benefits of This Structure**: -- Maintains horizontal layout (columns are appropriate here) -- Single Group wrapper with constrained layout -- Uses theme's constrained width setting -- Cleaner than original (removed redundant nesting) -- Proper semantic HTML for side-by-side content -- Better responsive behavior (columns stack on mobile) - -### Key Features to Preserve - -1. **InnerBlocks Template**: Two-column layout with profile image and text -2. **Rounded Image Border**: Custom rounded style with 8px gray border -3. **Full-Width Alignment**: Block spans full viewport width by default -4. **Centered Content**: Content constrained to readable width via Group -5. **Color System**: - - Background: #ebeced (border-light in theme) - - Text heading: Black (#000000) - - Text paragraphs: Gray #98999a (secondary in theme) - - Image border: #cbcbcb (border-dark in theme) -6. **Typography**: - - Font: Open Sans with system font fallbacks - - Heading: 3xl font size - - First paragraph: lg font size, line-height 1.6 - - Second paragraph: base font size, line-height 2 -7. **Vertical Spacing**: 60px padding top/bottom via spacers -8. **Column Layout**: 20% image column, 80% text column -9. **Responsive Design**: Mobile padding and centered headings - -### Technical Details - -**Attributes**: -- `backgroundColor`: "#ebeced" (default) -- `textColor`: "#98999a" (default) -- `style`: Object for custom styles - -**Block Supports**: -- Alignment: wide, full -- Color: background, text -- Spacing: padding, margin -- Typography: fontSize, lineHeight -- Border: color, radius, width (experimental) - -**Special Functionality**: -- **Image Style Registration**: Registers "rounded" style for core/image block -- **Profile Image Asset**: Default profile.jpg imported and used in template -- **Mobile Responsiveness**: Custom padding and centering on screens < 768px - -## Migration Plan - -### Phase 1: Create Sage Native Block - -#### Step 1.1: Generate Block Scaffold - -```bash -# Run from Trellis VM (required for database access) -cd trellis -trellis vm shell --workdir /srv/www/imagewize.com/current/web/app/themes/nynaeve -- wp acorn sage-native-block:create about-block --template=nynaeve-innerblocks --force -``` - -**Expected Output**: -- `resources/js/blocks/about-block/block.json` -- `resources/js/blocks/about-block/index.js` -- `resources/js/blocks/about-block/edit.js` -- `resources/js/blocks/about-block/save.js` -- `resources/js/blocks/about-block/style.css` -- `resources/js/blocks/about-block/editor.css` - -#### Step 1.2: Copy Profile Image Asset - -```bash -# Copy profile image from plugin to theme -cp site/web/app/plugins/about-block/src/assets/profile.jpg site/web/app/themes/nynaeve/resources/images/profile.jpg -``` - -#### Step 1.3: Update Block Metadata (block.json) - -```json -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 3, - "name": "imagewize/about-block", - "version": "1.0.0", - "title": "About Block", - "category": "imagewize", - "icon": "id-alt", - "description": "About section with profile image and text layout", - "keywords": ["about", "profile", "bio", "introduction"], - "textdomain": "imagewize", - "editorScript": "file:./index.js", - "editorStyle": "file:./editor.css", - "style": "file:./style.css", - "attributes": { - "align": { - "type": "string", - "default": "full" - }, - "backgroundColor": { - "type": "string", - "default": "border-light" - } - }, - "supports": { - "html": false, - "align": ["wide", "full"], - "color": { - "background": true, - "text": true - }, - "spacing": { - "padding": true, - "margin": true - }, - "typography": { - "fontSize": true, - "lineHeight": true - } - } -} -``` - -**Note**: Changed default alignment to `"full"` and background color to theme's `"border-light"` color. - -### Phase 2: Implement Block Structure - -#### Step 2.1: Create InnerBlocks Template (edit.js) - -```javascript -import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; -import profileImage from '../../images/profile.jpg'; - -// Register rounded image style -import { registerBlockStyle } from '@wordpress/blocks'; - -wp.domReady(() => { - if (wp.blocks.getBlockType('core/image')) { - registerBlockStyle('core/image', { - name: 'rounded', - label: __('Rounded', 'imagewize'), - }); - } -}); - -const TEMPLATE = [ - [ - 'core/group', - { - align: 'wide', - layout: { type: 'constrained' }, - style: { - color: { - background: 'var(--wp--preset--color--border-light, #ebeced)', - }, - spacing: { - padding: { - top: 'var(--wp--preset--spacing--60)', - bottom: 'var(--wp--preset--spacing--60)', - }, - }, - }, - }, - [ - [ - 'core/columns', - { - align: 'wide', - }, - [ - [ - 'core/column', - { - width: '20%', - style: { - spacing: { - padding: { - top: '1rem', - }, - }, - }, - }, - [ - [ - 'core/image', - { - url: profileImage, - alt: 'Profile Image', - className: 'is-style-rounded aligncenter', - style: { - border: { - width: '8px', - color: 'var(--wp--preset--color--border-dark, #cbcbcb)', - style: 'solid', - }, - }, - }, - ], - ], - ], - [ - 'core/column', - { - width: '80%', - }, - [ - [ - 'core/heading', - { - level: 2, - fontSize: '3xl', - style: { - typography: { - fontFamily: - 'var(--wp--preset--font-family--open-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif)', - fontStyle: 'normal', - fontWeight: '400', - }, - color: { - text: '#000000', - }, - }, - content: 'Custom Crafted Websites & E-Commerce.', - }, - ], - [ - 'core/paragraph', - { - fontSize: 'lg', - style: { - typography: { - fontFamily: - 'var(--wp--preset--font-family--open-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif)', - lineHeight: 1.6, - }, - color: { - text: 'var(--wp--preset--color--secondary, #98999a)', - }, - }, - content: - 'At Imagewize, we empower SMEs and startups by delivering custom web and e-commerce solutions. With expertise in web design, development, and SEO, every project is tailored to meet your unique needs and drive success. This site is dedicated to helping businesses grow online with customized, high-performance solutions.', - }, - ], - [ - 'core/paragraph', - { - fontSize: 'base', - style: { - typography: { - fontFamily: - 'var(--wp--preset--font-family--open-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif)', - lineHeight: 2, - }, - color: { - text: 'var(--wp--preset--color--secondary, #98999a)', - }, - }, - content: - 'Imagewize began as a passion project in 2016 and has grown into a full-service web solutions provider. Our mission is to craft stunning websites, build powerful e-commerce platforms with WooCommerce, and implement cutting-edge SEO strategies, including technical SEO. Whether you need a custom WordPress site or a tailored WooCommerce solution, we deliver exceptional results designed to help your business thrive online.', - }, - ], - ], - ], - ], - ], - ], - ], -]; - -export default function Edit() { - const blockProps = useBlockProps({ - className: 'wp-block-imagewize-about-block', - }); - - return ( -
- -
- ); -} -``` - -**Key Changes from Plugin**: -- Removed outer Group wrapper (WordPress handles full-width alignment) -- Inner Group provides constrained layout with vertical padding -- Columns remain for proper side-by-side layout -- Uses theme color variables with fallbacks -- Profile image imported from theme's resources/images/ -- Registers rounded image style using WordPress API - -#### Step 2.2: Create Save Function (save.js) - -```javascript -import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; - -export default function Save() { - const blockProps = useBlockProps.save({ - className: 'wp-block-imagewize-about-block', - }); - - return ( -
- -
- ); -} -``` - -### Phase 3: Style Implementation - -#### Step 3.1: Frontend Styles (style.css) - -```css -.wp-block-imagewize-about-block { - margin: 0; - padding: 0; - box-sizing: border-box; - - /* Image styles */ - .wp-block-image { - margin: 0; - display: flex; - justify-content: center; - } - - /* Rounded image style */ - .wp-block-image img.is-style-rounded { - border-radius: 9999px; /* Full circle */ - } - - /* Full width alignment - WordPress handles this natively */ - /* Note: Use width: 100% NOT 100vw (see docs/DEV.md → Full-Width Block Styling) */ - &.alignfull { - width: 100%; - } - - /* Mobile responsive styles */ - @media (max-width: 768px) { - /* Remove negative margins on mobile */ - margin-left: 0; - margin-right: 0; - - /* Full-width mobile padding */ - &.alignfull { - .wp-block-group__inner-container { - padding-left: 1rem; - padding-right: 1rem; - } - - .wp-block-heading { - text-align: center; - padding-left: 1rem; - padding-right: 1rem; - } - - .wp-block-paragraph, - p { - padding-left: 1rem; - padding-right: 1rem; - } - } - - /* Standard mobile padding */ - .wp-block-group__inner-container { - padding-left: 1rem; - padding-right: 1rem; - } - - /* Remove padding from columns container */ - .wp-block-columns { - padding-left: 0; - padding-right: 0; - } - - /* Center headings on mobile */ - .wp-block-heading { - text-align: center; - } - - /* Paragraph mobile padding */ - .wp-block-paragraph { - padding-left: 1rem; - padding-right: 1rem; - } - } -} -``` - -#### Step 3.2: Editor Styles (editor.css) - -```css -.wp-block-imagewize-about-block { - /* Editor-specific styles if needed */ - /* Most styles are shared via style.css */ - - /* Preview full-width behavior in editor */ - &.alignfull { - max-width: none; - } -} -``` - -### Phase 4: Testing & Validation - -#### Step 4.1: Build Theme - -```bash -cd site/web/app/themes/nynaeve -npm run build -``` - -#### Step 4.2: Test in Editor - -**Functionality Checklist**: -- [ ] Block appears in inserter under "Imagewize" category -- [ ] Default template renders with profile image and text -- [ ] Full-width alignment works correctly (default) -- [ ] Background color is border-light (#ebeced) -- [ ] Profile image displays with rounded border -- [ ] Profile image has 8px solid gray border -- [ ] Heading is 3xl font size, black color -- [ ] First paragraph is lg font size, gray color -- [ ] Second paragraph is base font size, gray color -- [ ] Columns are 20% / 80% width -- [ ] Content is constrained to theme's max width -- [ ] Vertical spacing (60px padding) is correct -- [ ] InnerBlocks allow customization -- [ ] Rounded image style is available in block styles - -#### Step 4.3: Test on Frontend - -**Frontend Checklist**: -- [ ] Block renders correctly on published page -- [ ] Full-width background spans viewport -- [ ] Content is centered and constrained -- [ ] Profile image is circular with border -- [ ] Typography matches design (sizes, colors, line heights) -- [ ] Colors match theme (border-light, secondary, border-dark) -- [ ] Columns layout works correctly (20/80 split) -- [ ] Responsive behavior works on mobile/tablet -- [ ] Mobile: Columns stack vertically -- [ ] Mobile: Heading is centered -- [ ] Mobile: Proper padding applied -- [ ] No console errors or warnings - -### Phase 5: Migration & Cleanup - -#### Step 5.1: Update Existing Content - -**Option A: Manual Update** (Recommended for few instances) -1. Create new About Block in editor -2. Copy content from old About Block -3. Upload same profile image -4. Delete old block -5. Save - -**Option B: Block Deprecation** (For many instances) -1. Create deprecation in block.json to handle old plugin block -2. WordPress auto-migrates on page save -3. Document in theme changelog - -#### Step 5.2: Remove Plugin Dependency - -Update `site/composer.json`: - -```json -{ - "require": { - // Remove this line: - // "imagewize/about-block": "^1.0.0" - } -} -``` - -Run Composer update: -```bash -cd site -composer update --no-dev -``` - -#### Step 5.3: Verify Removal - -```bash -# Should return empty/not found -ls site/web/app/plugins/about-block/ -``` - -### Phase 6: Documentation - -#### Step 6.1: Update Block Documentation - -Create usage guide in theme docs (this file). - -#### Step 6.2: Update Changelog - -Add to `site/web/app/themes/nynaeve/CHANGELOG.md`: - -```markdown -## [Version] - [Date] - -### Added -- About Block: Migrated from imagewize/about-block plugin to theme - - Uses Group + Columns for proper two-column layout - - Maintains rounded profile image with border - - Integrated with theme design system (border-light, secondary colors) - - Responsive mobile design with centered headings - -### Removed -- Dependency on imagewize/about-block Composer plugin -``` - -## Block Usage Guide - -### How to Use About Block - -1. **Insert Block**: - - Click "+" in editor - - Search for "About Block" - - Block inserts with default template (profile image + text) - -2. **Customize Content**: - - **Profile Image**: Click image → Upload/select from media library - - **Heading**: Edit heading text (default: "Custom Crafted Websites & E-Commerce.") - - **Paragraphs**: Edit both paragraph texts - - **Image Style**: Select image → Block toolbar → Styles → Rounded (circular) - -3. **Customize Appearance**: - - **Background**: Select block → Sidebar → Color → Background - - **Text Color**: Select individual heading/paragraph → Sidebar → Color → Text - - **Image Border**: Select image → Sidebar → Border → Width/Color/Radius - - **Font Sizes**: Select heading/paragraph → Sidebar → Typography → Font Size - -4. **Adjust Layout**: - - **Alignment**: Select block → Toolbar → Full/Wide - - **Spacing**: Select block → Sidebar → Spacing → Padding/Margin - - **Column Widths**: Select column → Sidebar → Width - -### Default Template - -**Visual Structure**: -``` -┌─────────────────────────────────────────────────────────┐ -│ [Full Width Gray Background - border-light] │ -│ │ -│ ┌─────────────────────────────────────────────┐ │ -│ │ [Constrained Width Group - Centered] │ │ -│ │ │ │ -│ │ ┌───┐ Custom Crafted Websites... │ │ -│ │ │ ● │ (Heading, 3xl, black, Open Sans) │ │ -│ │ └───┘ │ │ -│ │ 20% At Imagewize, we empower SMEs... │ │ -│ │ (Paragraph, lg, gray, line-height 1.6)│ │ -│ │ │ │ -│ │ Imagewize began as a passion... │ │ -│ │ (Paragraph, base, gray, line-height 2)│ │ -│ │ 80% Text Column │ │ -│ └─────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────┘ -``` - -## Benefits of Group + Columns Structure - -### Why Use Columns Here? - -Unlike the CTA Blue Block which was truly single-column content, the About Block has **genuine side-by-side layout requirements**: - -**About Block (Columns are correct)**: -``` -Columns (2 columns: 20% / 80%) -├── Column 1 (Profile image - actual content) -└── Column 2 (Text content - actual content) -``` - -**Advantages of Columns for This Use Case**: -1. **Semantic**: Represents true horizontal relationship between image and text -2. **Responsive**: Columns automatically stack on mobile (WordPress core behavior) -3. **Flexible**: Users can adjust column widths via block settings -4. **Appropriate**: This is exactly what columns are designed for - -### Comparison with CTA Blue Block - -**CTA Blue Block** (vertical stacking): -- Heading -- Paragraph -- Button -→ **Solution**: Group (single column, no horizontal layout) - -**About Block** (horizontal layout): -- Image | Text -→ **Solution**: Columns (side-by-side content) - -### Wrapper Simplification - -**Original Plugin**: -``` -Outer Group (redundant) -└── Inner Group - ├── Spacer - ├── Columns - └── Spacer -``` - -**New Theme Block**: -``` -Group (single wrapper with padding) -└── Columns -``` - -**Benefits**: -- Removed redundant outer Group -- Vertical padding via Group's spacing settings (no spacer blocks needed) -- Cleaner DOM structure -- Easier to maintain - -## Technical Notes - -### Image Style Registration - -The block registers a custom "rounded" style for the core/image block: - -```javascript -wp.domReady(() => { - if (wp.blocks.getBlockType('core/image')) { - registerBlockStyle('core/image', { - name: 'rounded', - label: __('Rounded', 'imagewize'), - }); - } -}); -``` - -**CSS Implementation**: -```css -.wp-block-image img.is-style-rounded { - border-radius: 9999px; /* Full circle */ -} -``` - -Users can select this style from the image block's style selector in the block toolbar. - -### Profile Image Asset - -The default profile image is stored in the theme: -- **Location**: `resources/images/profile.jpg` -- **Import**: Via ES6 import in edit.js -- **Usage**: Set as default URL in image block template -- **Replacement**: Users can upload their own image via media library - -### Mobile Responsiveness - -**Breakpoint**: 768px - -**Mobile Behavior**: -- Columns stack vertically (WordPress core behavior) -- Heading centers automatically -- Custom padding applied (1rem) -- Image remains centered -- Text remains readable with proper spacing - -### Typography System - -**Font Family**: Open Sans with comprehensive fallback stack: -``` -var(--wp--preset--font-family--open-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif) -``` - -**Font Sizes**: -- Heading: `3xl` (theme preset) -- First paragraph: `lg` (theme preset) -- Second paragraph: `base` (theme preset) - -**Line Heights**: -- Heading: Default (1.2-1.4 typically) -- First paragraph: 1.6 (increased readability) -- Second paragraph: 2.0 (extra spacing) - -## Files Modified/Created - -### New Files -``` -site/web/app/themes/nynaeve/ -├── resources/js/blocks/about-block/ -│ ├── block.json -│ ├── index.js -│ ├── edit.js -│ ├── save.js -│ ├── style.css -│ └── editor.css -├── resources/images/ -│ └── profile.jpg (copied from plugin) -└── docs/blocks/ - └── ABOUT-BLOCK.md (this file) -``` - -### Modified Files -``` -site/ -├── composer.json (remove imagewize/about-block dependency) -└── web/app/themes/nynaeve/ - └── CHANGELOG.md (document migration) -``` - -### Removed After Migration -``` -site/web/app/plugins/about-block/ (entire plugin directory) -``` - -## Color Reference - -### Default Colors - -**Block Colors**: -- **Background**: `border-light` (#ebeced) - Light gray -- **Heading Text**: `#000000` - Black -- **Paragraph Text**: `secondary` (#98999a) - Medium gray -- **Image Border**: `border-dark` (#cbcbcb) - Dark gray border - -**Theme Color Mapping**: -```css ---wp--preset--color--border-light: #ebeced; /* Block background */ ---wp--preset--color--secondary: #98999a; /* Paragraph text */ ---wp--preset--color--border-dark: #cbcbcb; /* Image border */ -``` - -### Tailwind CSS Classes (for reference) -```css -.bg-border-light /* Background */ -.text-black /* Heading color */ -.text-secondary /* Paragraph color */ -.border-border-dark /* Image border */ -``` - -## Future Enhancements - -### Potential Improvements - -1. **Multiple Layout Variations**: - - Image right / text left - - Image top / text bottom - - Three-column layout option - -2. **Pattern Variations**: Create block patterns for different about styles - - Team member profile - - Company introduction - - Founder story - -3. **Social Media Integration**: Add optional social media icons/links below text - -4. **Video Support**: Option to use video instead of static image - -5. **Stats/Numbers**: Optional statistics section (years in business, clients served, etc.) - -6. **Background Options**: - - Gradient backgrounds - - Image backgrounds with overlay - -7. **Animation**: Add subtle entrance animations for image and text - -### Theme Integration - -- Consider adding to theme's block patterns collection -- Create variations with different color schemes -- Add to Gutenberg style guide/showcase -- Document in theme's pattern library - -## Migration Timeline - -**Estimated Time**: 2-3 hours - -1. **Block Creation**: 30 minutes -2. **Feature Implementation**: 60 minutes -3. **Testing**: 30 minutes -4. **Content Migration**: 15 minutes -5. **Cleanup & Documentation**: 15 minutes - -## Success Criteria - -Migration is complete when: - -- [ ] New block matches all functionality of plugin version -- [ ] Block uses Group + Columns structure (appropriate for this layout) -- [ ] Profile image displays with rounded border -- [ ] Image style registration works (rounded style available) -- [ ] All typography matches original (sizes, colors, line heights) -- [ ] Responsive behavior works on mobile (stacking, centering) -- [ ] All existing About blocks updated to new version -- [ ] Plugin removed from composer.json -- [ ] Plugin directory deleted -- [ ] Theme builds without errors -- [ ] Documentation complete -- [ ] No console errors on frontend/backend -- [ ] Passes accessibility tests -- [ ] Responsive on all breakpoints -- [ ] Colors use theme variables with fallbacks - -## Support & Questions - -For implementation questions or issues during migration: -- Reference: [CONTENT-WIDTH-AND-LAYOUT.md](../CONTENT-WIDTH-AND-LAYOUT.md) -- Theme docs: `/site/web/app/themes/nynaeve/docs/` -- Sage Native Block: `github.com/imagewize/sage-native-block` -- Block development guide: [PATTERN-TO-NATIVE-BLOCK.md](../PATTERN-TO-NATIVE-BLOCK.md) diff --git a/docs/blocks/CAROUSEL-PATCH.md b/docs/blocks/CAROUSEL-PATCH.md deleted file mode 100644 index bd6dbd1..0000000 --- a/docs/blocks/CAROUSEL-PATCH.md +++ /dev/null @@ -1,113 +0,0 @@ -# Carousel Block Migration - Database Patch - -## Overview -This document records the database migration performed when converting the `imagewize/carousel-block` plugin to Sage Native Blocks in the Nynaeve theme. - -## Migration Details - -**Date:** October 2, 2025 -**Reason:** Convert standalone carousel plugin to integrated Sage Native Blocks -**Blocks affected:** `cb/carousel` → `imagewize/carousel`, `cb/slide` → `imagewize/slide` - -## Database Changes - -### Development Environment -All commands run from Trellis VM due to local MariaDB port conflicts: - -```bash -# Enter Trellis VM -cd trellis -trellis vm shell -cd /srv/www/imagewize.com/current - -# Backup database first (107MB backup created) -wp db export /tmp/backup_$(date +%Y%m%d_%H%M%S).sql.gz --path=web/wp - -# Migrate block names (1,038 replacements) -wp search-replace 'wp:cb/carousel' 'wp:imagewize/carousel' wp_posts --precise --path=web/wp - -# Migrate slide blocks (1,037 replacements) -wp search-replace 'wp:cb/slide' 'wp:imagewize/slide' wp_posts --precise --path=web/wp - -# Migrate carousel CSS classes (1,037 replacements) -wp search-replace 'wp-block-cb-carousel' 'wp-block-imagewize-carousel' wp_posts --precise --path=web/wp - -# Migrate slide CSS classes (1,036 replacements) -wp search-replace 'wp-block-cb-slide' 'wp-block-imagewize-slide' wp_posts --precise --path=web/wp - -# Flush cache -wp cache flush --path=web/wp -``` - -### Results -- **Carousel blocks migrated:** 1,038 -- **Slide blocks migrated:** 1,037 -- **Total content updates:** ~4,150 replacements across all tables -- **Backup location:** `/tmp/backup_20251002_143321.sql.gz` (107MB) - -## Staging/Production Deployment - -When deploying to staging or production, run the same migration: - -```bash -cd trellis - -# Backup first -ansible-playbook database-backup.yml -e env=production -e site=imagewize.com - -# Run migration via Ansible -ansible -i hosts/production web -m shell -a "cd /srv/www/imagewize.com/current && wp search-replace 'wp:cb/carousel' 'wp:imagewize/carousel' wp_posts --precise --path=web/wp" - -ansible -i hosts/production web -m shell -a "cd /srv/www/imagewize.com/current && wp search-replace 'wp:cb/slide' 'wp:imagewize/slide' wp_posts --precise --path=web/wp" - -ansible -i hosts/production web -m shell -a "cd /srv/www/imagewize.com/current && wp search-replace 'wp-block-cb-carousel' 'wp-block-imagewize-carousel' wp_posts --precise --path=web/wp" - -ansible -i hosts/production web -m shell -a "cd /srv/www/imagewize.com/current && wp search-replace 'wp-block-cb-slide' 'wp-block-imagewize-slide' wp_posts --precise --path=web/wp" - -# Flush cache -ansible -i hosts/production web -m shell -a "cd /srv/www/imagewize.com/current && wp cache flush --path=web/wp" -``` - -## Code Changes - -### Theme Integration -- **Location:** `resources/js/blocks/carousel/` and `resources/js/blocks/slide/` -- **Assets:** Slick Carousel library copied to `resources/vendor/slick/` -- **Enqueue:** Custom render callback in `app/setup.php:320` for Slick library -- **Removed:** `imagewize/carousel-block` plugin via Composer - -### Block Configuration -**Carousel block.json:** -- Name: `imagewize/carousel` -- 18 attributes (slides, arrows, dots, colors, responsive settings) -- Supports: align (wide/full), anchor - -**Slide block.json:** -- Name: `imagewize/slide` -- Parent: `imagewize/carousel` -- Optional `slideId` attribute - -## Troubleshooting - -### Issue: Search-replace found 0 results -**Cause:** Including HTML comment prefix in search string -**Fix:** Search for `wp:cb/carousel` instead of ` -
-

Image Optimization Services

-
- -
-
-
Professional Solutions
-

Transform Your Website Performance

-

- Discover how our advanced image optimization tools help reduce file sizes by up to 80% while maintaining visual quality. Speed up your website, improve SEO rankings, and deliver better user experiences across all devices. -

-
-
- - -
-

Why Choose ImageWize

-

- This is sample content below the heading section to show how it integrates with the rest of your page layout. The gradient background with white text creates strong visual contrast and draws attention to your key message. -

-
- - \ No newline at end of file diff --git a/style.css b/style.css index 34551fe..446c193 100644 --- a/style.css +++ b/style.css @@ -2,7 +2,7 @@ Theme Name: Nynaeve Theme URI: https://imagewize.com Description: Modern WordPress theme built on Sage 11 with reusable custom blocks using WordPress native tools and the Roots.io stack. -Version: 2.0.13 +Version: 2.0.14 Author: Jasper Frumau Author URI: https://magewize.com Text Domain: nynaeve