Files
unsupervised-scheduler/CLAUDE.md
T
thatguygriff fc70cde9d5
CI / No Debug Code (pull_request) Successful in 4s
CI / Tests (PHP 8.2) (pull_request) Successful in 52s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Tests (PHP 8.3) (pull_request) Successful in 1m29s
CI / Coding Standards (pull_request) Successful in 1m57s
CI / PHPStan (pull_request) Successful in 2m14s
CI / Build Plugin Zip (pull_request) Has been skipped
Add Gutenberg dynamic-block wrappers for the front-end shortcodes
Wrap the four shortcodes (us_booking, us_student_login,
us_student_register, us_group_classes) in dynamic blocks so pages can be
previewed and styled in the block editor. Front-end rendering delegates
to the same page objects the shortcodes use; in the editor's
block-renderer REST preview a static, script-free BlockPreview is
rendered instead (no live REST calls, redirects, or Stripe.js). The
editor script (vanilla JS, no build step) registers each block with
wp.serverSideRender previews and shortcode transforms; frontend.css is
attached as the block style so previews pick up theme styling.

Resolves #44

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 12:03:27 -03:00

6.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

composer install                  # Install all dependencies

composer test                     # Run the full test suite (required after every change)
composer lint                     # PHPStan static analysis
composer cs                       # PHPCS coding standards check
composer cs:fix                   # Auto-fix coding standards

# Run a single test file
./vendor/bin/phpunit tests/Unit/Availability/AvailabilityRepositoryTest.php

# Run a single test by name
./vendor/bin/phpunit --filter testInsertCallsWpdbInsertAndReturnsId

Run composer test after every code change before considering a task complete.

Architecture

Plugin Bootstrap

unsupervised-schedular.php defines constants (USC_VERSION, USC_PLUGIN_DIR, USC_PLUGIN_URL), registers activation/deactivation hooks, then calls Plugin::boot() on plugins_loaded. No logic lives in the root file.

Directory Structure

src/                  — All plugin PHP (PSR-4 namespace: Unsupervised\Schedular\)
  Availability/       — Availability slots: value object, repository, controller, REST endpoint
  Booking/            — Lessons/bookings: value object, repository, controller, REST endpoint, shortcode page
  Auth/               — Roles, capabilities, login page
  Plugin.php          — Wires all components together on plugins_loaded
  Installer.php       — Creates DB tables and roles on activation
  Schema.php          — CREATE TABLE SQL for dbDelta
  AdminMenu.php       — Registers wp-admin menu pages
  RestRegistrar.php   — Registers all REST routes under us-scheduler/v1
  ShortcodeRegistrar.php — Registers [us_booking] and [us_student_login] shortcodes
  BlockRegistrar.php  — Registers Gutenberg dynamic-block wrappers for the shortcodes
  BlockPreview.php    — Static editor-preview markup for the blocks
templates/            — PHP view files included by controllers/shortcodes
assets/               — CSS and JS (vanilla JS, no build step)
tests/Unit/           — PHPUnit unit tests (PSR-4: Unsupervised\Schedular\Tests\)
  Availability/       — Tests for src/Availability/
  Booking/            — Tests for src/Booking/
  Auth/               — Tests for src/Auth/
docs/features/        — One markdown file per feature describing data model, API, and test locations

Code is organised package-by-domain (Availability, Booking, Auth). Each domain package contains everything related to that domain: value objects, repositories, controllers, REST endpoints, and shortcode pages. Cross-cutting wiring classes (Plugin, AdminMenu, RestRegistrar, ShortcodeRegistrar, Schema) live directly under src/.

Data Storage

Two custom database tables (created via dbDelta on activation):

  • {prefix}us_availability — instructor availability windows
  • {prefix}us_lessons — booked lessons

All database access goes through repository classes within their domain package. No direct $wpdb calls outside repositories.

Key Classes

Class Responsibility
Plugin Wires all components together on plugins_loaded
Installer Creates DB tables and roles on activation
Schema CREATE TABLE SQL strings for dbDelta
AdminMenu Registers wp-admin menu pages
RestRegistrar Registers all REST routes under us-scheduler/v1
ShortcodeRegistrar Registers [us_booking] and [us_student_login] shortcodes
BlockRegistrar Registers Gutenberg dynamic-block wrappers for the shortcodes
BlockPreview Static editor-preview markup for the blocks
Auth\RoleManager Registers us_instructor and us_student roles with custom caps
Auth\LoginPage Renders front-end student login form
Availability\AvailabilitySlot Immutable value object for a slot row
Availability\AvailabilityRepository CRUD for availability slots
Availability\AvailabilityController Instructor availability management page
Availability\AvailabilityEndpoint REST handlers for availability CRUD
Booking\Lesson Immutable value object for a lesson row
Booking\BookingRepository CRUD for lesson bookings
Booking\BookingEndpoint REST handlers for booking and status updates
Booking\BookingPage Renders student booking UI shell (JS takes over)
Booking\LessonController Admin and instructor lesson list pages

REST API Namespace

All endpoints live under /wp-json/us-scheduler/v1/. Permissions are enforced via permission_callback using capability checks (manage_availability, book_lesson), never role name checks.

Testing Approach

Tests use Brain\Monkey to stub WordPress functions without a full WP installation, and Mockery to mock $wpdb and other dependencies.

All test classes extend tests/Unit/TestCase.php, which handles Monkey\setUp() / Monkey\tearDown() and stubs all WP translation/escape functions automatically.

Brain\Monkey API notes:

  • Functions\when('fn')->alias(fn() => ...) — stub with a closure (NOT returnUsing())
  • Functions\when('fn')->justReturn($val) — stub returning a fixed value
  • Functions\expect('fn')->once()->with(...) — assert call count and arguments
  • Use Functions\when() (not Functions\expect()) when you need argument-routing (e.g. get_role returning different values per argument) to avoid chaining ambiguity
  • Mockery matchers (e.g. \Mockery::type()) inside plain PHP arrays do not work with with() — use \Mockery::on(fn($arr) => ...) or \Mockery::any() instead
  • When mocking $wpdb, set $mock->prefix = 'wp_' explicitly — it is a public property, not a method

Adding a Feature

  1. Write the feature doc in docs/features/<feature-name>.md (data model, API, classes, test paths).
  2. Create a domain package under src/<Domain>/ containing all classes for that feature.
  3. Add template(s) under templates/ if needed.
  4. Write unit tests under tests/Unit/<Domain>/ mirroring the src/<Domain>/ structure.
  5. Run composer test — all tests must pass before the feature is complete.

CI

Gitea Actions (.gitea/workflows/ci.yml) runs on every push and pull request:

  • lint — PHPCS WordPress coding standards
  • static-analysis — PHPStan level 6
  • test — PHPUnit on PHP 8.1, 8.2, 8.3
  • no-debug — rejects commits with var_dump, error_log, etc. in src/