325 lines
15 KiB
PHP
325 lines
15 KiB
PHP
<?php
|
|
// Copyright 2026 Umbra Tools (umbratools.com)
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
/**
|
|
* Book Helper Functions
|
|
*
|
|
* @package BD_Murphy
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* BDM_Book_Helpers class
|
|
*/
|
|
class BDM_Book_Helpers {
|
|
|
|
/**
|
|
* Get localized title for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
* @return string
|
|
*/
|
|
public function get_localized_title($book_id, $language = 'en') {
|
|
if ($language !== 'en') {
|
|
$title = get_post_meta($book_id, 'title_' . $language, true);
|
|
if ($title) {
|
|
return $title;
|
|
}
|
|
}
|
|
return get_the_title($book_id);
|
|
}
|
|
|
|
/**
|
|
* Get localized blurb for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
* @return string
|
|
*/
|
|
public function get_localized_blurb($book_id, $language = 'en') {
|
|
if ($language !== 'en') {
|
|
$blurb = get_post_meta($book_id, 'blurb_' . $language, true);
|
|
if ($blurb) {
|
|
return $blurb;
|
|
}
|
|
}
|
|
|
|
$blurb = get_post_meta($book_id, 'blurb_en', true);
|
|
if ($blurb) {
|
|
return $blurb;
|
|
}
|
|
|
|
return get_post_meta($book_id, 'blurb', true);
|
|
}
|
|
|
|
/**
|
|
* Get cover URL for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
* @return string
|
|
*/
|
|
public function get_cover_url($book_id, $language = 'en') {
|
|
if ($language !== 'en') {
|
|
$cover = get_post_meta($book_id, 'cover_' . $language, true);
|
|
if ($cover) {
|
|
return $cover;
|
|
}
|
|
}
|
|
|
|
$cover = get_post_meta($book_id, 'cover_image', true);
|
|
if ($cover) {
|
|
return $cover;
|
|
}
|
|
|
|
$thumbnail_id = get_post_thumbnail_id($book_id);
|
|
if ($thumbnail_id) {
|
|
$image = wp_get_attachment_image_src($thumbnail_id, 'medium');
|
|
if ($image && !empty($image[0])) {
|
|
return $image[0];
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Get author's pen name
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @return string
|
|
*/
|
|
public function get_pen_name($book_id) {
|
|
$pen_name = get_post_meta($book_id, 'pen_name', true);
|
|
return $pen_name ? $pen_name : 'B.D. Murphy';
|
|
}
|
|
|
|
/**
|
|
* Get series info for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @return array|null
|
|
*/
|
|
public function get_series_info($book_id) {
|
|
$terms = get_the_terms($book_id, 'series');
|
|
if ($terms && !is_wp_error($terms)) {
|
|
$term = reset($terms);
|
|
$volume = get_post_meta($book_id, 'series_volume', true);
|
|
return array(
|
|
'name' => $term->name,
|
|
'slug' => $term->slug,
|
|
'volume' => $volume ? intval($volume) : 1,
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get ratings for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @return array
|
|
*/
|
|
public function get_ratings($book_id) {
|
|
$ratings = array();
|
|
|
|
$amazon = get_post_meta($book_id, 'amazon_rating', true);
|
|
if ($amazon) {
|
|
$ratings['amazon'] = $amazon;
|
|
}
|
|
|
|
$goodreads = get_post_meta($book_id, 'goodreads_rating', true);
|
|
if ($goodreads) {
|
|
$ratings['goodreads'] = $goodreads;
|
|
}
|
|
|
|
return $ratings;
|
|
}
|
|
|
|
/**
|
|
* Get preview excerpt for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
* @return string
|
|
*/
|
|
public function get_preview_excerpt($book_id, $language = 'en') {
|
|
if ($language !== 'en') {
|
|
$preview = get_post_meta($book_id, 'preview_' . $language, true);
|
|
if ($preview) {
|
|
return $preview;
|
|
}
|
|
}
|
|
return get_post_meta($book_id, 'preview_excerpt', true);
|
|
}
|
|
|
|
/**
|
|
* Get pull quotes for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
* @return array
|
|
*/
|
|
public function get_pull_quotes($book_id, $language = 'en') {
|
|
$quotes = array();
|
|
for ($i = 1; $i <= 3; $i++) {
|
|
$quote = get_post_meta($book_id, 'pull_quote_' . $i, true);
|
|
if ($quote) {
|
|
$quotes[] = $quote;
|
|
}
|
|
}
|
|
return $quotes;
|
|
}
|
|
|
|
/**
|
|
* Get reviews for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @return array
|
|
*/
|
|
public function get_reviews($book_id) {
|
|
$reviews = get_post_meta($book_id, 'reviews', true);
|
|
if ($reviews) {
|
|
return maybe_unserialize($reviews);
|
|
}
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Get available languages for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @return array
|
|
*/
|
|
public function get_available_languages($book_id) {
|
|
$all_languages = array(
|
|
'en' => 'English',
|
|
'fr' => 'Français',
|
|
'de' => 'Deutsch',
|
|
'es' => 'Español',
|
|
'it' => 'Italiano',
|
|
'pt' => 'Português',
|
|
'ru' => 'Русский',
|
|
'ja' => '日本語',
|
|
'zh' => '中文',
|
|
);
|
|
|
|
$available = array('en' => 'English');
|
|
foreach (array_keys($all_languages) as $lang) {
|
|
if ($lang === 'en') continue;
|
|
$title = get_post_meta($book_id, 'title_' . $lang, true);
|
|
if ($title) {
|
|
$available[$lang] = $all_languages[$lang];
|
|
}
|
|
}
|
|
|
|
return $available;
|
|
}
|
|
|
|
/**
|
|
* Get retailer links for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
* @return array
|
|
*/
|
|
public function get_retailer_links_by_language($book_id, $language = 'en') {
|
|
$retailers = array(
|
|
'amazon' => 'Amazon',
|
|
'apple' => 'Apple Books',
|
|
'barnes' => 'Barnes & Noble',
|
|
'kobo' => 'Kobo',
|
|
'google' => 'Google Play',
|
|
);
|
|
|
|
$links = array();
|
|
foreach ($retailers as $key => $name) {
|
|
$meta_key = 'ebook_url_' . $key . '_' . $language;
|
|
$url = get_post_meta($book_id, $meta_key, true);
|
|
|
|
if (!$url && $language !== 'en') {
|
|
$url = get_post_meta($book_id, 'ebook_url_' . $key, true);
|
|
}
|
|
|
|
if ($url) {
|
|
$links[$key] = array(
|
|
'name' => $name,
|
|
'url' => $url,
|
|
'retailer' => $key,
|
|
);
|
|
}
|
|
}
|
|
|
|
return $links;
|
|
}
|
|
|
|
/**
|
|
* Display retailer links for a book
|
|
*
|
|
* @param int $book_id Book post ID.
|
|
* @param string $language Language code.
|
|
*/
|
|
public function display_retailer_links($book_id, $language = 'en', $format = 'ebook') {
|
|
$retailers = array(
|
|
'amazon' => array(
|
|
'name' => 'Amazon',
|
|
'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M.045 18.02c.072-.116.187-.124.348-.022 3.636 2.11 7.594 3.166 11.87 3.166 2.852 0 5.668-.533 8.447-1.595l.315-.14c.138-.06.234-.1.293-.12.228-.085.395-.06.525.085.135.15.118.3-.052.465l-.255.24c-.135.128-.3.188-.503.188-.19 0-.42-.085-.675-.255a9.87 9.87 0 01-.855-.54c-.562-.36-1.085-.778-1.575-1.245-.49-.468-.9-1.015-1.215-1.635-.32-.62-.48-1.285-.48-1.995 0-.772.165-1.452.495-2.04.33-.588.78-1.082 1.365-1.482.584-.4 1.256-.7 2.015-.9.76-.2 1.55-.3 2.38-.3.43 0 .855.03 1.28.09.42.063.815.16 1.185.285.37.125.72.29 1.04.495.32.204.6.455.84.75.24.297.42.64.54 1.03.12.39.18.825.18 1.305 0 .98-.31 1.77-.93 2.37-.62.6-1.43.9-2.43.9-.38 0-.755-.07-1.125-.21-.37-.14-.715-.34-1.035-.6-.32-.26-.615-.565-.885-.915-.27-.35-.53-.735-.78-1.155l-.585.285c.28.54.62 1.015 1.02 1.425.4.41.88.745 1.44 1.005.56.26 1.205.39 1.935.39.96 0 1.84-.19 2.64-.57.8-.38 1.44-.91 1.92-1.59.48-.68.72-1.48.72-2.4 0-.81-.17-1.515-.51-2.115-.34-.6-.82-1.085-1.44-1.455-.62-.37-1.36-.63-2.22-.78-.86-.15-1.79-.225-2.79-.225-1.46 0-2.82.18-4.08.54-1.26.36-2.34.87-3.24 1.53-.9.66-1.59 1.45-2.07 2.37-.48.92-.72 1.95-.72 3.09 0 .9.15 1.695.45 2.385.3.69.735 1.265 1.305 1.725.57.46 1.27.795 2.1 1.005.83.21 1.75.315 2.76.315-1.36-1.16-2.04-2.76-2.04-4.8 0-.48.045-.96.135-1.44z"/></svg>'
|
|
),
|
|
'apple' => array(
|
|
'name' => 'Apple Books',
|
|
'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>'
|
|
),
|
|
'barnes' => array(
|
|
'name' => 'Barnes & Noble',
|
|
'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M21.94 4.88C21.76 4.58 21.47 4.38 21.12 4.28 20.77 4.18 20.39 4.17 20 4.25c-.4.07-.77.22-1.12.43-.35.22-.64.5-.88.85-.23.35-.4.75-.49 1.19-.1.44-.1.89 0 1.33.09.44.26.84.49 1.2.24.35.53.64.88.86.35.22.72.36 1.12.43.39.07.78.07 1.17 0 .39-.07.75-.22 1.1-.45.35-.23.64-.52.88-.87.23-.35.41-.75.49-1.19.09-.44.09-.89 0-1.33-.08-.44-.26-.84-.49-1.2-.24-.35-.53-.64-.88-.86-.35-.23-.72-.37-1.12-.44-.18-.03-.36-.05-.54-.04zm-1.24 2.08c-.06.17-.15.32-.27.44-.12.12-.26.21-.42.27-.16.06-.32.09-.5.09-.18 0-.35-.03-.5-.09-.16-.06-.3-.15-.42-.27-.12-.12-.21-.27-.27-.44-.06-.17-.09-.35-.09-.53s.03-.35.09-.53c.06-.17.15-.32.27-.44.12-.12.26-.21.42-.27.16-.06.32-.09.5-.09s.35.03.5.09c.16.06.3.15.42.27.12.12.21.27.27.44.06.17.09.35.09.53s-.03.36-.09.53zM12 6.25c-2.63 0-4.77 2.08-4.77 4.64 0 .72.16 1.4.45 2.02.29.62.7 1.14 1.22 1.56.52.42 1.12.72 1.79.91.67.19 1.38.26 2.13.21.75-.05 1.46-.21 2.13-.49.67-.28 1.27-.68 1.79-1.19.52-.51.93-1.12 1.22-1.82.29-.7.44-1.46.44-2.26 0-2.56-2.14-4.64-4.77-4.64zM11.53 1.75c.96 0 1.88.17 2.75.51.87.34 1.62.82 2.25 1.44.63.62 1.13 1.37 1.48 2.25.36.88.53 1.85.53 2.9 0 .96-.17 1.88-.51 2.75-.34.87-.82 1.62-1.44 2.25-.62.63-1.37 1.13-2.25 1.48-.88.36-1.85.53-2.9.53-.96 0-1.88-.17-2.75-.51-.87-.34-1.62-.82-2.25-1.44-.63-.62-1.13-1.37-1.48-2.25-.36-.88-.53-1.85-.53-2.9 0-.96.17-1.88.51-2.75.34-.87.82-1.62 1.44-2.25.62-.63 1.37-1.13 2.25-1.48.88-.36 1.85-.53 2.9-.53z"/></svg>'
|
|
),
|
|
'kobo' => array(
|
|
'name' => 'Kobo',
|
|
'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M21.385 14.197c-.29.205-.62.307-.99.307-.36 0-.71-.102-.99-.307l-.13-.093c-.322-.228-.49-.548-.49-.907v-.007c0-.36.168-.68.49-.908l.13-.092c.28-.205.63-.308.99-.308.37 0 .7.103.99.308l.13.092c.322.229.49.549.49.908v.007c0 .359-.168.679-.49.907l-.13.093zm-1.97-2.86c-.29.205-.62.307-.99.307-.37 0-.71-.102-.99-.307l-.13-.093c-.322-.228-.49-.548-.49-.907v-.007c0-.36.168-.68.49-.908l.13-.092c.28-.205.63-.308.99-.308.37 0 .7.103.99.308l.13.092c.322.229.49.549.49.908v.007c0 .359-.168.679-.49.907l-.13.093zm-1.97-2.86c-.29.205-.62.307-.99.307-.37 0-.71-.102-.99-.307l-.13-.093c-.322-.228-.49-.548-.49-.907V7.57c0-.36.168-.68.49-.908l.13-.092c.28-.205.63-.308.99-.308.37 0 .7.103.99.308l.13.092c.322.229.49.549.49.908v.007c0 .359-.168.679-.49.907l-.13.093zm-1.97-2.86c-.29.205-.62.307-.99.307-.37 0-.71-.102-.99-.307l-.13-.093c-.322-.228-.49-.548-.49-.907V4.71c0-.36.168-.68.49-.908l.13-.092c.28-.205.63-.308.99-.308.37 0 .7.103.99.308l.13.092c.322.229.49.549.49.908v.007c0 .359-.168.679-.49.907l-.13.093zM5.68 18.14c.36 0 .7-.102.99-.308l.13-.092c.322-.229.49-.549.49-.908v-.007c0-.36-.168-.68-.49-.908l-.13-.092c-.29-.205-.63-.308-.99-.308-.37 0-.71.103-.99.308l-.13.092c-.322.229-.49.549-.49.908v.007c0 .36.168.68.49.908l.13.092c.28.205.62.308.99.308zm.5-2.58c.36 0 .7-.103.99-.308l.13-.093c.322-.228.49-.548.49-.907v-.007c0-.36-.168-.68-.49-.908l-.13-.092c-.29-.205-.63-.308-.99-.308-.37 0-.71.103-.99.308l-.13.092c-.322.229-.49.549-.49.908v.007c0 .36.168.68.49.908l.13.093c.28.205.62.308.99.308zm.5-2.58c.36 0 .7-.103.99-.308l.13-.093c.322-.228.49-.548.49-.907V11.98c0-.36-.168-.68-.49-.908l-.13-.092c-.29-.205-.63-.308-.99-.308-.37 0-.71.103-.99.308l-.13.092c-.322.229-.49.549-.49.908v.007c0 .36.168.68.49.908l.13.093c.28.205.62.308.99.308zm.5-2.58c.36 0 .7-.103.99-.308l.13-.093c.322-.228.49-.548.49-.907V9.4c0-.36-.168-.68-.49-.908l-.13-.092c-.29-.205-.63-.308-.99-.308-.37 0-.71.103-.99.308l-.13.092c-.322.229-.49.549-.49.908v.007c0 .36.168.68.49.908l.13.093c.28.205.62.308.99.308zM5.18 3.77c.36 0 .7.103.99.308l.13.092c.322.229.49.549.49.908v.007c0 .36-.168.68-.49.908l-.13.093c-.29.205-.63.307-.99.307-.37 0-.71-.102-.99-.307l-.13-.093c-.322-.229-.49-.549-.49-.908v-.007c0-.36.168-.68.49-.908l.13-.092c.28-.205.62-.308.99-.308z"/></svg>'
|
|
),
|
|
'google' => array(
|
|
'name' => 'Google Play',
|
|
'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M3.609 1.814L13.792 12 3.61 22.186c-.186.185-.437.247-.656.165-.22-.082-.365-.292-.365-.527V2.176c0-.235.145-.445.365-.527.219-.082.47-.02.656.165zm14.591 3.19l3.8 3.8-3.8 3.8-3.8-3.8 3.8-3.8zm-5.88 3.578l5.88-3.578-5.88-3.578-5.88 3.578 5.88 3.578z"/></svg>'
|
|
),
|
|
);
|
|
|
|
$isbn = get_post_meta($book_id, 'isbn_' . $format, true);
|
|
|
|
foreach ($retailers as $key => $retailer) {
|
|
$meta_key = $format . '_url_' . $key . '_' . $language;
|
|
$url = '';
|
|
|
|
$lang_url = get_post_meta($book_id, $meta_key, true);
|
|
if ($lang_url) {
|
|
$url = $lang_url;
|
|
}
|
|
|
|
if (!$url) {
|
|
$default_url = get_post_meta($book_id, $format . '_url_' . $key, true);
|
|
if ($default_url) {
|
|
$url = $default_url;
|
|
}
|
|
}
|
|
|
|
if (!$url && $key === 'amazon' && $isbn) {
|
|
$url = 'https://www.amazon.com/dp/' . $isbn;
|
|
}
|
|
|
|
if ($url) {
|
|
printf(
|
|
'<a href="%s" class="retailer-link retailer-%s" target="_blank" rel="noopener noreferrer" title="%s">%s</a>',
|
|
esc_url($url),
|
|
esc_attr($key),
|
|
esc_attr($retailer['name']),
|
|
$retailer['svg']
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|