SiamCafe · Blog
WordPress Block Theme Multi-tenant Design —
บทความ

WordPress Block Theme Multi-tenant Design —

เผยแพร่ 28 พฤษภาคม 2569

WordPress Block Theme

WordPress Block Theme Multi-tenant Full Site Editing FSE theme.json Block Patterns Multisite Network Global Styles Template Parts Domain Mapping Production

FeatureClassic ThemeBlock ThemeHybrid Theme
TemplatePHP filesHTML + BlocksPHP + Blocks
Stylingstyle.csstheme.jsonBoth
EditingCustomizerSite EditorBoth
PatternsLimitedFull supportFull support
Global Stylesไม่รองรับเต็มรูปแบบบางส่วน
เหมาะกับLegacy sitesNew projectsMigration

theme.json Configuration

=== theme.json for Block Theme ===

theme.json — Main configuration

{

"$schema": "https://schemas.wp.org/trunk/theme.json",

"version": 2,

"settings": {

"color": {

"palette": [

{ "slug": "primary", "color": "#1e40af", "name": "Primary" },

{ "slug": "secondary", "color": "#7c3aed", "name": "Secondary" },

{ "slug": "accent", "color": "#f59e0b", "name": "Accent" },

{ "slug": "background", "color": "#ffffff", "name": "Background" },

{ "slug": "foreground", "color": "#1f2937", "name": "Foreground" }

],

"gradients": [],

"defaultPalette": false

},

"typography": {

"fontFamilies": [

{

"fontFamily": "Inter, sans-serif",

"slug": "inter",

"name": "Inter",

"fontFace": [{

"fontFamily": "Inter",

"fontWeight": "400 700",

"fontStyle": "normal",

"src": ["file:./assets/fonts/inter.woff2"]

}]

}

],

"fontSizes": [

{ "slug": "small", "size": "0.875rem", "name": "Small" },

{ "slug": "medium", "size": "1rem", "name": "Medium" },

{ "slug": "large", "size": "1.5rem", "name": "Large" },

{ "slug": "x-large", "size": "2.25rem", "name": "Extra Large" }

]

},

"layout": {

"contentSize": "800px",

"wideSize": "1200px"

},

"spacing": {

"units": ["px", "rem", "%"],

"spacingSizes": [

{ "slug": "10", "size": "0.5rem", "name": "XS" },

{ "slug": "20", "size": "1rem", "name": "S" },

{ "slug": "30", "size": "1.5rem", "name": "M" },

{ "slug": "40", "size": "2rem", "name": "L" },

{ "slug": "50", "size": "3rem", "name": "XL" }

]

}

},

"styles": {

"color": { "background": "var(--wp--preset--color--background)", "text": "var(--wp--preset--color--foreground)" },

"typography": { "fontFamily": "var(--wp--preset--font-family--inter)", "fontSize": "var(--wp--preset--font-size--medium)" },

"elements": {

"h1": { "typography": { "fontSize": "var(--wp--preset--font-size--x-large)" } },

"button": { "color": { "background": "var(--wp--preset--color--primary)", "text": "#ffffff" } },

"link": { "color": { "text": "var(--wp--preset--color--primary)" } }

}

}

}

from dataclasses import dataclass

@dataclass

class ThemeComponent:

component: str

file_path: str

purpose: str

required: bool

components = [

ThemeComponent("theme.json", "theme.json", "Global styles and settings", True),

ThemeComponent("style.css", "style.css", "Theme metadata (name, version)", True),

ThemeComponent("Index Template", "templates/index.html", "Main fallback template", True),

ThemeComponent("Header Part", "parts/header.html", "Site header with nav", True),

ThemeComponent("Footer Part", "parts/footer.html", "Site footer", True),

ThemeComponent("Single Template", "templates/single.html", "Single post template", False),

ThemeComponent("Page Template", "templates/page.html", "Page template", False),

ThemeComponent("Patterns", "patterns/*.php", "Reusable block patterns", False),

]

print("=== Block Theme Structure ===")

for c in components:

req = "Required" if c.required else "Optional"

print(f" [{req}] {c.component}")

print(f" Path: {c.file_path} | Purpose: {c.purpose}")

Multisite Multi-tenant

=== WordPress Multisite Setup ===

wp-config.php — Enable Multisite

define('WP_ALLOW_MULTISITE', true);

After network setup:

define('MULTISITE', true);

define('SUBDOMAIN_INSTALL', true);

define('DOMAIN_CURRENT_SITE', 'example.com');

define('PATH_CURRENT_SITE', '/');

define('SITE_ID_CURRENT_SITE', 1);

define('BLOG_ID_CURRENT_SITE', 1);

.htaccess for Multisite

RewriteEngine On

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

RewriteBase /

RewriteRule ^index\.php$ - [L]

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule . /index.php [L]

WP-CLI — Manage Multisite

wp site create --slug=tenant-a --title="Tenant A" --email=admin@tenant-a.com

wp site create --slug=tenant-b --title="Tenant B" --email=admin@tenant-b.com

wp site list

wp theme enable my-block-theme --network

wp plugin activate woocommerce --url=tenant-a.example.com

Domain Mapping (WordPress 4.5+)

wp site create --slug=tenant-c --title="Tenant C"

-- In admin: Settings > Domains > Add tenant-c.com

Nginx Configuration per site

server {

listen 443 ssl http2;

server_name tenant-a.com www.tenant-a.com;

root /var/www/wordpress;

# ... standard WordPress config

}

@dataclass

class TenantSite:

tenant: str

domain: str

theme_variation: str

plugins: str

storage: str

users: int

tenants = [

TenantSite("Tenant A", "tenant-a.com", "Blue Corporate", "WooCommerce, Yoast", "5GB", 12),

TenantSite("Tenant B", "tenant-b.com", "Green Nature", "LearnDash, BuddyPress", "10GB", 45),

TenantSite("Tenant C", "tenant-c.com", "Purple Creative", "Elementor, WPForms", "3GB", 5),

TenantSite("Tenant D", "tenant-d.com", "Red Bold", "WooCommerce, Mailchimp", "8GB", 20),

]

print("\n=== Multi-tenant Sites ===")

for t in tenants:

print(f" [{t.tenant}] {t.domain}")

print(f" Theme: {t.theme_variation} | Users: {t.users}")

print(f" Plugins: {t.plugins} | Storage: {t.storage}")

Block Patterns

# === Block Patterns for Multi-tenant ===

# patterns/hero-section.php
# <?php
# /**
#  * Title: Hero Section
#  * Slug: mytheme/hero-section
#  * Categories: featured
#  * Keywords: hero, banner, header
#  */
# ?>
# <!-- wp:cover {"dimRatio":50} -->
# <div class="wp-block-cover">
#   <!-- wp:heading {"level":1} -->
#   <h1>Welcome to Our Site</h1>
#   <!-- /wp:heading -->
#   <!-- wp:paragraph -->
#   <p>Discover our services and solutions</p>
#   <!-- /wp:paragraph -->
#   <!-- wp:buttons -->
#   <div class="wp-block-buttons">
#     <!-- wp:button -->
#     <div class="wp-block-button"><a class="wp-block-button__link">Get Started</a></div>
#     <!-- /wp:button -->
#   </div>
#   <!-- /wp:buttons -->
# </div>
# <!-- /wp:cover -->

@dataclass
class BlockPattern:
    name: str
    slug: str
    category: str
    blocks_used: str
    tenant_customizable: bool

patterns = [
    BlockPattern("Hero Section", "mytheme/hero", "Featured", "Cover Heading Paragraph Buttons", True),
    BlockPattern("Pricing Table", "mytheme/pricing", "Commerce", "Columns Group Heading List Button", True),
    BlockPattern("Testimonials", "mytheme/testimonials", "Social", "Columns Quote Image Paragraph", True),
    BlockPattern("FAQ Accordion", "mytheme/faq", "Content", "Details Summary Paragraph", True),
    BlockPattern("CTA Banner", "mytheme/cta", "Featured", "Group Heading Paragraph Buttons", True),
    BlockPattern("Team Grid", "mytheme/team", "About", "Columns Image Heading Paragraph Social", True),
]

print("Block Patterns:")
for p in patterns:
    custom = "Customizable per tenant" if p.tenant_customizable else "Fixed"
    print(f"  [{p.name}] {p.slug}")
    print(f"    Category: {p.category} | Blocks: {p.blocks_used}")
    print(f"    {custom}")

performance = {
    "Page Cache": "WP Super Cache / Redis Object Cache",
    "CDN": "Cloudflare / BunnyCDN สำหรับ Static Assets",
    "Image": "WebP conversion + Lazy Loading",
    "Database": "Query Monitor + Index Optimization",
    "PHP": "OPcache enabled PHP 8.2+",
    "Cron": "Disable wp-cron ใช้ System Cron แทน",
}

print(f"\n\nPerformance Optimization:")
for k, v in performance.items():
    print(f"  [{k}]: {v}")

เคล็ดลับ

  • theme.json: กำหนดทุกอย่างใน theme.json ลด Custom CSS
  • Variations: ใช้ Style Variations แยก Look ต่อ Tenant
  • Patterns: สร้าง Block Patterns ให้ Tenant เลือกใช้
  • Multisite: ใช้ Multisite สำหรับ 5+ Tenant
  • Cache: ใช้ Object Cache + Page Cache ทุก Site

WordPress Block Theme คืออะไร

Full Site Editing FSE Block Editor HTML Template theme.json Block Patterns Global Styles Template Parts WordPress 6.0+ ไม่ต้อง PHP Template