monorepo/native/wordpress/maple-fonts-wp/CLAUDE.md
2026-01-30 22:33:40 -05:00

9.4 KiB
Raw Blame History

CLAUDE.md — Maple Local Fonts WordPress Plugin

Quick Reference

Document When to Reference
CLAUDE.md (this file) Architecture, file structure, build order
SECURITY.md Writing ANY PHP code
GOOGLE_FONTS_API.md Building the font downloader class
WORDPRESS_COMPATIBILITY.md Building the font registry, FSE integration

Project Overview

Build a WordPress plugin called Maple Local Fonts that:

  1. Imports Google Fonts to local storage (one-time download)
  2. Registers them with WordPress's native Font Library API
  3. Fonts appear in FSE typography dropdowns alongside theme fonts

Key principle: Work WITH WordPress, not around it. We're a font importer — WordPress handles everything else.


Requirements

  • Minimum PHP: 7.4
  • Minimum WordPress: 6.5 (required for Font Library API)
  • License: GPL-2.0-or-later

User Flow

Admin enters "Open Sans" → selects weights (400, 700) → selects styles (normal, italic)
                ↓
Plugin hits Google Fonts CSS2 API (ONE TIME)
                ↓
Downloads WOFF2 files to wp-content/fonts/
                ↓
Registers font via WP Font Library API
                ↓
Font appears in Appearance → Editor → Styles → Typography dropdown
                ↓
User applies font using standard WordPress FSE controls
                ↓
GOOGLE NEVER CONTACTED AGAIN — fonts served locally

File Structure

maple-local-fonts/
├── maple-local-fonts.php          # Main plugin file
├── index.php                       # Silence is golden
├── uninstall.php                   # Clean removal
├── readme.txt                      # WordPress.org readme
├── includes/
│   ├── index.php                   # Silence is golden
│   ├── class-mlf-font-downloader.php
│   ├── class-mlf-font-registry.php
│   ├── class-mlf-admin-page.php
│   └── class-mlf-ajax-handler.php
├── assets/
│   ├── index.php                   # Silence is golden
│   ├── admin.css
│   └── admin.js
└── languages/
    ├── index.php                   # Silence is golden
    └── maple-local-fonts.pot

Class Responsibilities

MLF_Font_Downloader

  • Build Google Fonts CSS2 URL
  • Fetch CSS (with correct user-agent for WOFF2)
  • Parse CSS to extract font face data
  • Download WOFF2 files to wp-content/fonts/
  • Reference: GOOGLE_FONTS_API.md

MLF_Font_Registry

  • Register fonts with WP Font Library (wp_font_family, wp_font_face post types)
  • Delete fonts (remove posts and files)
  • List imported fonts
  • Reference: WORDPRESS_COMPATIBILITY.md

MLF_Admin_Page

  • Render settings page under Appearance menu
  • Font name input, weight checkboxes, style checkboxes
  • Display installed fonts with delete buttons
  • Reference: SECURITY.md for output escaping

MLF_Ajax_Handler

  • Handle download requests
  • Handle delete requests
  • Reference: SECURITY.md for nonce/capability checks

Admin Page UI

┌─────────────────────────────────────────────────────────┐
│ Maple Local Fonts                                       │
├─────────────────────────────────────────────────────────┤
│ IMPORT FROM GOOGLE FONTS                                │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Font Name: [Open Sans_________________________]    │ │
│ │                                                     │ │
│ │ Weights:                                            │ │
│ │ ☑ 400 (Regular)   ☐ 300 (Light)   ☐ 500 (Medium)  │ │
│ │ ☑ 700 (Bold)      ☐ 600 (Semi)    ☐ 800 (Extra)   │ │
│ │                                                     │ │
│ │ Styles:                                             │ │
│ │ ☑ Normal   ☑ Italic                                │ │
│ │                                                     │ │
│ │ Files to download: 4                                │ │
│ │                              [Download & Install]   │ │
│ └─────────────────────────────────────────────────────┘ │
│                                                         │
│ INSTALLED FONTS                                         │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Open Sans                                           │ │
│ │ 400 normal, 400 italic, 700 normal, 700 italic     │ │
│ │                                          [Delete]   │ │
│ ├─────────────────────────────────────────────────────┤ │
│ │ Roboto                                              │ │
│ │ 400 normal, 500 normal, 700 normal                 │ │
│ │                                          [Delete]   │ │
│ └─────────────────────────────────────────────────────┘ │
│                                                         │
│  Use Appearance → Editor → Styles → Typography to    │
│   apply fonts to your site.                            │
└─────────────────────────────────────────────────────────┘

Build Order

Phase 1: Foundation

  1. maple-local-fonts.php — Plugin header, constants, autoloader, activation hook
  2. index.php files in all directories (silence is golden)
  3. includes/class-mlf-ajax-handler.php — With full security checks (nonce, capability, validation)

Phase 2: Core Functionality

  1. includes/class-mlf-font-downloader.php — Google Fonts fetching/parsing/downloading
  2. includes/class-mlf-font-registry.php — WP Font Library integration

Phase 3: Admin Interface

  1. includes/class-mlf-admin-page.php — Settings page render
  2. assets/admin.css — Admin page styles
  3. assets/admin.js — AJAX handling for download/delete

Phase 4: Cleanup & Polish

  1. uninstall.php — Clean removal of fonts and data
  2. readme.txt — WordPress.org readme with privacy section
  3. Testing against all compatibility targets

Critical Reminders

Security (see SECURITY.md)

  • ABSPATH check on EVERY PHP file
  • index.php in EVERY directory
  • Nonce verification FIRST in every AJAX handler
  • Capability check SECOND
  • Input validation THIRD
  • Escape ALL output

Performance

  • Zero JavaScript on frontend
  • Zero CSS on frontend
  • All plugin code is admin-side only (except lightweight font registration)
  • Timeout handling on all external requests
  • Maximum limits to prevent infinite loops

GDPR

  • No user data collected
  • External requests only during admin import
  • Fonts served locally after import
  • Document in readme.txt

Compatibility (see WORDPRESS_COMPATIBILITY.md)

  • Declare WooCommerce HPOS compatibility
  • Use wp_get_font_dir() not hardcoded paths
  • Use Font Library API (post types) not theme.json filtering
  • Don't touch frontend, let Global Styles handle everything

Constants

define('MLF_VERSION', '1.0.0');
define('MLF_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('MLF_PLUGIN_URL', plugin_dir_url(__FILE__));
define('MLF_PLUGIN_BASENAME', plugin_basename(__FILE__));

// Limits
define('MLF_MAX_FONTS_PER_REQUEST', 10);
define('MLF_MAX_WEIGHTS_PER_FONT', 9);
define('MLF_REQUEST_TIMEOUT', 30);

WordPress Hooks Used

// Activation
register_activation_hook(__FILE__, 'mlf_activate');

// Admin menu
add_action('admin_menu', 'mlf_register_menu');

// Admin assets (our page only)
add_action('admin_enqueue_scripts', 'mlf_enqueue_admin_assets');

// AJAX (admin only, no nopriv)
add_action('wp_ajax_mlf_download_font', 'mlf_ajax_download');
add_action('wp_ajax_mlf_delete_font', 'mlf_ajax_delete');

// WooCommerce HPOS
add_action('before_woocommerce_init', 'mlf_declare_hpos_compatibility');

Testing Checklist

Functional

  • Import Open Sans 400, 700 normal + italic → 4 files created
  • Font appears in FSE typography dropdown
  • Apply font in Global Styles → frontend shows local font
  • Delete font → files and posts removed
  • Re-import same font → appropriate error message

Security

  • AJAX without nonce → 403
  • AJAX as subscriber → 403
  • Path traversal in font name → rejected
  • XSS in font name → sanitized
  • Direct PHP file access → blank/exit

Performance

  • No frontend network requests from plugin
  • Import 5 fonts → completes without timeout
  • Admin page load < 500ms added time

Compatibility

  • WordPress 6.5, 6.6+
  • Twenty Twenty-Five theme
  • WooCommerce (HPOS enabled)
  • Wordfence (enabled)
  • LearnDash
  • WPForms