Files
Umbra-Bookshelf/umbra-bookshelf/spec/SPEC_Umbra_Bookshelf_Plugin.md
bdm 5b5303186a Establish Umbra-Bookshelf as the successor repository
Continues the Bookshelf history. The three plugins tracked there are
consolidated into umbra-bookshelf/ and this repository becomes the canonical
home for the plugin and the theme.

  bd-bookshelf/  ->  theme/     separate artifact, name unchanged
  (root specs)   ->  umbra-bookshelf/spec/  aligned to Umbra Bookshelf
  old plugin zips -> archive/pre-umbra-releases/

Adds a repository README and drops the Bookshelf closure notice.
2026-10-18 19:56:26 -07:00

10 KiB

Umbra Bookshelf — Plugin Specification

Status: Active Version: 1.0.0 Supersedes: spec/archive/SPEC_BD_Bookshelf_Plugin.txt, spec/archive/SPEC_BD_BookHelper_Plugin.txt License: Apache-2.0


1. Identity

Field Value
Plugin name Umbra Bookshelf
Slug / folder umbra-bookshelf
Entry point umbra-bookshelf.php
Text domain umbra-bookshelf
Domain path /languages
Author Umbra Tools
Requires WordPress 6.0, PHP 7.4
Version 1.0.0

The three pre-merge plugins map onto modules as follows:

Former plugin Former version Module Code location
BD Bookshelf 0.1.0 Books (catalogue) includes/books/
BD BookShelfHelper 2.0.0 Library includes/library/
BD SimpleEmail 2.0.0 Email includes/email/

2. Naming rules

Two categories of identifier, treated differently on purpose.

2.1 Renamed to the Umbra Bookshelf identity

  • Plugin header fields (Plugin Name, Plugin URI, Author, Author URI, License).
  • Text domain: bd-bookshelf, bd-bookshelfhelper, bd-simpleemail → umbra-bookshelf.
  • PHP classes: BD_Bookshelf, BDM_*, BD_BookShelfHelper*, BD_SimpleEmail*, BD_Email_Sender → Umbra_*.
  • Constants: BD_BOOKSHELF_* → UMBRA_BOOKSHELF_*; BD_BHS_VERSION → UMBRA_BOOKSHELF_LIBRARY_VERSION; BD_EMAIL_* → UMBRA_BOOKSHELF_EMAIL_VERSION. BD_BHS_DIR / BD_EMAIL_URI were removed in favour of the single UMBRA_BOOKSHELF_DIR / UMBRA_BOOKSHELF_URL pair.
  • Asset handles, one per module so they cannot shadow each other: umbra-bookshelf-admin, umbra-bookshelf-library-admin, umbra-bookshelf-email-admin, umbra-bookshelf-gdpr.
  • JavaScript globals: bdBookshelfAdmin → umbraBookshelfAdmin, bdBookshelfGdpr → umbraBookshelfGdpr, bdmAdmin → umbraBookshelfLibraryAdmin.
  • Admin menu slugs (see §5).

2.2 Deliberately not renamed

These are the persisted contract with live installations and with published post content. Renaming any of them silently orphans existing data.

Contract Values
Table names bd_books, bd_series, bd_book_authors, bd_authors, bd_book_seo, bd_retail_links, bd_retail_sites, bd_shortcodes, bd_shortcode_clicks, bd_book_meta, bd_pen_names, bd_reviews, bd_ratings, bd_review_shortlinks, bd_subscribers, bd_newsletters
Option keys bd_bookshelf_db_version, bd_bookshelf_activation_time, bdm_affiliate_codes, bdm_goodreads_author_id, bdm_awards, bdm_gmail_address, bdm_gmail_password, bdm_sender_name, bdm_reply_to, bdm_gemini_api_key
Post meta _bd_bookshelf_book_id
Transient prefix _transient_bd_bookshelf_*
Nonce actions bd_bookshelf_admin_nonce, bd_bookshelf_import_posts, bd_bookshelf_import_csv, bd_bookshelf_admin, bd_bookshelf_gdpr_nonce
Cron hooks bd_bookshelf_sync_ratings, bd_bookshelf_goodreads_refresh, bd_bookshelf_amazon_scrape
AJAX actions bd_bookshelf_*, bdm_update_links, bdm_autosave, bdm_ajax_signup, bdm_signup_submit, bdm_unsubscribe_submit
Shortcodes [bd-book], [bd-books], [bdm_signup]
Content types post type book, taxonomy series
Cookies bd_bookshelf_consent
CSS classes bd-bookshelf-*, bd-email-* (paired HTML/CSS, may be styled by themes)

One legacy PHP class name is retained by design: class-umbra-theme-compatibility.php declares Umbra_Theme_Compatibility and then class_alias('Umbra_Theme_Compatibility', 'BD_BookShelfHelper') so the unmodified theme/ (bd-bookshelf) theme's static BD_BookShelfHelper:: calls keep working.


3. Architecture

umbra-bookshelf/
├── umbra-bookshelf.php          bootstrap: constants, requires, singleton, single top-level menu
├── uninstall.php                drops every table and option from all three modules
├── includes/
│   ├── books/                   catalogue: books, authors, series, retail, ratings,
│   │                            shortcodes, SEO, GDPR, scrapers, admin, import
│   ├── library/                 book post type + taxonomy, pen names, data entry,
│   │                            shortlinks, reviews, ratings, migrate
│   └── email/                   subscribers, newsletters, AI-assisted composition, sending
├── admin/       css, js         catalogue admin assets
├── public/      css, js         front-end + GDPR consent assets
├── library/     assets          library admin assets
├── email/       assets          email admin assets
├── assets/      images          default-cover.png
├── languages/                   translation catalogues
├── spec/                        this document; archive/ holds pre-merge specs
├── docs/                        architecture and known issues
└── tests/                       verify_structure.py, smoke_runtime.php

Boot order. Modules are constructed on plugins_loaded, not init. Several modules register their own init callbacks (post type, taxonomy, shortcodes, rewrite rules); constructing them from inside an init callback makes it accidental whether those callbacks run. A $modules_initialized flag prevents double construction.


4. Module responsibilities

4.1 Books (catalogue) — includes/books/

Owns the custom-table catalogue model: books with ISBN-10/13 and ASIN variants, author records and pen-name linkage, series, retail sites and per-format retail links, Goodreads and Amazon rating synchronisation, SEO rows, shortlink click tracking, GDPR consent, and CSV/post import.

Classes: Umbra_Database, Umbra_Book_Manager, Umbra_Authors, Umbra_Series, Umbra_Retail_Sites, Umbra_Rating_Sync, Umbra_Shortcodes, Umbra_SEO, Umbra_GDPR, Umbra_Goodreads_Scraper, Umbra_Amazon_Scraper, Umbra_Admin, Umbra_Migration, Umbra_Theme_Compatibility.

Umbra_SEO is never instantiated by the bootstrap (carried over unchanged from the original plugin). See docs/KNOWN-ISSUES.md item 5.

4.2 Library — includes/library/

Owns the WordPress-native model: registers post type book and taxonomy series, pen names, a focused data-entry screen, shortlink handling, reviews and ratings, and a migration screen for data created by earlier plugins.

Classes: Umbra_Bookshelf_Helper, Umbra_Bookshelf_Helper_Admin, Umbra_Bookshelf_Helper_Install.

4.3 Email — includes/email/

Owns newsletter delivery: subscriber and newsletter tables, [bdm_signup], signup and unsubscribe form handling (AJAX and admin_post), Gemini-assisted newsletter composition, and SMTP/Gmail sending.

Classes: Umbra_Simple_Email, Umbra_Simple_Email_Admin, Umbra_Simple_Email_Install, Umbra_Email_Sender.


5. Admin menu

One top-level menu, registered exactly once by the bootstrap at admin_menu priority 9. Each module contributes only submenus beneath it.

Umbra Bookshelf (umbra-bookshelf, dashicons-book-alt, position 30)

Submenu slug Module Capability
umbra-bookshelf bootstrap edit_posts
umbra-bookshelf-all books manage_options
umbra-bookshelf-add books manage_options
umbra-bookshelf-authors books manage_options
umbra-bookshelf-series books manage_options
umbra-bookshelf-sites books manage_options
umbra-bookshelf-shortcodes books manage_options
umbra-bookshelf-sync books manage_options
umbra-bookshelf-settings books manage_options
umbra-bookshelf-import books manage_options
edit.php?post_type=book library edit_posts
post-new.php?post_type=book library edit_posts
umbra-bookshelf-data-entry library edit_posts
edit-tags.php?taxonomy=series&post_type=book library manage_categories
umbra-bookshelf-pen-names library manage_options
umbra-bookshelf-library-settings library manage_options
umbra-bookshelf-migrate library manage_options
umbra-bookshelf-subscribers email manage_options
umbra-bookshelf-newsletter email manage_options
umbra-bookshelf-email-settings email manage_options

Catalogue and library settings are deliberately separate screens with separate slugs; the pre-merge plugins both claimed bd-bookshelf-settings, so one of the two was unreachable.


6. Lifecycle

  • Activate: create catalogue tables (Umbra_Database::create_tables()), library tables + roles (Umbra_Bookshelf_Helper_Install::activate()), email tables (Umbra_Simple_Email_Install::activate()), flush rewrites, record bd_bookshelf_activation_time.
  • Deactivate: clear all three cron hooks, run module deactivators, flush rewrites.
  • Uninstall: drop every table across all three modules (deduplicated so bd_books/bd_series are dropped once), delete bd_bookshelf_% options and transients, delete the bdm_* options, clear cron. Guarded by WP_UNINSTALL_PLUGIN.

7. Verification

python3 umbra-bookshelf/tests/verify_structure.py   # static checks
php umbra-bookshelf/tests/smoke_runtime.php front   # front-end boot
php umbra-bookshelf/tests/smoke_runtime.php admin   # admin boot + menu shape

The static check enforces: valid PHP syntax, no class declared twice, no reference to an undefined class, every require_once and enqueued asset resolves on disk, no leftover pre-merge identifiers in shipped source, and all preserved contracts of §2.2 still present.

The runtime check stubs WordPress, loads the bootstrap, fires plugins_loaded, init and admin_menu, and asserts the post type, taxonomy and shortcodes register, that exactly one top-level menu appears with all 20 expected submenus under it, that no callback is registered twice on a hook, and that asset handles are unique per module.


8. Open issues

bd_books and bd_series are created with two incompatible schemas by the books and library modules. This predates the consolidation and is not fixed here; see docs/KNOWN-ISSUES.md.