271 lines
6.9 KiB
PHP
271 lines
6.9 KiB
PHP
<?php
|
|
// Copyright 2026 Umbra Tools (umbratools.com)
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
/**
|
|
* Navigation Menu Hooks
|
|
*
|
|
* @package BD_Murphy
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Filter nav menu items to add dynamic submenus
|
|
*
|
|
* @param string $items Menu items HTML.
|
|
* @param stdClass $args Menu arguments.
|
|
* @return string
|
|
*/
|
|
function bdm_filter_nav_menu_items($items, $args) {
|
|
if ($args->theme_location !== 'primary') {
|
|
return $items;
|
|
}
|
|
|
|
// Get books for MyBooks submenu
|
|
$books = bdm_get_books_for_menu();
|
|
if (!empty($books)) {
|
|
$books_submenu = bdm_build_book_submenu($books);
|
|
|
|
// Find or create MyBooks menu item
|
|
if (preg_match('/(<li[^>]*>.*?My\s*Books.*?<\/li>)/s', $items, $matches)) {
|
|
$mybooks_item = $matches[1];
|
|
// Add submenu class to the li
|
|
$mybooks_item_with_sub = preg_replace(
|
|
'/(<li[^>]*class=["\'])/',
|
|
'$1menu-item-has-children ',
|
|
$mybooks_item
|
|
);
|
|
// Close current li and add submenu
|
|
$mybooks_item_with_sub = preg_replace(
|
|
'/<\/li>\s*$/',
|
|
$books_submenu . '</li>',
|
|
$mybooks_item_with_sub
|
|
);
|
|
$items = str_replace($mybooks_item, $mybooks_item_with_sub, $items);
|
|
}
|
|
}
|
|
|
|
// Get series for Series submenu
|
|
$series = bdm_get_series_for_menu();
|
|
if (!empty($series)) {
|
|
$series_submenu = bdm_build_series_submenu($series);
|
|
|
|
if (preg_match('/(<li[^>]*>.*?Series.*?<\/li>)/s', $items, $matches)) {
|
|
$series_item = $matches[1];
|
|
$series_item_with_sub = preg_replace(
|
|
'/(<li[^>]*class=["\'])/',
|
|
'$1menu-item-has-children ',
|
|
$series_item
|
|
);
|
|
$series_item_with_sub = preg_replace(
|
|
'/<\/li>\s*$/',
|
|
$series_submenu . '</li>',
|
|
$series_item_with_sub
|
|
);
|
|
$items = str_replace($series_item, $series_item_with_sub, $items);
|
|
}
|
|
}
|
|
|
|
// Get books with reviews for Reviews submenu
|
|
$review_books = bdm_get_books_with_reviews();
|
|
if (!empty($review_books)) {
|
|
$reviews_submenu = bdm_build_reviews_submenu($review_books);
|
|
|
|
if (preg_match('/(<li[^>]*>.*?Reviews.*?<\/li>)/s', $items, $matches)) {
|
|
$reviews_item = $matches[1];
|
|
$reviews_item_with_sub = preg_replace(
|
|
'/(<li[^>]*class=["\'])/',
|
|
'$1menu-item-has-children ',
|
|
$reviews_item
|
|
);
|
|
$reviews_item_with_sub = preg_replace(
|
|
'/<\/li>\s*$/',
|
|
$reviews_submenu . '</li>',
|
|
$reviews_item_with_sub
|
|
);
|
|
$items = str_replace($reviews_item, $reviews_item_with_sub, $items);
|
|
}
|
|
}
|
|
|
|
return $items;
|
|
}
|
|
add_filter('wp_nav_menu_items', 'bdm_filter_nav_menu_items', 10, 2);
|
|
|
|
/**
|
|
* Get books for menu
|
|
*
|
|
* @return array
|
|
*/
|
|
function bdm_get_books_for_menu() {
|
|
$books = get_posts(array(
|
|
'post_type' => 'book',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => -1,
|
|
'orderby' => 'title',
|
|
'order' => 'ASC',
|
|
));
|
|
|
|
return $books;
|
|
}
|
|
|
|
/**
|
|
* Get series for menu
|
|
*
|
|
* @return array
|
|
*/
|
|
function bdm_get_series_for_menu() {
|
|
if (!taxonomy_exists('series')) {
|
|
return array();
|
|
}
|
|
|
|
$terms = get_terms(array(
|
|
'taxonomy' => 'series',
|
|
'hide_empty' => true,
|
|
'orderby' => 'name',
|
|
'order' => 'ASC',
|
|
));
|
|
|
|
return is_wp_error($terms) ? array() : $terms;
|
|
}
|
|
|
|
/**
|
|
* Get books with reviews
|
|
*
|
|
* @return array
|
|
*/
|
|
function bdm_get_books_with_reviews() {
|
|
$books = get_posts(array(
|
|
'post_type' => 'book',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => -1,
|
|
'orderby' => 'title',
|
|
'order' => 'ASC',
|
|
));
|
|
|
|
$review_books = array();
|
|
foreach ($books as $book) {
|
|
$goodreads = get_post_meta($book->ID, 'goodreads_url', true);
|
|
$amazon = get_post_meta($book->ID, 'amazon_review_url', true);
|
|
if (!empty($goodreads) || !empty($amazon)) {
|
|
$review_books[] = $book;
|
|
}
|
|
}
|
|
|
|
return $review_books;
|
|
}
|
|
|
|
/**
|
|
* Build book submenu HTML
|
|
*
|
|
* @param array $books Books.
|
|
* @return string
|
|
*/
|
|
function bdm_build_book_submenu($books) {
|
|
if (empty($books)) {
|
|
return '';
|
|
}
|
|
|
|
$submenu = "\n" . '<ul class="sub-menu">' . "\n";
|
|
|
|
foreach ($books as $book) {
|
|
$url = get_permalink($book->ID);
|
|
$title = $book->post_title;
|
|
$submenu .= '<li class="menu-item"><a href="' . esc_url($url) . '">' . esc_html($title) . '</a></li>' . "\n";
|
|
}
|
|
|
|
$submenu .= '</ul>';
|
|
|
|
return $submenu;
|
|
}
|
|
|
|
/**
|
|
* Build series submenu HTML
|
|
*
|
|
* @param array $series Series.
|
|
* @return string
|
|
*/
|
|
function bdm_build_series_submenu($series) {
|
|
if (empty($series)) {
|
|
return '';
|
|
}
|
|
|
|
$submenu = "\n" . '<ul class="sub-menu">' . "\n";
|
|
|
|
foreach ($series as $term) {
|
|
$url = get_term_link($term);
|
|
$submenu .= '<li class="menu-item"><a href="' . esc_url($url) . '">' . esc_html($term->name) . '</a></li>' . "\n";
|
|
}
|
|
|
|
$submenu .= '</ul>';
|
|
|
|
return $submenu;
|
|
}
|
|
|
|
/**
|
|
* Build reviews submenu HTML
|
|
*
|
|
* @param array $books Books with reviews.
|
|
* @return string
|
|
*/
|
|
function bdm_build_reviews_submenu($books) {
|
|
if (empty($books)) {
|
|
return '';
|
|
}
|
|
|
|
$submenu = "\n" . '<ul class="sub-menu">' . "\n";
|
|
|
|
foreach ($books as $book) {
|
|
$title = $book->post_title;
|
|
|
|
// Determine the review URL (prefer Goodreads if available)
|
|
$goodreads = get_post_meta($book->ID, 'goodreads_url', true);
|
|
$amazon = get_post_meta($book->ID, 'amazon_review_url', true);
|
|
$url = !empty($goodreads) ? $goodreads : $amazon;
|
|
|
|
if (!empty($url)) {
|
|
$submenu .= '<li class="menu-item"><a href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer">' . esc_html($title) . '</a></li>' . "\n";
|
|
}
|
|
}
|
|
|
|
$submenu .= '</ul>';
|
|
|
|
return $submenu;
|
|
}
|
|
|
|
/**
|
|
* Check if series exist
|
|
*
|
|
* @return bool
|
|
*/
|
|
function bdm_series_exist() {
|
|
if (class_exists('BD_BookShelfHelper')) {
|
|
$terms = get_terms(array(
|
|
'taxonomy' => 'series',
|
|
'hide_empty' => true,
|
|
'fields' => 'count',
|
|
));
|
|
return $terms > 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Add series menu item class
|
|
*
|
|
* @param array $classes CSS classes.
|
|
* @param WP_Post $item Menu item.
|
|
* @param array $args Menu arguments.
|
|
* @param int $depth Item depth.
|
|
* @return array
|
|
*/
|
|
function bdm_nav_menu_css_class($classes, $item, $args, $depth) {
|
|
if ($item->url && false !== strpos($item->url, '/series/')) {
|
|
$classes[] = 'series-menu-item';
|
|
}
|
|
return $classes;
|
|
}
|
|
add_filter('nav_menu_css_class', 'bdm_nav_menu_css_class', 10, 4);
|