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.
850 lines
30 KiB
JavaScript
850 lines
30 KiB
JavaScript
// Copyright 2026 Umbra Tools (umbratools.com)
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
/**
|
|
* BD Bookshelf - Admin JavaScript
|
|
*
|
|
* @package Umbra_Bookshelf
|
|
*/
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
$(document).ready(function() {
|
|
// Initialize media uploader for book cover
|
|
initCoverUploader();
|
|
|
|
// Initialize media uploader for author photo
|
|
initAuthorPhotoUploader();
|
|
|
|
// Book form
|
|
$('#bd-bookshelf-book-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
saveBook();
|
|
});
|
|
|
|
// Delete book
|
|
$(document).on('click', '.bd-bookshelf-delete', function(e) {
|
|
e.preventDefault();
|
|
var bookId = $(this).data('id');
|
|
if (confirm('Are you sure you want to delete this book?')) {
|
|
deleteBook(bookId);
|
|
}
|
|
});
|
|
|
|
// Author Modal
|
|
initAuthorModal();
|
|
|
|
// Series Modal
|
|
initSeriesModal();
|
|
|
|
// Shortcode Modal
|
|
initShortcodeModal();
|
|
|
|
// Sites form
|
|
$('#bd-bookshelf-sites-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
saveSites();
|
|
});
|
|
|
|
// Settings form
|
|
$('#bd-bookshelf-settings-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
saveSettings();
|
|
});
|
|
|
|
// Import CSV form
|
|
$('#bd-bookshelf-import-csv-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
importCSV();
|
|
});
|
|
|
|
// Import Posts form
|
|
$('#bd-bookshelf-import-posts-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
importPosts();
|
|
});
|
|
|
|
// Manual sync
|
|
$('#bd-bookshelf-manual-sync').on('click', function() {
|
|
var btn = $(this);
|
|
btn.prop('disabled', true).text('Syncing...');
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_sync_ratings',
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
alert(response.data.message);
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
},
|
|
complete: function() {
|
|
btn.prop('disabled', false).text('Sync Now');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Regenerate retail links
|
|
$('#bd-bookshelf-regenerate-links').on('click', function() {
|
|
var btn = $(this);
|
|
var bookId = btn.data('book-id');
|
|
btn.prop('disabled', true).text('Regenerating...');
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_regenerate_links',
|
|
book_id: bookId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#bd-bookshelf-retail-links').html(response.data.html);
|
|
alert('Retail links regenerated!');
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
},
|
|
complete: function() {
|
|
btn.prop('disabled', false).text('Regenerate Links');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Scan forms
|
|
initScanForms();
|
|
});
|
|
|
|
/**
|
|
* Initialize Scan Forms
|
|
*/
|
|
function initScanForms() {
|
|
// Goodreads scan
|
|
$('#bd-bookshelf-goodreads-scan-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
var authorId = $('#goodreads_author_id').val();
|
|
if (!authorId) {
|
|
alert('Please enter a Goodreads Author ID');
|
|
return;
|
|
}
|
|
scanAuthor('goodreads', authorId);
|
|
});
|
|
|
|
// Amazon scan
|
|
$('#bd-bookshelf-amazon-scan-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
var authorId = $('#amazon_author_id').val();
|
|
if (!authorId) {
|
|
alert('Please enter an Amazon Author ID');
|
|
return;
|
|
}
|
|
scanAuthor('amazon', authorId);
|
|
});
|
|
|
|
// Select all books
|
|
$(document).on('change', '#select-all-books', function() {
|
|
$('.book-checkbox').prop('checked', $(this).prop('checked'));
|
|
});
|
|
|
|
// Import selected books
|
|
$('#bd-bookshelf-import-selected').on('click', function() {
|
|
importSelectedBooks();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Scan author from source
|
|
*/
|
|
function scanAuthor(source, authorId) {
|
|
var action = source === 'goodreads' ? 'bd_bookshelf_scan_goodreads' : 'bd_bookshelf_scan_amazon';
|
|
|
|
$('#bd-bookshelf-scan-results').hide();
|
|
$('body').css('cursor', 'wait');
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: action,
|
|
author_id: authorId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
$('body').css('cursor', 'default');
|
|
|
|
if (response.success) {
|
|
displayScanResults(response.data);
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
$('body').css('cursor', 'default');
|
|
alert('An error occurred while scanning. Please try again.');
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Display scan results
|
|
*/
|
|
function displayScanResults(data) {
|
|
var author = data.author;
|
|
var books = data.books;
|
|
var source = data.source;
|
|
|
|
// Show results section
|
|
$('#bd-bookshelf-scan-results').show();
|
|
|
|
// Display author info
|
|
var authorHtml = '<div class="bd-bookshelf-author-card">';
|
|
if (author.photo) {
|
|
authorHtml += '<img src="' + author.photo + '" style="width:100px;height:100px;border-radius:50%;margin-right:20px;float:left">';
|
|
}
|
|
authorHtml += '<h3>' + (author.name || 'Unknown Author') + '</h3>';
|
|
if (author.bio) {
|
|
authorHtml += '<p>' + author.bio.substring(0, 200) + '...</p>';
|
|
}
|
|
authorHtml += '<p><strong>Source:</strong> ' + source.charAt(0).toUpperCase() + source.slice(1) + '</p>';
|
|
authorHtml += '<p><strong>Books Found:</strong> ' + books.length + '</p>';
|
|
authorHtml += '<div style="clear:both"></div></div>';
|
|
|
|
$('#bd-bookshelf-author-info').html(authorHtml);
|
|
|
|
// Display books
|
|
var booksHtml = '';
|
|
books.forEach(function(book, index) {
|
|
booksHtml += '<tr>';
|
|
booksHtml += '<td><input type="checkbox" class="book-checkbox" value="' + index + '" checked></td>';
|
|
booksHtml += '<td>';
|
|
if (book.cover_image) {
|
|
booksHtml += '<img src="' + book.cover_image + '" style="width:60px;height:auto">';
|
|
}
|
|
booksHtml += '</td>';
|
|
booksHtml += '<td>' + (book.title || '') + '</td>';
|
|
booksHtml += '<td>' + (book.isbn || book.isbn13 || book.asin || '') + '</td>';
|
|
booksHtml += '<td>' + (book.rating || '0') + '/5</td>';
|
|
booksHtml += '<td>' + (book.published || '') + '</td>';
|
|
booksHtml += '<td>' + (book.description ? book.description.substring(0, 100) + '...' : '') + '</td>';
|
|
booksHtml += '</tr>';
|
|
|
|
// Store book data in hidden fields
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][title]" value="' + (book.title || '').replace(/"/g, '"') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][isbn]" value="' + (book.isbn || '') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][isbn13]" value="' + (book.isbn13 || '') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][cover_image]" value="' + (book.cover_image || '') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][rating]" value="' + (book.rating || '0') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][published]" value="' + (book.published || '') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][description]" value="' + (book.description || '').replace(/"/g, '"') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][goodreads_id]" value="' + (book.goodreads_id || '') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][asin]" value="' + (book.asin || '') + '">';
|
|
booksHtml += '<input type="hidden" name="book_data[' + index + '][format]" value="' + (book.format || '') + '">';
|
|
});
|
|
|
|
$('#bd-bookshelf-books-list').html(booksHtml);
|
|
|
|
// Store author data
|
|
$('#bd-bookshelf-scan-results').data('author', author);
|
|
$('#bd-bookshelf-scan-results').data('source', source);
|
|
|
|
// Scroll to results
|
|
$('html, body').animate({
|
|
scrollTop: $('#bd-bookshelf-scan-results').offset().top
|
|
}, 500);
|
|
}
|
|
|
|
/**
|
|
* Import selected books
|
|
*/
|
|
function importSelectedBooks() {
|
|
var books = [];
|
|
var author = $('#bd-bookshelf-scan-results').data('author');
|
|
var source = $('#bd-bookshelf-scan-results').data('source');
|
|
|
|
$('.book-checkbox:checked').each(function() {
|
|
var index = $(this).val();
|
|
var bookData = {
|
|
title: $('input[name="book_data[' + index + '][title]"]').val(),
|
|
isbn: $('input[name="book_data[' + index + '][isbn]"]').val(),
|
|
isbn13: $('input[name="book_data[' + index + '][isbn13]"]').val(),
|
|
cover_image: $('input[name="book_data[' + index + '][cover_image]"]').val(),
|
|
rating: $('input[name="book_data[' + index + '][rating]"]').val(),
|
|
published: $('input[name="book_data[' + index + '][published]"]').val(),
|
|
description: $('input[name="book_data[' + index + '][description]"]').val(),
|
|
goodreads_id: $('input[name="book_data[' + index + '][goodreads_id]"]').val(),
|
|
asin: $('input[name="book_data[' + index + '][asin]"]').val() || '',
|
|
format: $('input[name="book_data[' + index + '][format]"]').val() || '',
|
|
};
|
|
books.push(bookData);
|
|
});
|
|
|
|
if (books.length === 0) {
|
|
alert('Please select at least one book to import');
|
|
return;
|
|
}
|
|
|
|
if (!confirm('Import ' + books.length + ' book(s)?')) {
|
|
return;
|
|
}
|
|
|
|
$('body').css('cursor', 'wait');
|
|
|
|
// Build form data manually for proper nested array handling
|
|
var formData = new FormData();
|
|
formData.append('action', 'bd_bookshelf_import_scraped');
|
|
formData.append('nonce', umbraBookshelfAdmin.nonce);
|
|
formData.append('source', source);
|
|
|
|
// Add author data
|
|
if (author) {
|
|
formData.append('author[name]', author.name || '');
|
|
formData.append('author[bio]', author.bio || '');
|
|
formData.append('author[photo]', author.photo || '');
|
|
formData.append('author[id]', author.id || '');
|
|
}
|
|
|
|
// Add books array
|
|
books.forEach(function(book, i) {
|
|
formData.append('books[' + i + '][title]', book.title || '');
|
|
formData.append('books[' + i + '][isbn]', book.isbn || '');
|
|
formData.append('books[' + i + '][isbn13]', book.isbn13 || '');
|
|
formData.append('books[' + i + '][cover_image]', book.cover_image || '');
|
|
formData.append('books[' + i + '][rating]', book.rating || '0');
|
|
formData.append('books[' + i + '][published]', book.published || '');
|
|
formData.append('books[' + i + '][description]', book.description || '');
|
|
formData.append('books[' + i + '][goodreads_id]', book.goodreads_id || '');
|
|
formData.append('books[' + i + '][asin]', book.asin || '');
|
|
formData.append('books[' + i + '][format]', book.format || '');
|
|
});
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function(response) {
|
|
$('body').css('cursor', 'default');
|
|
|
|
if (response.success) {
|
|
alert(response.data.message);
|
|
if (response.data.imported > 0 || response.data.updated > 0) {
|
|
location.reload();
|
|
}
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
$('body').css('cursor', 'default');
|
|
alert('An error occurred while importing. Please try again.');
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize Cover Image Uploader
|
|
*/
|
|
function initCoverUploader() {
|
|
var coverFrame;
|
|
|
|
$('#cover-upload-btn').on('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
if (coverFrame) {
|
|
coverFrame.open();
|
|
return;
|
|
}
|
|
|
|
coverFrame = wp.media({
|
|
title: umbraBookshelfAdmin.mediaTitle,
|
|
button: { text: umbraBookshelfAdmin.mediaButton },
|
|
multiple: false,
|
|
library: { type: 'image' }
|
|
});
|
|
|
|
coverFrame.on('select', function() {
|
|
var attachment = coverFrame.state().get('selection').first().toJSON();
|
|
var url = attachment.sizes && attachment.sizes.medium ? attachment.sizes.medium.url : attachment.url;
|
|
|
|
$('#cover_image').val(attachment.url);
|
|
$('#cover-preview').html('<img src="' + url + '" style="max-width:200px;height:auto">');
|
|
$('#cover-remove-btn').show();
|
|
});
|
|
|
|
coverFrame.open();
|
|
});
|
|
|
|
$('#cover-remove-btn').on('click', function(e) {
|
|
e.preventDefault();
|
|
$('#cover_image').val('');
|
|
$('#cover-preview').html('');
|
|
$(this).hide();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize Author Photo Uploader
|
|
*/
|
|
function initAuthorPhotoUploader() {
|
|
var photoFrame;
|
|
|
|
$('#author-photo-btn').on('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
if (photoFrame) {
|
|
photoFrame.open();
|
|
return;
|
|
}
|
|
|
|
photoFrame = wp.media({
|
|
title: 'Select Author Photo',
|
|
button: { text: 'Use This Photo' },
|
|
multiple: false,
|
|
library: { type: 'image' }
|
|
});
|
|
|
|
photoFrame.on('select', function() {
|
|
var attachment = photoFrame.state().get('selection').first().toJSON();
|
|
var url = attachment.sizes && attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.url;
|
|
|
|
$('#author_photo_url').val(attachment.url);
|
|
$('#author-photo-preview').html('<img src="' + url + '" style="max-width:100px;height:auto">');
|
|
$('#author-photo-remove').show();
|
|
});
|
|
|
|
photoFrame.open();
|
|
});
|
|
|
|
$('#author-photo-remove').on('click', function(e) {
|
|
e.preventDefault();
|
|
$('#author_photo_url').val('');
|
|
$('#author-photo-preview').html('');
|
|
$(this).hide();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize Author Modal
|
|
*/
|
|
function initAuthorModal() {
|
|
// Open modal for new author
|
|
$('#bd-bookshelf-add-author').on('click', function() {
|
|
$('#author_id').val(0);
|
|
$('#author_display_name').val('');
|
|
$('#author_email').val('');
|
|
$('#author_website').val('');
|
|
$('#author_bio').val('');
|
|
$('#author_goodreads_id').val('');
|
|
$('#author_photo_url').val('');
|
|
$('#author-photo-preview').html('');
|
|
$('#author-photo-remove').hide();
|
|
$('#bd-bookshelf-author-modal-title').text('Add New Author');
|
|
$('#bd-bookshelf-author-modal').show();
|
|
});
|
|
|
|
// Edit author
|
|
$(document).on('click', '.bd-bookshelf-edit-author', function(e) {
|
|
e.preventDefault();
|
|
var authorId = $(this).data('id');
|
|
|
|
// Fetch author data
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_get_author',
|
|
id: authorId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
var author = response.data;
|
|
$('#author_id').val(author.id);
|
|
$('#author_display_name').val(author.display_name);
|
|
$('#author_email').val(author.email);
|
|
$('#author_website').val(author.website);
|
|
$('#author_bio').val(author.bio);
|
|
$('#author_goodreads_id').val(author.goodreads_author_id);
|
|
$('#author_photo_url').val(author.photo_url);
|
|
|
|
if (author.photo_url) {
|
|
$('#author-photo-preview').html('<img src="' + author.photo_url + '" style="max-width:100px;height:auto">');
|
|
$('#author-photo-remove').show();
|
|
} else {
|
|
$('#author-photo-preview').html('');
|
|
$('#author-photo-remove').hide();
|
|
}
|
|
|
|
$('#bd-bookshelf-author-modal-title').text('Edit Author');
|
|
$('#bd-bookshelf-author-modal').show();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Delete author
|
|
$(document).on('click', '.bd-bookshelf-delete-author', function(e) {
|
|
e.preventDefault();
|
|
var authorId = $(this).data('id');
|
|
if (confirm('Are you sure you want to delete this author?')) {
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_delete_author',
|
|
id: authorId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Save author
|
|
$('#bd-bookshelf-author-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
var data = $(this).serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_save_author',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Close modal
|
|
$(document).on('click', '.bd-bookshelf-modal-close', function() {
|
|
$(this).closest('.bd-bookshelf-modal').hide();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize Series Modal
|
|
*/
|
|
function initSeriesModal() {
|
|
// Open modal for new series
|
|
$('#bd-bookshelf-add-series').on('click', function() {
|
|
$('#series_id_input').val(0);
|
|
$('#series_name').val('');
|
|
$('#series_description').val('');
|
|
$('#bd-bookshelf-series-modal-title').text('Add New Series');
|
|
$('#bd-bookshelf-series-modal').show();
|
|
});
|
|
|
|
// Edit series
|
|
$(document).on('click', '.bd-bookshelf-edit-series', function(e) {
|
|
e.preventDefault();
|
|
var seriesId = $(this).data('id');
|
|
|
|
// Fetch series data
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_get_series',
|
|
id: seriesId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
var series = response.data;
|
|
$('#series_id_input').val(series.id);
|
|
$('#series_name').val(series.name);
|
|
$('#series_description').val(series.description);
|
|
$('#bd-bookshelf-series-modal-title').text('Edit Series');
|
|
$('#bd-bookshelf-series-modal').show();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Delete series
|
|
$(document).on('click', '.bd-bookshelf-delete-series', function(e) {
|
|
e.preventDefault();
|
|
var seriesId = $(this).data('id');
|
|
if (confirm('Are you sure you want to delete this series? Books in this series will be unlinked.')) {
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_delete_series',
|
|
id: seriesId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Save series
|
|
$('#bd-bookshelf-series-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
var data = $(this).serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_save_series',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize Shortcode Modal
|
|
*/
|
|
function initShortcodeModal() {
|
|
// Open modal for new shortcode
|
|
$('#bd-bookshelf-add-shortcode').on('click', function() {
|
|
$('#shortcode_id').val(0);
|
|
$('#shortcode_slug').val('');
|
|
$('#shortcode_target').val('');
|
|
$('#shortcode_redirect').val('301');
|
|
$('#shortcode_description').val('');
|
|
$('#shortcode_slug').prop('readonly', false);
|
|
$('#bd-bookshelf-shortcode-modal-title').text('Add New Shortcode');
|
|
$('#bd-bookshelf-shortcode-modal').show();
|
|
});
|
|
|
|
// Edit shortcode
|
|
$(document).on('click', '.bd-bookshelf-edit-shortcode', function(e) {
|
|
e.preventDefault();
|
|
var shortcodeId = $(this).data('id');
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_get_shortcode',
|
|
id: shortcodeId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
var sc = response.data;
|
|
$('#shortcode_id').val(sc.id);
|
|
$('#shortcode_slug').val(sc.slug).prop('readonly', true);
|
|
$('#shortcode_target').val(sc.target_url);
|
|
$('#shortcode_redirect').val(sc.redirect_type);
|
|
$('#shortcode_description').val(sc.description);
|
|
$('#bd-bookshelf-shortcode-modal-title').text('Edit Shortcode');
|
|
$('#bd-bookshelf-shortcode-modal').show();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Delete shortcode
|
|
$(document).on('click', '.bd-bookshelf-delete-shortcode', function(e) {
|
|
e.preventDefault();
|
|
var shortcodeId = $(this).data('id');
|
|
if (confirm('Are you sure you want to delete this shortcode?')) {
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_delete_shortcode',
|
|
id: shortcodeId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Save shortcode
|
|
$('#bd-bookshelf-shortcode-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
var data = $(this).serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_save_shortcode',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Save Book
|
|
*/
|
|
function saveBook() {
|
|
var form = $('#bd-bookshelf-book-form');
|
|
var data = form.serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_save_book',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
alert('Book saved!');
|
|
if (!form.find('input[name="book_id"]').val() || form.find('input[name="book_id"]').val() === '0') {
|
|
window.location.href = window.location.href.split('&book_id=')[0] + '&book_id=' + response.data.id;
|
|
}
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Delete Book
|
|
*/
|
|
function deleteBook(bookId) {
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'bd_bookshelf_delete_book',
|
|
id: bookId,
|
|
nonce: umbraBookshelfAdmin.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Save Sites/Affiliate Codes
|
|
*/
|
|
function saveSites() {
|
|
var form = $('#bd-bookshelf-sites-form');
|
|
var data = form.serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_save_sites',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
alert('Affiliate codes saved!');
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Save Settings
|
|
*/
|
|
function saveSettings() {
|
|
var form = $('#bd-bookshelf-settings-form');
|
|
var data = form.serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_save_settings',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
alert('Settings saved!');
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Import CSV
|
|
*/
|
|
function importCSV() {
|
|
var form = $('#bd-bookshelf-import-csv-form');
|
|
var formData = new FormData(form[0]);
|
|
formData.append('action', 'bd_bookshelf_import_csv');
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#bd-bookshelf-import-results').show();
|
|
$('#bd-bookshelf-import-message').text(response.data.message);
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Import Posts
|
|
*/
|
|
function importPosts() {
|
|
var form = $('#bd-bookshelf-import-posts-form');
|
|
var data = form.serialize();
|
|
|
|
$.ajax({
|
|
url: umbraBookshelfAdmin.ajaxurl,
|
|
type: 'POST',
|
|
data: data + '&action=bd_bookshelf_import_posts',
|
|
success: function(response) {
|
|
if (response.success) {
|
|
alert(response.data.message);
|
|
} else {
|
|
alert('Error: ' + response.data.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
})(jQuery);
|