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.
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 | 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_URIwere removed in favour of the singleUMBRA_BOOKSHELF_DIR/UMBRA_BOOKSHELF_URLpair. - 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_SEOis never instantiated by the bootstrap (carried over unchanged from the original plugin). Seedocs/KNOWN-ISSUES.mditem 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 |
manage_options |
|
umbra-bookshelf-newsletter |
manage_options |
|
umbra-bookshelf-email-settings |
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, recordbd_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_seriesare dropped once), deletebd_bookshelf_%options and transients, delete thebdm_*options, clear cron. Guarded byWP_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.