Files
Bookshelf/bd-bookshelf-plugin-spec-0.0.1.md
bdm 38cdebd0c6 Track Bookshelf WordPress theme, plugins and specs
Initial import of the bdmurphy Bookshelf work: the bd-bookshelf theme,
bd-bookshelf-plugin, bd-bookshelfhelper and bd-simpleemail plugins, plus
the specification documents, mockups and release archives.
2026-09-28 06:24:25 -07:00

32 KiB

BD Bookshelf Plugin - Technical Specification v0.0.1

1. Overview

The bd-bookshelf plugin is a WordPress plugin designed to work alongside the bd-bookshelf theme. It provides book management via custom database tables, automated retail link generation via ISBN/ASIN, rating synchronization from Amazon and Goodreads via web scraping, marketing shortcodes, GDPR compliance, SEO metadata management, and book series management.

Plugin Slug: bd-bookshelf Text Domain: bd-bookshelf Requires WordPress: 6.0+ Requires PHP: 7.4+ License: GPLv2 or later


2. WordPress Requirements & Best Practices

This plugin MUST comply with all WordPress.org Plugin Directory guidelines and security best practices.

  • All code must be compatible with GPLv2 or later
  • Include copyright information in plugin header
  • Include license file (license.txt or LICENSE)
  • Third-party libraries must be GPL-compatible
  • Provide attribution for bundled assets in readme.txt

2.2 Plugin Header Requirements

/**
 * Plugin Name: BD Bookshelf
 * Plugin URI: https://authorbdmurphy.com/plugins/bd-bookshelf
 * Description: Book management plugin for authors with ISBN tracking, retail links, and rating synchronization.
 * Version: 0.0.1
 * Author: B.D. Murphy
 * Author URI: https://authorbdmurphy.com
 * License: GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: bd-bookshelf
 * Domain Path: /languages
 * Requires at least: 6.0
 * Requires PHP: 7.4
 */

2.3 Security Requirements

Data Validation & Sanitization

  • Never trust user input - validate all data before processing
  • Use sanitize_text_field(), sanitize_email(), absint(), etc.
  • Validate data types and ranges before database insertion
  • Use wp_unslash() to remove magic quotes from user input

Data Escaping

  • Escape as late as possible - escape all output
  • Use esc_html() for HTML output
  • Use esc_attr() for HTML attributes
  • Use esc_url() for URLs
  • Use esc_js() for inline JavaScript
  • Use wp_kses() or wp_kses_post() for allowed HTML

Nonce Verification

  • Always verify nonces on form submissions and AJAX requests
  • Use wp_nonce_field() in forms
  • Use wp_create_nonce() and wp_verify_nonce() in AJAX
  • Name nonces with pattern: bd-bookshelf_{action}_{object}_{id}

Capability Checks

  • Check user capabilities before any privileged action
  • Use current_user_can() with appropriate capability
  • Never rely on user roles alone - use capabilities
  • Minimum capability for most actions: manage_options

SQL Injection Prevention

  • Never concatenate user input into SQL queries
  • Always use $wpdb->prepare() with parameterized queries
  • Use %s for strings, %d for integers, %f for floats
  • Example: $wpdb->prepare("SELECT * FROM {$table} WHERE id = %d", $id)

2.4 Database Best Practices

Table Creation

  • Use dbDelta() for table creation and updates
  • Include utf8mb4 charset for full Unicode support
  • Use bigint(20) unsigned for primary keys and foreign keys
  • Include created_at and updated_at timestamps
  • Add proper indexes for frequently queried columns

Table Naming

  • Prefix all tables with $wpdb->prefix (e.g., wp_bd_books)
  • Use lowercase with underscores for table names
  • Use singular nouns for table names (e.g., wp_bd_book not wp_bd_books)

Query Optimization

  • Use $wpdb->get_results() for multiple rows
  • Use $wpdb->get_row() for single row
  • Use $wpdb->get_var() for single value
  • Use $wpdb->query() for INSERT/UPDATE/DELETE
  • Always use $wpdb->prepare() for parameterized queries

2.5 Code Standards

PHP Coding Standards

  • Follow WordPress Coding Standards (WPCS)
  • Use K&R bracing style (opening brace on same line)
  • Use spaces, not tabs (4 spaces per indent)
  • Use snake_case for function names and variables
  • Use PascalCase for class names
  • Prefix all functions with plugin slug (e.g., bd_bookshelf_)
  • Prefix all classes with BDM_ (e.g., BDM_Book_Manager)

File Organization

bd-bookshelf/
├── bd-bookshelf.php              (main plugin file)
├── readme.txt                    (WordPress.org format)
├── license.txt                   (GPLv2 license)
├── uninstall.php                 (cleanup on uninstall)
├── includes/
│   ├── class-bdm-book-manager.php
│   ├── class-bdm-rating-sync.php
│   ├── class-bdm-shortcodes.php
│   └── class-bdm-admin.php
├── admin/
│   ├── css/
│   ├── js/
│   └── partials/
├── public/
│   ├── css/
│   └── js/
├── languages/
│   └── bd-bookshelf.pot
└── assets/
    ├── icons/
    └── images/

2.6 Hook Best Practices

Actions

  • Use add_action() with specific priority when order matters
  • Avoid hooks that fire too frequently (e.g., init without priority)
  • Prefix hook callback functions with plugin slug
  • Example: add_action('admin_menu', 'bd_bookshelf_admin_menu', 10);

Filters

  • Always return a value from filter callbacks
  • Use has_filter() to check if filter exists before removing
  • Example: add_filter('the_content', 'bd_bookshelf_shortcode_output', 20);

2.7 AJAX Security

// Admin AJAX
add_action('wp_ajax_bd_bookshelf_save_book', 'bd_bookshelf_ajax_save_book');
add_action('wp_ajax_nopriv_bd_bookshelf_save_book', 'bd_bookshelf_ajax_save_book');

function bd_bookshelf_ajax_save_book() {
    // 1. Verify nonce
    if (!wp_verify_nonce($_POST['nonce'], 'bd_bookshelf_save_book_' . $_POST['book_id'])) {
        wp_send_json_error('Invalid nonce');
    }
    
    // 2. Check capabilities
    if (!current_user_can('manage_options')) {
        wp_send_json_error('Insufficient permissions');
    }
    
    // 3. Sanitize input
    $title = sanitize_text_field($_POST['title']);
    
    // 4. Process and respond
    wp_send_json_success(['id' => $book_id]);
}

2.8 Internationalization

  • Use bd-bookshelf text domain throughout plugin
  • Wrap all user-facing strings in translation functions
  • Use esc_html_e() for escaped translated output
  • Use esc_html__() for escaped translated return values
  • Include .pot file in /languages directory
  • Use load_plugin_textdomain() in main plugin file

2.9 Uninstall Cleanup

  • Implement uninstall.php for cleanup when plugin is deleted
  • Remove all custom tables (prefix: wp_bd_)
  • Remove all options (prefix: bd_bookshelf_)
  • Remove all transients (prefix: bd_bookshelf_)
  • Check WP_UNINSTALL_PLUGIN constant before executing

2.10 Performance Best Practices

  • Use transients for cached data (e.g., ratings)
  • Implement proper pagination for large datasets
  • Use background processing for heavy operations (WP-Cron)
  • Minimize database queries in loops
  • Use $wpdb->get_results() with OBJECT_K for keyed results
  • Implement proper caching strategies

2.11 Plugin Check Compliance

The plugin MUST pass the WordPress Plugin Check tool with no errors:

Required Checks

  • No PHP errors, warnings, or notices
  • No security vulnerabilities flagged
  • Proper data sanitization and escaping
  • Nonce verification on all forms
  • Capability checks on privileged actions
  • Proper SQL query parameterization
  • No deprecated function usage
  • Proper hook priority settings
  • Efficient database queries
  • Proper error handling

2.12 Readme Requirements

=== BD Bookshelf ===
Contributors: bdmurphy
Requires at least: 6.0
Tested up to: 6.5
Requires PHP: 7.4
Stable tag: 0.0.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Copyright 2026 B.D. Murphy

Book management plugin for authors with ISBN tracking, retail links, and rating synchronization.

== Description ==
[Detailed description]

== Installation ==
[Step-by-step instructions]

== Frequently Asked Questions ==
[Common questions and answers]

== Changelog ==
[Version history]

== Upgrade Notice ==
[Upgrade information]

== Resources ==
[Third-party asset attributions]

2.13 Version Management

  • Increment version number for each release
  • Update Stable tag in readme.txt
  • Update Version in plugin header
  • Update Tested up to for WordPress compatibility
  • Document changes in Changelog section

2.14 Privacy & GDPR Compliance

  • Do not track users without explicit consent
  • Provide privacy policy text for plugin data collection
  • Implement cookie consent mechanism
  • Allow users to opt-out of tracking
  • Document all data collection in privacy policy

2.15 Third-Party Libraries

  • Include only GPL-compatible libraries
  • Bundle libraries locally (no CDN without consent)
  • Include original source files
  • Provide attribution in readme.txt
  • Keep libraries updated for security

3. Core Entities

2.1 Book

The primary entity managed by the plugin. Stored in custom database tables for performance and future plugin integration.

Field Type Description
id bigint Primary key (auto-increment)
title varchar(255) The book title
description text Book description/blurb
cover_image varchar(500) URL to book cover image
isbn_ebook varchar(20) ISBN for eBook format
isbn_paperback varchar(20) ISBN for Paperback format
isbn_hardcover varchar(20) ISBN for Hard Cover format
isbn_audio varchar(20) ISBN/Audio ASIN for Audio format
amazon_asin varchar(20) Amazon ASIN (may differ from ISBN)
goodreads_id varchar(20) Goodreads book ID
rating_amazon decimal(3,2) Latest Amazon rating (synced)
rating_goodreads decimal(3,2) Latest Goodreads rating (synced)
last_sync datetime Last rating synchronization timestamp
series_id bigint Reference to Series (optional)
series_order int Order within series (optional)
created_at datetime Creation timestamp
updated_at datetime Last update timestamp

2.2 Book Author

Supports up to three authors per book.

Field Type Description
id bigint Primary key
book_id bigint Reference to Book
author_name varchar(255) Author display name
author_id bigint WordPress user ID (if applicable)
goodreads_author_id varchar(20) Goodreads Author ID
is_primary tinyint(1) 1 if primary author
sort_order int Display order (1-3)

2.3 Series

Book series management.

Field Type Description
id bigint Primary key
name varchar(255) Series name
description text Series description
cover_image varchar(500) Series cover image URL
created_at datetime Creation timestamp

2.4 Retail Site

Predefined and custom retail sites where books are sold.

Field Type Description
id bigint Primary key
name string Site name (e.g., "Amazon")
url_pattern text URL pattern with {ISBN} placeholder
icon varchar(255) Icon identifier or URL
affiliate_param varchar(50) Query parameter for affiliate code
affiliate_code varchar(100) Affiliate code for this site
is_custom tinyint(1) 1 if user-created site
is_active tinyint(1) 1 if site is enabled
created_at datetime Creation timestamp

Default Sites:

  • Amazon (amazon.com/dp/{ISBN}) - ?tag=
  • Barnes & Noble (barnesandnoble.com/w/{ISBN}) - TBD
  • Apple Books (books.apple.com/book/{ISBN}) - TBD
  • Google Play Books (play.google.com/store/books/details?id={ISBN}) - TBD
  • Kobo (kobo.com/us/en/ebook/{ISBN}) - TBD

Note: Affiliate parameter names for B&N, Apple, Google, Kobo will be researched and provided in a specification update.

Maps books to retail sites with format-specific links.

Field Type Description
id bigint Primary key
book_id bigint Reference to Book
site_id bigint Reference to Retail Site
format varchar(20) ebook, paperback, hardcover, audio
url text Generated or manual URL
is_custom tinyint(1) 1 if manually entered
created_at datetime Creation timestamp

2.6 Custom Shortcode

User-defined shortcodes for URL redirection. Primary use case: books cannot link directly to competitor sites, so authors use shortcodes on their author site that redirect to retail/review pages.

Field Type Description
id bigint Primary key
slug varchar(100) The shortcode identifier (unique)
target_url text Destination URL
redirect_type varchar(10) 301, 302, 307
description text Internal note
click_count bigint Total clicks
is_active tinyint(1) 1 if live
created_at datetime Creation timestamp

2.7 Click Analytics

Detailed click tracking for custom shortcodes.

Field Type Description
id bigint Primary key
shortcode_id bigint Reference to Custom Shortcode
clicked_at datetime Click timestamp
ip_address varchar(45) User IP (anonymized for GDPR)
user_agent text Browser user agent
referer varchar(500) HTTP referer

4. Core Modules

3.1 Book Management Module

Admin Page: Books > Add New Book

  • Form to enter book title, description, cover image
  • Four ISBN input fields (eBook, Paperback, Hard Cover, Audio)
  • Amazon ASIN field (optional, auto-populated from ISBN if possible)
  • Goodreads Book ID field (optional, auto-populated via search)
  • Author selection (up to 3 authors per book)
  • Series assignment (optional)
  • Retail link grid showing generated and custom links
  • SEO metadata fields (Title, Description, Keywords)

Data Storage: Custom database tables (not CPT)

3.2 Author Management

Admin Page: Books > Authors

  • Manage author entries
  • Link to WordPress user accounts
  • Store Goodreads Author IDs
  • Auto-detect author ID from theme configuration (fallback to manual entry in settings)
  • Show all authors equally (no primary author highlighting)
  • Primary author: uploaded photo; other authors: WordPress avatar

3.3 Series Management

Admin Page: Books > Series

  • Create/edit/delete book series
  • Assign books to series (one series per book)
  • Books ordered by publication date within series
  • Series description and cover image
  • No frontend series pages (admin only, future plugin can expand)

When an ISBN is entered or updated, the plugin automatically generates retail links using URL patterns.

Pattern Format:

https://www.amazon.com/dp/{ISBN}?tag={AFFILIATE}

Link Generation Rules:

  1. If ISBN is present for a format, generate links for all active retail sites
  2. If Amazon ASIN is provided, use it instead of ISBN for Amazon links
  3. Affiliate codes are appended using the site's query parameter format
  4. Custom retail sites (book/quill icon) do NOT support affiliate codes
  5. User can click on any generated link to edit the URL manually

URL Patterns: Will be researched and provided in a specification update.

3.5 Rating Synchronization Engine

Cron Job: Runs every 12 hours via WP-Cron.

Synchronization Process:

  1. Query all books with valid ISBNs or ASINs
  2. For each book:
    • Fetch Amazon rating via robust web scraping of product page
    • Fetch Goodreads rating via robust web scraping of book page
  3. Update rating_amazon and rating_goodreads fields
  4. Update last_sync timestamp
  5. Log any errors or failures

Rating Fetch Failure Handling:

  • If fetch fails, keep the last known rating indefinitely
  • If no previously saved rating exists, show zero (0.0)
  • Log failures for admin review

Web Scraping Implementation:

  • Use wp_remote_get() with realistic browser User-Agent (e.g., Chrome on Windows)
  • No proxy (direct requests only)
  • Implement delays between requests (1-2 seconds) to avoid rate limiting
  • Handle HTTP 429 (rate limiting) with longer delays
  • Parse HTML with DOMDocument or regex for rating extraction
  • Amazon: Scrape main product page (/dp/{ASIN})
  • Goodreads: Scrape book page (/book/show/{id})

Rating Display:

  • Unicode stars (★☆) for star ratings
  • Support half-star ratings (e.g., 4.5)
  • Both star and numeric display (configurable)

3.6 Shortcode Suite

Format-Specific Retail Grids

[sell_ebook]     // Renders eBook retail links grid
[sell_pb]        // Renders Paperback retail links grid
[sell_hc]        // Renders Hard Cover retail links grid
[sell_audio]     // Renders Audio retail links grid

Parameters:

Parameter Default Description
id (required) Book ID to display
class (empty) Additional CSS class
columns auto Number of columns (2, 3, 4, auto)
show_icons true Show site icons
show_names true Show site names
icon_style simple simple (letter/abbreviation), uploaded (user images)

Display:

  • Grid layout (configurable columns), use as much screen as possible
  • Option for uploaded images/icons, fallback to simple icons
  • Responsive design for mobile devices

Note: The destination for shortcodes can be any website, including external sites. The local site is not required.

Rating Shortcode

[rating title="Pandemic Hacker"]              // Shows rating for specific book by title
[rating title="Pandemic Hacker" format="stars"]     // Star display format (★☆)
[rating title="Pandemic Hacker" format="numeric"]   // Numeric display format (4.5/5)
[rating title="Pandemic Hacker" format="both"]      // Both stars and numeric

Parameters:

Parameter Default Description
title (required) Book title to display rating for
format both stars (Unicode ★☆), numeric, both

Note: Half-star ratings are supported (e.g., 4.5 stars).

Custom Shortcodes

[my-promo]    // Redirects to target URL (301, 302, or 307)

3.7 SEO Metadata Module

Per-Book SEO Fields:

  • Custom meta title (overrides default)
  • Meta description
  • Meta keywords
  • Open Graph tags
  • Twitter Card tags

Implementation:

  • Stored in custom table (bd_book_seo)
  • Injected into <head> via wp_head action
  • Compatible with Yoast/RankMath (does not override if present)
  • Generates sitemap entries for books (does not rely on other plugins)
  • Sitemap priority: Based on rating (higher rating = higher priority)
  • Sitemap change frequency: Monthly

Stretch Goal: Links to social references (Facebook, etc.) for enhanced search engine results.

3.8 GDPR Compliance Module

Features:

  • Privacy consent banner at bottom of page (not blocking modal)
  • Must accept to continue browsing (not dismissible)
  • Cookie tracking for affiliate links only
  • Example privacy policy text provided (common internet text)
  • Opt-in/opt-out for tracking

Implementation:

  • JavaScript-based consent banner
  • bd_bookshelf_gdpr_consent user meta for consent status
  • Cookie: bd_bookshelf_consent (30-day expiry, reappears after expiry)
  • Cookie for affiliate tracking: bd_bookshelf_affiliate (30-day expiry, standard)
  • Cookie stores: Just the affiliate code

Data Collected:

  • Affiliate cookie for tracking (not click tracking)

3.9 Custom Shortcode Manager

Admin Page: Books > Shortcodes

Primary Use Case: URL shortening for books. Book sites do not allow links to competitor sites. Having a link for a review needs to be to the author's site, with a short code that links to the seller review page.

Features:

  • Create/edit/delete custom shortcodes
  • Define slug, target URL, and redirect type (301/302/307)
  • View click statistics with IP/user agent tracking
  • Bulk import/export functionality

Analytics Tracking:

  • Total click count
  • Click count with timestamp
  • Click count with full IP address (stored for security tracking)
  • User agent tracking
  • Referrer tracking
  • Data retention: 1 year

5. Database Schema

4.1 wp_bd_books

Column Type Description
id bigint(20) unsigned Primary key (auto-increment)
title varchar(255) Book title
description text Book description
cover_image varchar(500) Cover image URL
isbn_ebook varchar(20) eBook ISBN
isbn_paperback varchar(20) Paperback ISBN
isbn_hardcover varchar(20) Hard Cover ISBN
isbn_audio varchar(20) Audio ISBN
amazon_asin varchar(20) Amazon ASIN
goodreads_id varchar(20) Goodreads Book ID
rating_amazon decimal(3,2) Amazon rating
rating_goodreads decimal(3,2) Goodreads rating
last_sync datetime Last sync timestamp
series_id bigint(20) unsigned Series ID (nullable)
series_order int(11) Order within series
created_at datetime Creation timestamp
updated_at datetime Update timestamp

4.2 wp_bd_book_authors

Column Type Description
id bigint(20) unsigned Primary key
book_id bigint(20) unsigned Book ID
author_name varchar(255) Author display name
author_id bigint(20) unsigned WordPress user ID
goodreads_author_id varchar(20) Goodreads Author ID
is_primary tinyint(1) 1 if primary author
sort_order int(11) Display order (1-3)

4.3 wp_bd_series

Column Type Description
id bigint(20) unsigned Primary key
name varchar(255) Series name
description text Series description
cover_image varchar(500) Series cover image
created_at datetime Creation timestamp

4.4 wp_bd_retail_sites

Column Type Description
id bigint(20) unsigned Primary key
name varchar(100) Site name
url_pattern text URL pattern with {ISBN}
icon varchar(255) Icon file or URL
affiliate_param varchar(50) Query param for affiliate code
affiliate_code varchar(100) Affiliate code
is_custom tinyint(1) 1 if user-created
is_active tinyint(1) 1 if enabled
created_at datetime Creation timestamp
Column Type Description
id bigint(20) unsigned Primary key
book_id bigint(20) unsigned Book ID
site_id bigint(20) unsigned Retail Site ID
format varchar(20) eBook, paperback, hardcover, audio
url text Generated or custom URL
is_custom tinyint(1) 1 if manually created
created_at datetime Creation timestamp

4.6 wp_bd_shortcodes

Column Type Description
id bigint(20) unsigned Primary key
slug varchar(100) Shortcode identifier (unique)
target_url text Destination URL
redirect_type varchar(10) 301, 302, 307
description text Internal note
click_count bigint(20) Total clicks
is_active tinyint(1) 1 if live
created_at datetime Creation timestamp

4.7 wp_bd_shortcode_clicks

Column Type Description
id bigint(20) unsigned Primary key
shortcode_id bigint(20) unsigned Shortcode ID
clicked_at datetime Click timestamp
ip_address varchar(45) User IP (stored in full for security)
user_agent text Browser user agent
referer varchar(500) HTTP referer

4.8 wp_bd_book_seo

Column Type Description
id bigint(20) unsigned Primary key
book_id bigint(20) unsigned Book ID (unique)
seo_title varchar(255) Custom SEO title
seo_description text Custom SEO description
seo_keywords varchar(500) Custom SEO keywords
og_title varchar(255) Open Graph title
og_description text Open Graph description
og_image varchar(500) Open Graph image
created_at datetime Creation timestamp
updated_at datetime Update timestamp

6. Cron Job Specification

5.1 Rating Sync Job

Hook Name: bd_bookshelf_sync_ratings Schedule: Every 12 hours (twicedaily)

Process:

1. Get all books with valid ISBNs or ASINs
2. For each book:
   a. If Amazon ASIN or ISBN exists:
      - Scrape Amazon product page with robust implementation
      - Parse rating value from HTML
      - Update wp_bd_books.rating_amazon
   b. If Goodreads ID exists:
      - Scrape Goodreads book page with robust implementation
      - Parse rating value from HTML
      - Update wp_bd_books.rating_goodreads
   c. Update wp_bd_books.last_sync timestamp
3. Log results for admin display

Error Handling:

  • Retry failed fetches up to 3 times with exponential backoff
  • If fetch fails, keep last known rating
  • If no previous rating, show 0.0
  • Log errors for admin review

Web Scraping Implementation:

  • Use wp_remote_get() with appropriate headers
  • Set realistic User-Agent string
  • Implement delays between requests (1-2 seconds)
  • Handle HTTP 429 (rate limiting) with longer delays
  • Parse HTML with DOMDocument or regex for rating extraction

7. Admin Interface

6.1 Books Menu

  • All Books: List view with columns for Title, ISBNs, Ratings, Last Sync
  • Add New Book: Book entry form
  • Authors: Manage author entries
  • Series: Manage book series
  • Rating Sync: Manual sync trigger and status display
  • Settings: Affiliate codes, sync interval, GDPR options

6.2 Shortcodes Menu

  • All Shortcodes: List of custom shortcodes with click stats
  • Add New Shortcode: Create new redirect shortcode
  • Analytics: Detailed click analytics with IP/user agent
  • Import/Export: Bulk shortcode management

6.3 Settings Page

  • Affiliate Codes: Per-site affiliate code configuration
  • Author IDs: Manual Goodreads Author ID entry (fallback)
  • Sync Settings: Cron interval configuration
  • GDPR: Consent banner text, cookie duration, privacy page
  • SEO: Default meta tag patterns, sitemap settings

8. Theme Integration

7.1 Functions Available

// Get book data
bd_bookshelf_get_book( $book_id );

// Get books by series
bd_bookshelf_get_books_by_series( $series_id );

// Get retail links for a book
bd_bookshelf_get_retail_links( $book_id, $format );

// Get book rating
bd_bookshelf_get_rating( $book_id );

// Get author information
bd_bookshelf_get_book_authors( $book_id );

// Get series information
bd_bookshelf_get_series( $series_id );

// Check if GDPR consent given
bd_bookshelf_has_consent();

7.2 Template Tags

// Display book rating
bd_bookshelf_the_rating( $book_id, $format );

// Display retail grid
bd_bookshelf_the_retail_grid( $book_id, $format );

// Display series books
bd_bookshelf_the_series_books( $series_id );

9. Security Implementation

9.1 Data Validation & Sanitization

All user input must be validated and sanitized before processing:

// Example: Book form processing
$title = sanitize_text_field($_POST['title']);
$description = wp_kses_post($_POST['description']);
$isbn = preg_replace('/[^0-9X]/i', '', $_POST['isbn']);
$email = sanitize_email($_POST['author_email']);
$amount = absint($_POST['rating']);

9.2 Data Escaping

All output must be escaped at the point of display:

// HTML output
echo esc_html($book->title);
echo esc_attr($book->isbn);
echo esc_url($book->affiliate_url);
echo wp_kses_post($book->description);

9.3 Nonce Verification

All forms and AJAX requests must include nonce verification:

// In form
wp_nonce_field('bd_bookshelf_save_book_' . $book_id, 'bd_bookshelf_nonce');

// In processing
if (!wp_verify_nonce($_POST['bd_bookshelf_nonce'], 'bd_bookshelf_save_book_' . $book_id)) {
    wp_die('Security check failed');
}

// AJAX
wp_localize_script('bd-bookshelf-admin', 'bdBookshelfAjax', [
    'ajaxurl' => admin_url('admin-ajax.php'),
    'nonce' => wp_create_nonce('bd_bookshelf_ajax_nonce'),
]);

9.4 Capability Checks

All privileged actions must verify user capabilities:

function bd_bookshelf_save_book() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(['message' => 'Insufficient permissions']);
    }
    // Process save...
}

9.5 SQL Injection Prevention

All database queries must use prepared statements:

// Correct
$book = $wpdb->get_row(
    $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}bd_books WHERE id = %d",
        $book_id
    )
);

// Incorrect - NEVER do this
$book = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}bd_books WHERE id = $book_id");

9.6 AJAX Security

// Register AJAX handlers
add_action('wp_ajax_bd_bookshelf_save_book', 'bd_bookshelf_ajax_save_book');
add_action('wp_ajax_bd_bookshelf_delete_book', 'bd_bookshelf_ajax_delete_book');

function bd_bookshelf_ajax_save_book() {
    // 1. Verify nonce
    if (!wp_verify_nonce($_POST['nonce'], 'bd_bookshelf_save_book')) {
        wp_send_json_error('Invalid nonce');
    }
    
    // 2. Check capabilities
    if (!current_user_can('manage_options')) {
        wp_send_json_error('Insufficient permissions');
    }
    
    // 3. Sanitize all input
    $book_id = absint($_POST['book_id']);
    $title = sanitize_text_field($_POST['title']);
    $isbn = preg_replace('/[^0-9X]/i', '', $_POST['isbn']);
    
    // 4. Validate data
    if (empty($title)) {
        wp_send_json_error('Title is required');
    }
    
    // 5. Process with prepared statements
    $result = $wpdb->update(
        $wpdb->prefix . 'bd_books',
        ['title' => $title, 'isbn_ebook' => $isbn],
        ['id' => $book_id],
        ['%s', '%s'],
        ['%d']
    );
    
    wp_send_json_success(['message' => 'Book saved', 'id' => $book_id]);
}

9.7 File Upload Security

If plugin allows file uploads (e.g., book covers):

function bd_bookshelf_handle_upload() {
    // Check capability
    if (!current_user_can('upload_files')) {
        wp_die('Unauthorized');
    }
    
    // Validate file type
    $allowed_types = ['image/jpeg', 'image/png', 'image/webp'];
    if (!in_array($_FILES['file']['type'], $allowed_types)) {
        wp_die('Invalid file type');
    }
    
    // Validate file size (max 5MB)
    if ($_FILES['file']['size'] > 5 * 1024 * 1024) {
        wp_die('File too large');
    }
    
    // Use WordPress upload handler
    $upload = wp_handle_upload($_FILES['file'], ['test_form' => false]);
    
    if (isset($upload['url'])) {
        // Store $upload['url'] in database
    }
}

9.8 Error Handling

// Log errors for debugging (not exposed to users)
error_log('BD Bookshelf Error: ' . $error_message);

// Display generic error to users
wp_die('An error occurred. Please try again later.');

// For AJAX, send JSON error
wp_send_json_error(['message' => 'An error occurred']);

10. Data Migration

9.1 Migration Tool

Admin Page: Books > Import

Features:

  • Import books from WordPress posts/CPTs
  • CSV import functionality
  • Map existing post fields to plugin fields
  • Preserve ISBNs, ratings, and metadata
  • Batch processing for large catalogs

Migration Process:

  1. Select source (WordPress posts or CSV file)
  2. Map fields (title, description, ISBNs, etc.)
  3. Preview import data
  4. Execute import with progress bar
  5. Report results (success/failure counts)

11. Version History

v0.0.1 (Current)

  • Initial specification
  • Core entity definitions
  • Module architecture
  • Database schema
  • Shortcode specifications
  • Custom database tables (not CPT)
  • Web scraping for ratings (robust implementation)
  • Up to 3 authors per book
  • Series management (one series per book, ordered by publication date)
  • Detailed click analytics with full IP storage
  • Unicode stars for rating display with half-star support
  • Data migration tool from existing WordPress books
  • GDPR banner (must accept, 30-day cookie)
  • Sitemap with rating-based priority
  • WordPress Requirements & Best Practices section added
  • Security implementation details (validation, escaping, nonces, capability checks)
  • Plugin Check compliance requirements
  • Internationalization guidelines
  • File organization structure
  • Uninstall cleanup procedures