Merge BD Bookshelf (0.1.0), BD BookShelfHelper (2.0.0) and BD SimpleEmail
(2.0.0) into a single plugin released as Umbra Bookshelf 1.0.0, with the
BD Bookshelf theme left as a separate, unrenamed artifact.
Modules
includes/books/ catalogue, ISBN/ASIN, series, retail, ratings, shortcodes,
SEO, GDPR, scrapers, admin, CSV/post import
includes/library/ book post type + series taxonomy, pen names, data entry,
shortlinks, reviews, migrate
includes/email/ subscribers, newsletters, composition, sending
Renamed: plugin headers, text domains (all three -> umbra-bookshelf), classes
(BD_*/BDM_* -> Umbra_*), constants (-> UMBRA_BOOKSHELF_*), asset handles, JS
globals and admin slugs.
Deliberately not renamed -- persisted contract with live installs and with
published post content: table names, option keys, post meta keys, transients,
nonce actions, cron hooks, AJAX actions, shortcodes ([bd-book], [bd-books],
[bdm_signup]), post type `book`, taxonomy `series`, cookies and CSS classes.
BD_BookShelfHelper survives only as a class_alias for the unmodified theme.
Collisions resolved
* class-umbra-theme-compatibility.php declared BD_BookShelfHelper, the same
name as the library module's helper. Latent while the plugins were
separate (only fired when both were active), but an unconditional fatal
once merged. Renamed to Umbra_Theme_Compatibility with a class_alias.
* All three modules called add_menu_page. One top-level menu is now
registered by the bootstrap at admin_menu priority 9.
* BD Bookshelf and BookShelfHelper both claimed bd-bookshelf-settings, leaving
one Settings screen unreachable -> umbra-bookshelf-settings and
umbra-bookshelf-library-settings.
* Catalogue and library both enqueued bd-bookshelf-admin; the second enqueue
was silently discarded -> unique handles per module.
* Umbra_Admin and Umbra_Migration both registered bd_bookshelf_import_csv, so
one handler silently replaced the other. The import page now lives only in
Umbra_Admin (the variant wired to the admin JS); Umbra_Migration keeps only
the preview/run endpoints it uniquely provides.
* Modules were constructed from an init callback, so their own init
registrations raced the hook being dispatched. Now constructed on
plugins_loaded behind a re-entrancy guard.
Also
* Missing assets created: assets/images/default-cover.png (referenced but
never committed, so every cover-less book 404'd) and email/assets/js/
admin.js (enqueued on every email admin page but never committed).
* Library module's strpos($hook, 'bd-bookshelf') asset check matched every
catalogue and email screen once slugs shared the umbra-bookshelf- prefix;
now matched against its own slug list.
* Consolidated uninstall deduplicates the double drop of bd_books/bd_series.
* Specs aligned to the new name; pre-merge specs retained under
spec/archive/ with provenance notes.
* Tests added: tests/verify_structure.py (static) and tests/smoke_runtime.php
(WordPress-stub runtime boot, front-end and admin contexts).
Deferred and recorded in docs/KNOWN-ISSUES.md: the catalogue and library
modules still create bd_books and bd_series with two incompatible schemas
(pre-existing, now unconditional), and Goodreads/Amazon scraping is still
implemented twice on shared cron hooks.
439 lines
16 KiB
Plaintext
439 lines
16 KiB
Plaintext
================================================================================
|
|
BD BOOKHELPER PLUGIN SPECIFICATION (Book Data Management)
|
|
================================================================================
|
|
|
|
Version: 2.0.0
|
|
Location: /wp-content/plugins/bd-bookshelfhelper/
|
|
|
|
================================================================================
|
|
1. OVERVIEW
|
|
================================================================================
|
|
|
|
This plugin is the core book data management system. It handles all aspects of
|
|
storing, retrieving, and displaying book information including titles, blurbs,
|
|
covers, ratings, reviews, and retailer links. It is designed to work
|
|
seamlessly with the BD BookShelf theme to provide an Amazon-style book display.
|
|
|
|
================================================================================
|
|
2. DUPLICATE INFORMATION FROM BD BOOKSHELF PLUGIN
|
|
================================================================================
|
|
|
|
For complete plugin details, see SPEC_BD_Bookshelf_Plugin.txt.
|
|
This specification duplicates key information for reference.
|
|
|
|
================================================================================
|
|
3. SHORTCODES FOR BOOK DISPLAY
|
|
================================================================================
|
|
|
|
The plugin provides two main shortcodes for displaying books:
|
|
|
|
[bd-book book="ID|TITLE"]
|
|
- Displays a single book by ID or title
|
|
- Uses render_book_display() for HTML output
|
|
|
|
[bd-books limit="-1" orderby="date" order="DESC"]
|
|
- Displays all books sorted by publish date (newest first)
|
|
- Default: Shows all books in DESC order by date
|
|
- Output wrapped in <div class="bd-books-list">
|
|
|
|
USAGE IN THEME:
|
|
Home page: [bd-books limit="3"] (shows 3 most recent books)
|
|
Books page: [bd-books limit="-1"] (shows all books)
|
|
|
|
================================================================================
|
|
4. AMAZON DETAIL LAYOUT OUTPUT
|
|
================================================================================
|
|
|
|
The plugin generates this specific HTML structure for the Amazon Detail layout:
|
|
|
|
<div class="bd-book-listing">
|
|
<div class="bd-book-entry">
|
|
|
|
<!-- LEFT COLUMN (25%) -->
|
|
<div class="bd-book-cover">
|
|
<a href="[book-url]">
|
|
<img src="[cover-url]" alt="[book-title] Cover">
|
|
</a>
|
|
<div class="bd-book-purchase">
|
|
<div class="bd-book-format-selector">
|
|
<button class="bd-book-format-btn active" data-format="ebook">eBook</button>
|
|
<button class="bd-book-format-btn" data-format="paperback">Paperback</button>
|
|
<button class="bd-book-format-btn" data-format="hardback">Hardback</button>
|
|
</div>
|
|
<div class="bd-book-retailers" data-book-id="[book-id]">
|
|
[retailer links with retailer-box class]
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RIGHT COLUMN (75%) -->
|
|
<div class="bd-book-details">
|
|
<h2 class="bd-book-title">
|
|
<a href="[book-url]">[book-title]</a>
|
|
</h2>
|
|
<p class="bd-book-byline">by [pen-name]</p>
|
|
|
|
<div class="bd-book-ratings">
|
|
<span class="rating-amazon">Amazon: [rating]/5</span>
|
|
<span class="rating-goodreads">Goodreads: [rating]/5</span>
|
|
</div>
|
|
|
|
<hr class="bd-book-separator">
|
|
|
|
<div class="bd-book-blurb">
|
|
[localized blurb with wpautop()]
|
|
</div>
|
|
|
|
<div class="bd-book-metadata">
|
|
<span class="metadata-genre">[genre]</span> |
|
|
<span class="metadata-pages">[pages] pages</span> |
|
|
<span class="metadata-language">[language]</span> |
|
|
<span class="metadata-publisher">[publisher]</span>
|
|
</div>
|
|
|
|
<div class="bd-book-categories">[category-list]</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
================================================================================
|
|
5. RETAILER LINKS (retailer-box styling)
|
|
================================================================================
|
|
|
|
Output via display_retailer_links() method:
|
|
|
|
```html
|
|
<a href="[url]" class="retailer-box retailer-[key]" target="_blank" rel="noopener noreferrer">[name]</a>
|
|
```
|
|
|
|
CLASSES:
|
|
retailer-box Base class (shared styling)
|
|
retailer-amazon Amazon - background: #FF9900
|
|
retailer-apple Apple Books - background: #b3b3b3
|
|
retailer-barnes Barnes & Noble - background: #8b0000
|
|
retailer-kobo Kobo - background: #f4f4f4
|
|
retailer-google Google Play - background: #ffffff
|
|
|
|
STYLING (matching Goodreads widget style):
|
|
.retailer-box {
|
|
display: inline-block;
|
|
padding: 10px 15px;
|
|
text-align: center;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 4px;
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
|
|
Unavailable retailers get: .retailer-unavailable (grayed out)
|
|
|
|
================================================================================
|
|
6. DATABASE SCHEMA (COMPLETE)
|
|
================================================================================
|
|
|
|
CREATE TABLE {prefix}bd_books (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
post_id BIGINT(20) NOT NULL UNIQUE,
|
|
pen_name_id BIGINT(20),
|
|
series_id BIGINT(20),
|
|
volume_number INT(11),
|
|
asin VARCHAR(20),
|
|
isbn VARCHAR(20),
|
|
publish_date DATE,
|
|
sort_order INT(11) DEFAULT 0,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE {prefix}bd_book_meta (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
book_id BIGINT(20) NOT NULL,
|
|
language_code VARCHAR(5) NOT NULL,
|
|
title VARCHAR(255),
|
|
blurb TEXT,
|
|
preview_excerpt TEXT,
|
|
pull_quotes JSON,
|
|
UNIQUE KEY book_language (book_id, language_code)
|
|
);
|
|
|
|
CREATE TABLE {prefix}bd_pen_names (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
pen_name VARCHAR(255) NOT NULL,
|
|
notes TEXT,
|
|
active TINYINT(1) DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE {prefix}bd_reviews (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
book_id BIGINT(20) NOT NULL,
|
|
comment_text TEXT,
|
|
synopsis TEXT,
|
|
source_name VARCHAR(255) NOT NULL,
|
|
source_url VARCHAR(500),
|
|
display_order INT(11) DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE {prefix}bd_ratings (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
book_id BIGINT(20) NOT NULL,
|
|
source VARCHAR(20) NOT NULL,
|
|
rating DECIMAL(3,2),
|
|
review_count INT(11),
|
|
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE KEY book_source (book_id, source)
|
|
);
|
|
|
|
CREATE TABLE {prefix}bd_series (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
slug VARCHAR(100) NOT NULL UNIQUE,
|
|
cover_attachment_id BIGINT(20),
|
|
header_attachment_id BIGINT(20),
|
|
blurb TEXT,
|
|
display_order INT(11) DEFAULT 0,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE {prefix}bd_review_shortlinks (
|
|
id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
book_id BIGINT(20) NOT NULL,
|
|
site_code VARCHAR(5) NOT NULL,
|
|
slug VARCHAR(20) NOT NULL UNIQUE,
|
|
destination_url VARCHAR(500),
|
|
status VARCHAR(20) DEFAULT 'pending',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
activated_at DATETIME
|
|
);
|
|
|
|
================================================================================
|
|
7. POST META FIELDS
|
|
================================================================================
|
|
|
|
The plugin stores metadata on 'book' post type:
|
|
|
|
IDENTIFICATION:
|
|
pen_name_id int FK to bd_pen_names
|
|
asin string Amazon ASIN (10 chars)
|
|
isbn string ISBN-13
|
|
short_link_slug string Short URL slug
|
|
|
|
SERIES & ORDER:
|
|
volume_number int Position in series
|
|
publish_date date Publication date
|
|
sort_order int Manual sort
|
|
|
|
RATINGS:
|
|
amazon_rating string e.g., "4.5"
|
|
goodreads_rating string e.g., "4.2"
|
|
|
|
LOCALIZED CONTENT (en, fr, de, es, it, pt, ru, ja, zh):
|
|
title_{lang} Title in language
|
|
blurb_{lang} Description in language
|
|
preview_excerpt_{lang} Preview text
|
|
pull_quote_{lang}_{n} Pull quotes 1-5
|
|
genre_tags_{lang} Genre tags
|
|
amazon_search_terms_{lang} Amazon keywords
|
|
cover_{lang} Cover image ID
|
|
|
|
RETAILER LINKS:
|
|
{format}_url_{retailer}
|
|
|
|
Format keys: ebook, paperback, hardback, audiobook
|
|
Retailer keys: amazon, apple, barnes, kobo, google, bookshop,
|
|
amazon_uk, waterstones, audible, scribner
|
|
|
|
EXAMPLES:
|
|
ebook_url_amazon
|
|
paperback_url_barnes
|
|
hardback_url_amazon
|
|
audiobook_url_audible
|
|
|
|
================================================================================
|
|
8. HELPER METHODS FOR THEME USE
|
|
================================================================================
|
|
|
|
BD_BookShelfHelper::get_cover_url($book_id, $size = 'thumbnail', $lang = 'en')
|
|
Returns cover image URL with language fallback
|
|
|
|
BD_BookShelfHelper::get_ratings($book_id)
|
|
Returns: array('amazon' => '4.5', 'goodreads' => '4.2')
|
|
|
|
BD_BookShelfHelper::get_retailer_links($book_id, $format = 'ebook')
|
|
Returns array of retailer link data
|
|
|
|
BD_BookShelfHelper::display_retailer_links($book_id, $format = 'ebook')
|
|
Echos retailer links with retailer-box classes
|
|
|
|
BD_BookShelfHelper::get_localized_title($book_id, $lang = 'en')
|
|
Gets title in specified language (falls back to English)
|
|
|
|
BD_BookShelfHelper::get_localized_blurb($book_id, $lang = 'en')
|
|
Gets blurb in specified language
|
|
|
|
BD_BookShelfHelper::get_pen_name($book_id)
|
|
Gets author pen name
|
|
|
|
BD_BookShelfHelper::get_series_info($book_id)
|
|
Returns: array('id', 'name', 'slug', 'volume')
|
|
|
|
BD_BookShelfHelper::get_supported_languages()
|
|
Returns: array('en'=>'English', 'fr'=>'Francais', etc.)
|
|
|
|
================================================================================
|
|
9. MULTI-LANGUAGE IMPLEMENTATION
|
|
================================================================================
|
|
|
|
Supported Languages (9):
|
|
en, fr, de, es, it, pt, ru, ja, zh
|
|
|
|
Data Storage:
|
|
- Each language stores its own meta field: title_en, title_fr, blurb_en, etc.
|
|
- get_localized_blurb($book_id, 'fr') returns blurb_fr meta
|
|
- Falls back to English if requested language not set
|
|
|
|
Admin Interface:
|
|
- Language tabs in data entry form
|
|
- Each language panel contains: title, blurb, preview, pull quotes, genre, search terms
|
|
|
|
================================================================================
|
|
10. CSS CLASSES OUTPUT BY PLUGIN
|
|
================================================================================
|
|
|
|
FRONTEND (theme must style these):
|
|
.bd-book-listing Outer container
|
|
.bd-book-entry Flex container
|
|
.bd-book-cover Left column (25%)
|
|
.bd-book-purchase Purchase section
|
|
.bd-book-format-selector Format buttons container
|
|
.bd-book-format-btn Format buttons
|
|
.bd-book-format-btn.active Active format
|
|
.bd-book-retailers Retailer links container
|
|
.bd-book-details Right column (75%)
|
|
.bd-book-title Title heading
|
|
.bd-book-byline "by Author" line
|
|
.bd-book-ratings Ratings container
|
|
.rating-amazon Amazon rating
|
|
.rating-goodreads Goodreads rating
|
|
.bd-book-separator HR divider
|
|
.bd-book-blurb Description
|
|
.bd-book-metadata Metadata row
|
|
.metadata-genre Genre span
|
|
.metadata-pages Pages span
|
|
.metadata-language Language span
|
|
.metadata-publisher Publisher span
|
|
.bd-book-categories Categories
|
|
.bd-books-list Multiple books wrapper
|
|
.bd-book-error Error message
|
|
|
|
RETAILER LINKS:
|
|
.retailer-box Base class
|
|
.retailer-amazon Amazon styling
|
|
.retailer-apple Apple Books styling
|
|
.retailer-barnes B&N styling
|
|
.retailer-kobo Kobo styling
|
|
.retailer-google Google Play styling
|
|
.retailer-unavailable Disabled/grayed out
|
|
|
|
================================================================================
|
|
11. REQUIRED CSS VARIABLES (from theme)
|
|
================================================================================
|
|
|
|
The plugin expects these CSS variables to be defined by the theme:
|
|
|
|
:root {
|
|
--bdm-navy: #1B3A6B; /* Primary color - headers, nav */
|
|
--bdm-slate: #2E6DA4; /* Hover states */
|
|
--bdm-sky: #4A90D9; /* Links on hover */
|
|
--bdm-gold: #C8A96E; /* Accent - highlights, borders */
|
|
--bdm-cream: #F5F0E8; /* Page background */
|
|
--bdm-parchment: #EDE4D0; /* Alternate background */
|
|
--bdm-body-text: #2C2C2C; /* Primary text */
|
|
--bdm-mid-grey: #555555; /* Secondary text, bylines */
|
|
--bdm-light-grey: #888888; /* Metadata text */
|
|
--bdm-active-green: #2D6A4F; /* Active/positive states */
|
|
--bdm-heading-font: "Playfair Display", Georgia, serif;
|
|
--bdm-body-font: "Lato", Calibri, sans-serif;
|
|
--bdm-card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
--bdm-card-shadow-hover: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
--bdm-border-radius: 8px;
|
|
--bdm-transition: all 0.3s ease;
|
|
}
|
|
|
|
================================================================================
|
|
12. CUSTOM POST TYPES & TAXONOMIES
|
|
================================================================================
|
|
|
|
CPT: book
|
|
Public: Yes
|
|
Has Archive: Yes (/book)
|
|
REST API: Yes
|
|
Supports: title, editor, thumbnail, excerpt, custom-fields
|
|
|
|
Taxonomy: series
|
|
Hierarchical: Yes
|
|
Object Type: book
|
|
REST API: Yes
|
|
|
|
================================================================================
|
|
13. ADMIN FEATURES
|
|
================================================================================
|
|
|
|
Admin Pages (under BD BookHelper menu):
|
|
- Dashboard: Overview stats
|
|
- Book Data Entry: Multi-language form interface
|
|
- Series: Taxonomy management
|
|
- Short Links: URL slug management
|
|
- Reviews: Review management
|
|
- Pen Names: Author name CRUD
|
|
- Settings: Affiliate codes, Goodreads ID
|
|
- Migrate: From BD Books plugin
|
|
|
|
Meta Boxes on book posts:
|
|
- Book Details: ASIN, ISBN, publish date, series, volume
|
|
- Book SEO: Custom title, description
|
|
|
|
================================================================================
|
|
14. INTEGRATION WITH THEME
|
|
================================================================================
|
|
|
|
Nav Integration:
|
|
Hooks into 'bdm_nav_menu_items' filter to add Series dropdown
|
|
Adds My Books submenu with all book titles
|
|
Adds Series submenu with series taxonomy terms
|
|
|
|
Short Link Handling:
|
|
Registers rewrite rule for /[slug]/ pattern
|
|
Redirects to book when short link accessed
|
|
|
|
Schema.org Data:
|
|
generate_schema() creates JSON-LD structured data
|
|
output_seo_tags() outputs Open Graph and meta tags
|
|
|
|
================================================================================
|
|
15. ACTIVATION REQUIREMENTS
|
|
================================================================================
|
|
|
|
On activation, creates:
|
|
- Database tables
|
|
- book_manager role (limited capabilities)
|
|
- Default pen name "B.D. Murphy"
|
|
- Scheduled cron for Goodreads/Amazon updates
|
|
|
|
On deactivation:
|
|
- Removes book_manager role
|
|
- Clears cron events
|
|
- Flushes rewrite rules
|
|
|
|
================================================================================
|
|
16. AJAX HANDLERS
|
|
================================================================================
|
|
|
|
wp_ajax_bdm_autosave - Auto-save form data
|
|
wp_ajax_bdm_scan_retailers - Scan retailer websites
|
|
wp_ajax_bdm_update_links - Update retailer links
|
|
|
|
All require:
|
|
- check_ajax_referer() verification
|
|
- current_user_can('edit_posts') capability check
|
|
|
|
================================================================================ |