WordPress Blocks Support
Wash: Blog Manager provides comprehensive WordPress Gutenberg block support:
- All native blocks - Full HTML rendering support
- Block metadata sync - Block structure saved as Shopify metafields
- Custom Wash blocks - Embed Shopify products and collections directly in your content
- Optional CSS extraction - Include block styles for theme integration
How Block Processing Works
flowchart TD
A[WordPress Gutenberg Editor] --> B[Block-based Content]
B --> C[Wash Block Parser]
C --> D[WordPress Rendering]
D --> E[Clean HTML Output]
E --> F[Wash Processing]
F --> G[Shopify Article/Page]
B -.- B1["stored as comments"]
C -.- C1["Extract metadata, convert blocks, collect CSS"]
D -.- D1["apply_filters the_content"]
F -.- F1["URL rewriting, CDN replacement, link conversion"]
G -.- G1["HTML content, block metafields, optional CSS"]
Custom Wash Blocks
Shopify Product Block
Embed a Shopify product card directly in your WordPress content:
- Add the "Shopify Product" block in the editor
- Search and select a product from your Shopify store
- Choose display style (Card, Minimal, or Full)
- Configure price and button visibility
In Shopify: The block renders using your theme's product-card snippet via Liquid:
{% assign product = all_products["your-product-handle"] %}
{% render "product-card", product: product %}
Shopify Collection Block
Display a grid of products from a Shopify collection:
- Add the "Shopify Collection" block in the editor
- Select a collection from your store
- Set the number of columns (2-6)
- Choose how many products to display (1-24)
In Shopify: The block loops through collection products:
{% for product in collections["your-collection"].products limit: 6 %} {% render "product-card", product: product %}
{% endfor %}
Sync Status Block
An editor-only block showing the current sync status:
- Not synced - Post hasn't been synced yet
- Queued - Sync is in progress
- Synced - Shows Shopify URL and timestamp
- Error - Displays error message
This block is not rendered on the frontend.
Supported Native Blocks
Text Blocks
| Block | WordPress | Shopify Output | Status |
|---|---|---|---|
| Paragraph | core/paragraph | <p> | Full support |
| Heading | core/heading | <h1> - <h6> | Full support |
| List | core/list | <ul>, <ol> | Full support |
| Quote | core/quote | <blockquote> | Full support |
| Code | core/code | <pre><code> | Full support |
| Preformatted | core/preformatted | <pre> | Full support |
| Pullquote | core/pullquote | <figure><blockquote> | Full support |
| Verse | core/verse | <pre> | Full support |
| Details | core/details | <details><summary> | Full support |
Media Blocks
| Block | WordPress | Shopify Output | Status |
|---|---|---|---|
| Image | core/image | <figure><img> | Full support + CDN |
| Gallery | core/gallery | <figure> gallery | Full support + CDN |
| Audio | core/audio | <audio> | Partial (size limits) |
| Video | core/video | <video> | Limited (external recommended) |
| Cover | core/cover | <div> with background | Full support |
| Media & Text | core/media-text | Flex container | Full support |
| File | core/file | <a> download link | Full support |
Design Blocks
| Block | WordPress | Shopify Output | Status |
|---|---|---|---|
| Columns | core/columns | Flex container | Full support |
| Group | core/group | <div> wrapper | Full support |
| Row | core/row | Flex row | Full support |
| Stack | core/stack | Flex stack | Full support |
| Separator | core/separator | <hr> | Full support |
| Spacer | core/spacer | <div> with height | Full support |
| Buttons | core/buttons | Button container | Full support |
| Button | core/button | <a> styled link | Full support |
Widget Blocks
| Block | WordPress | Shopify Output | Status |
|---|---|---|---|
| Shortcode | core/shortcode | Rendered output | Depends on shortcode |
| Custom HTML | core/html | Raw HTML | Full support |
| Table | core/table | <table> | Full support |
Embed Blocks
| Block | WordPress | Shopify Output | Status |
|---|---|---|---|
| YouTube | core/embed | <iframe> | Full support |
| Vimeo | core/embed | <iframe> | Full support |
| Twitter/X | core/embed | Embed script | Partial |
core/embed | Embed script | Partial | |
| Spotify | core/embed | <iframe> | Full support |
| SoundCloud | core/embed | <iframe> | Full support |
| TikTok | core/embed | Embed script | Partial |
Image Handling
Automatic CDN Migration
Images in blocks are automatically processed:
WordPress (before sync):
<!-- wp:image {"id":123} -->
<figure class="wp-block-image"> <img src="https://yourblog.com/wp-content/uploads/2024/01/photo.jpg" alt="Description"/>
</figure>
<!-- /wp:image -->
Shopify (after sync):
<figure class="wp-block-image"> <img src="https://cdn.shopify.com/s/files/1/0123/4567/files/photo.jpg" alt="Description"/>
</figure>
Srcset Handling
WordPress responsive images (srcset) are simplified for Shopify's CDN:
<!-- WordPress srcset removed -->
<!-- Shopify CDN handles responsive images via image_url filter -->
Internal Link Handling
Links to other WordPress posts/pages are converted to Shopify URLs:
WordPress:
<a href="https://yourblog.com/my-article/">Read more</a>
Shopify:
<a href="/blogs/news/my-article">Read more</a>
Block Styling
CSS Class Preservation
Block CSS classes are preserved in Shopify:
<p class="has-large-font-size has-primary-color">Styled text</p>
Inline Styles
Inline styles from blocks are kept:
<div style="background-color:#f5f5f5;padding:20px">Content</div>
Theme Compatibility
For best results, ensure your Shopify theme includes basic block styles:
/* Add to your Shopify theme CSS */ /* Columns */
.wp-block-columns { display: flex; flex-wrap: wrap; gap: 1.5rem;
}
.wp-block-column { flex: 1; min-width: 200px;
} /* Buttons */
.wp-block-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem;
}
.wp-block-button__link { display: inline-block; padding: 0.75rem 1.5rem; background: var(--color-primary, #000); color: #fff; text-decoration: none; border-radius: 4px;
} /* Quote */
.wp-block-quote { border-left: 4px solid var(--color-primary, #000); padding-left: 1rem; margin-left: 0; font-style: italic;
} /* Separator */
.wp-block-separator { border: none; border-top: 2px solid #e0e0e0; margin: 2rem 0;
} /* Cover */
.wp-block-cover { position: relative; background-size: cover; background-position: center; min-height: 300px; display: flex; align-items: center; justify-content: center; padding: 2rem;
}
.wp-block-cover__inner-container { position: relative; z-index: 1;
} /* Media & Text */
.wp-block-media-text { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: center;
}
@media (max-width: 768px) { .wp-block-media-text { grid-template-columns: 1fr; }
} /* Table */
.wp-block-table table { width: 100%; border-collapse: collapse;
}
.wp-block-table th,
.wp-block-table td { border: 1px solid #e0e0e0; padding: 0.75rem; text-align: left;
} /* Gallery */
.wp-block-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem;
}
.wp-block-gallery .wp-block-image { margin: 0;
}
Blocks with Limited Support
Dynamic Blocks
Some WordPress blocks render dynamic content that won't work in Shopify:
| Block | Issue | Workaround |
|---|---|---|
| Latest Posts | Queries WP database | Use Shopify blog sections |
| Categories | WP-specific | Manual list or Shopify tags |
| Archives | WP-specific | Remove or replace |
| Comments | WP comments | Use Shopify comments |
| Search | WP search | Shopify search |
| Navigation | WP menus | Shopify navigation |
| Site Title/Logo | WP settings | Shopify theme settings |
Script-dependent Embeds
Some embeds require JavaScript that may not execute properly:
| Embed | Status | Solution |
|---|---|---|
| Twitter/X | May not render | Use static screenshot or link |
| May not render | Use static image or link | |
| TikTok | May not render | Use static image or link |
| May not render | Use static link |
Interactive Blocks
Blocks requiring user interaction have limitations:
| Block | Status | Notes |
|---|---|---|
| Forms | Won't work | Use Shopify forms or third-party |
| Accordions (plugins) | May work | Depends on implementation |
| Tabs (plugins) | May work | Depends on implementation |
| Sliders (plugins) | Usually won't work | Use Shopify sections |
Third-Party Block Plugins
Supported (HTML-based)
These plugin blocks generally work because they render to standard HTML:
- Kadence Blocks - Most layout blocks work
- Stackable - Basic blocks work
- GenerateBlocks - Layout blocks work
- CoBlocks - Most blocks work
Limited Support
These may have issues:
- Elementor - Complex structure, limited support
- Divi Builder - Proprietary format, not recommended
- WPBakery - Shortcode-heavy, partial support
- Beaver Builder - Limited support
Recommendation
For best compatibility:
- Use native WordPress blocks when possible
- Test third-party blocks before relying on them
- Avoid blocks that require plugin-specific JavaScript
Troubleshooting
Block Not Rendering
Symptoms: Block appears as comment or raw code
Solutions:
- Ensure block plugin is active in WordPress
- Check if block requires frontend JavaScript
- Test by viewing rendered HTML in WordPress before sync
Styling Lost
Symptoms: Content appears but styling is missing
Solutions:
- Add WordPress block CSS to Shopify theme
- Check if inline styles are preserved
- Use Custom CSS in Shopify theme editor
Images Missing
Symptoms: Images show broken or old URLs
Solutions:
- Re-sync the article
- Check image sync settings in Wash
- Verify images uploaded to Shopify Files
Embeds Not Working
Symptoms: Embed shows link instead of content
Solutions:
- Check if embed requires JavaScript
- Use iframe-based embeds when possible
- Consider static alternatives (screenshots, links)
Block Metadata
Wash automatically extracts and syncs block metadata to Shopify metafields under the wash_blocks namespace:
| Metafield | Description |
|---|---|
wash_blocks.structure | JSON array of all blocks with their types and attributes |
wash_blocks.counts | Count of each block type used |
wash_blocks.shopify_refs | References to Shopify products and collections |
wash_blocks.css | Extracted block CSS (if enabled) |
Metafield Structure Example
The wash_blocks.structure metafield contains a JSON array with block information:
{ "blocks": [ { "name": "core/paragraph", "attrs": { "align": "left" } }, { "name": "core/image", "attrs": { "id": 123, "sizeSlug": "large" } }, { "name": "wash/shopify-product", "attrs": { "productHandle": "premium-coffee", "style": "card" } }, { "name": "core/columns", "attrs": {}, "innerBlocks": [ { "name": "core/column", "attrs": { "width": "50%" } }, { "name": "core/column", "attrs": { "width": "50%" } } ] } ], "version": 2
}
Using Block Metadata in Liquid
Access block data in your Shopify theme Liquid templates:
Basic Access
{% comment %} Access block structure metafield {% endcomment %}
{% assign blocks_json = article.metafields.wash_blocks.structure.value %}
{% assign refs = article.metafields.wash_blocks.shopify_refs.value %} {% comment %} Check if article contains Shopify product embeds {% endcomment %}
{% if refs.products.size > 0 %} <div class="article-featured-products"> <h3>Featured Products in This Article</h3> <div class="product-grid"> {% for handle in refs.products %} {% assign product = all_products[handle] %} {% if product %} {% render 'product-card', product: product %} {% endif %} {% endfor %} </div> </div>
{% endif %}
Display Block Count Statistics
{% comment %} Show content statistics {% endcomment %}
{% assign counts = article.metafields.wash_blocks.counts.value %} {% if counts %} <div class="article-stats"> {% if counts.image > 0 %} <span class="stat">๐ท {{ counts.image }} images</span> {% endif %} {% if counts.video > 0 %} <span class="stat">๐ฌ {{ counts.video }} videos</span> {% endif %} {% if counts.embed > 0 %} <span class="stat">๐ {{ counts.embed }} embeds</span> {% endif %} </div>
{% endif %}
Render Embedded Collections
{% comment %} Render all collections referenced in the article {% endcomment %}
{% assign refs = article.metafields.wash_blocks.shopify_refs.value %} {% if refs.collections.size > 0 %} <section class="article-collections"> <h2>Shop the Collections</h2> {% for collection_handle in refs.collections %} {% assign collection = collections[collection_handle] %} {% if collection %} <div class="collection-preview"> <h3>{{ collection.title }}</h3> <div class="product-row"> {% for product in collection.products limit: 4 %} {% render 'product-card', product: product %} {% endfor %} </div> <a href="{{ collection.url }}" class="btn">View All {{ collection.title }}</a> </div> {% endif %} {% endfor %} </section>
{% endif %}
Conditional Styling Based on Blocks
{% comment %} Add CSS class based on block content {% endcomment %}
{% assign blocks_json = article.metafields.wash_blocks.structure.value %}
{% assign has_gallery = false %}
{% assign has_video = false %} {% if blocks_json %} {% for block in blocks_json.blocks %} {% if block.name == 'core/gallery' %} {% assign has_gallery = true %} {% endif %} {% if block.name == 'core/video' or block.name == 'core/embed' %} {% assign has_video = true %} {% endif %} {% endfor %}
{% endif %} <article class="article-content {% if has_gallery %}has-gallery{% endif %} {% if has_video %}has-media{% endif %}"> {{ article.content }}
</article>
Include Block CSS
{% comment %} Include extracted block CSS if available {% endcomment %}
{% assign block_css = article.metafields.wash_blocks.css.value %} {% if block_css and block_css != blank %} <style> {{ block_css }} </style>
{% endif %}
Complete Article Template Example
{% comment %} sections/article-template.liquid {% endcomment %}
<article class="article" itemscope itemtype="http://schema.org/BlogPosting"> <header class="article-header"> <h1 itemprop="headline">{{ article.title }}</h1> {% comment %} Show content stats from blocks metadata {% endcomment %} {% assign counts = article.metafields.wash_blocks.counts.value %} {% if counts %} <div class="article-meta"> <time datetime="{{ article.published_at | date: '%Y-%m-%d' }}"> {{ article.published_at | date: '%B %d, %Y' }} </time> {% if counts.image > 0 %} <span class="meta-item">{{ counts.image }} images</span> {% endif %} </div> {% endif %} </header> {% comment %} Include block CSS if enabled {% endcomment %} {% assign block_css = article.metafields.wash_blocks.css.value %} {% if block_css != blank %} <style>{{ block_css }}</style> {% endif %} {% comment %} Main content {% endcomment %} <div class="article-body" itemprop="articleBody"> {{ article.content }} </div> {% comment %} Featured products from article {% endcomment %} {% assign refs = article.metafields.wash_blocks.shopify_refs.value %} {% if refs.products.size > 0 %} <aside class="article-products"> <h3>Products Mentioned</h3> <div class="product-grid product-grid--{{ refs.products.size | at_most: 4 }}-col"> {% for handle in refs.products %} {% assign product = all_products[handle] %} {% if product %} {% render 'product-card', product: product, show_quick_add: true %} {% endif %} {% endfor %} </div> </aside> {% endif %}
</article>
Block Settings
Configure block behavior in Wash settings:
| Setting | Default | Description |
|---|---|---|
| Enable Wash blocks | On | Show custom Wash blocks in editor |
| Sync block metadata | On | Save block structure to metafields |
| Include block CSS | Off | Extract and sync block styles |
Shopify Theme CSS
WordPress blocks use specific CSS classes that need styling in your Shopify theme. Add this CSS to properly render all block types.
Quick Setup
- Create
assets/wp-blocks.cssin your Shopify theme - Include it in your article template:
{{ 'wp-blocks.css' | asset_url | stylesheet_tag }}
CSS Variables
Customize these variables to match your theme:
:root { --wp-primary-color: #000; --wp-secondary-color: #666; --wp-accent-color: #0073aa; --wp-border-color: #e0e0e0; --wp-background-light: #f8f9fa; --wp-border-radius: 4px; --wp-spacing: 1.5rem;
}
Essential Block Styles
Typography
.has-small-font-size { font-size: 0.875rem; }
.has-medium-font-size { font-size: 1.25rem; }
.has-large-font-size { font-size: 1.5rem; }
.has-x-large-font-size { font-size: 2rem; } .has-text-align-left { text-align: left; }
.has-text-align-center { text-align: center; }
.has-text-align-right { text-align: right; }
Images & Gallery
.wp-block-image img { max-width: 100%; height: auto; border-radius: var(--wp-border-radius);
} .wp-block-gallery { display: grid; gap: 1rem;
}
.wp-block-gallery.columns-2 { grid-template-columns: repeat(2, 1fr); }
.wp-block-gallery.columns-3 { grid-template-columns: repeat(3, 1fr); }
.wp-block-gallery.columns-4 { grid-template-columns: repeat(4, 1fr); } .wp-block-gallery.is-cropped img { width: 100%; height: 200px; object-fit: cover;
}
Cover Block
.wp-block-cover { position: relative; display: flex; align-items: center; justify-content: center; min-height: 400px; padding: 2rem; overflow: hidden;
} .wp-block-cover__image-background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0;
} .wp-block-cover__background.has-background-dim { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 1;
} .wp-block-cover__inner-container { position: relative; z-index: 2; color: #fff; text-align: center;
}
Columns
.wp-block-columns { display: flex; flex-wrap: wrap; gap: var(--wp-spacing);
} .wp-block-column { flex: 1; min-width: 0;
} @media (max-width: 768px) { .wp-block-columns { flex-direction: column; } .wp-block-column { flex-basis: 100%; }
}
Quote
.wp-block-quote { padding: 1.5rem 1.5rem 1.5rem 2rem; border-left: 4px solid var(--wp-accent-color); background: var(--wp-background-light); font-style: italic;
} .wp-block-quote cite { display: block; margin-top: 1rem; font-style: normal; color: var(--wp-secondary-color);
} .wp-block-quote cite::before { content: "โ ";
}
Buttons
.wp-block-buttons { display: flex; flex-wrap: wrap; gap: 0.75rem;
} .wp-block-button__link { display: inline-block; padding: 0.75rem 1.5rem; background: var(--wp-primary-color); color: #fff; text-decoration: none; border-radius: var(--wp-border-radius); font-weight: 500;
} .wp-block-button__link:hover { opacity: 0.9;
}
Table
.wp-block-table table { width: 100%; border-collapse: collapse;
} .wp-block-table th,
.wp-block-table td { padding: 0.75rem 1rem; border: 1px solid var(--wp-border-color); text-align: left;
} .wp-block-table thead th { background: var(--wp-background-light); font-weight: 600;
}
Separator
.wp-block-separator { border: none; border-top: 2px solid var(--wp-border-color); margin: 2rem 0;
} .wp-block-separator.is-style-dots { border: none; text-align: center;
} .wp-block-separator.is-style-dots::before { content: "ยทยทยท"; font-size: 1.5rem; letter-spacing: 1rem; color: var(--wp-secondary-color);
}
Embeds (YouTube, Vimeo)
.wp-block-embed__wrapper { position: relative; width: 100%;
} .wp-embed-aspect-16-9 .wp-block-embed__wrapper { padding-bottom: 56.25%;
} .wp-has-aspect-ratio .wp-block-embed__wrapper iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;
}
Rank Math FAQ (Third-party)
.rank-math-faq-item { margin-bottom: 1rem; border: 1px solid var(--wp-border-color); border-radius: var(--wp-border-radius);
} .rank-math-question { margin: 0; padding: 1rem; background: var(--wp-background-light); font-weight: 600;
} .rank-math-answer { padding: 1rem;
}
Download Complete CSS
For a complete CSS file with all block styles, responsive breakpoints, and color utilities:
Best Practices
- Test before bulk sync - Sync a few posts first to verify block rendering
- Use native blocks - Better compatibility than third-party plugins
- Add block CSS - Include WordPress block styles in your Shopify theme
- Use Wash blocks - Embed Shopify products instead of static images
- Avoid dynamic blocks - Replace with Shopify-native features
- Check embeds - Verify third-party embeds render correctly
- Keep it simple - Complex layouts may need adjustment for Shopify
- Preview in Shopify - Always review synced content appearance