You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
583 lines
15 KiB
583 lines
15 KiB
<?php |
|
/** |
|
* Aldine Helpers |
|
* |
|
* @package Aldine |
|
*/ |
|
|
|
namespace Aldine\Helpers; |
|
|
|
use const Aldine\Customizer\MAX_FEATURED_BOOKS; |
|
use function Pressbooks\Metadata\get_institutions_flattened; |
|
use function \Pressbooks\Metadata\book_information_to_schema; |
|
use function \Pressbooks\Metadata\is_bisac; |
|
use function \Pressbooks\Utility\str_starts_with; |
|
use Pressbooks\DataCollector\Book as BookDataCollector; |
|
use Pressbooks\Licensing; |
|
|
|
/** |
|
* Get all the books in the catalog |
|
* |
|
* @return array[] |
|
*/ |
|
function get_catalog_options(): array { |
|
|
|
$dc = BookDataCollector::init(); |
|
/** |
|
* Filter the WP_Site_Query args for the catalog display. |
|
* |
|
* @since 1.0.0 |
|
*/ |
|
$args = apply_filters( |
|
'pb_aldine_catalog_query_args', |
|
/** |
|
* Deprecation notice |
|
* |
|
* @deprecated 1.0.0 |
|
* |
|
* @see Pressbooks Publisher |
|
*/ |
|
apply_filters( |
|
'pb_publisher_catalog_query_args', |
|
[ |
|
'number' => 1000000, |
|
'meta_key' => $dc::IN_CATALOG, // @codingStandardsIgnoreLine |
|
'meta_value' => 1, // @codingStandardsIgnoreLine |
|
'public' => 1, |
|
'archived' => 0, |
|
'spam' => 0, |
|
'deleted' => 0, |
|
'network_id' => get_network()->site_id, |
|
] |
|
) |
|
); |
|
return get_catalog_data( $args ); |
|
} |
|
|
|
/** |
|
* Get featured books |
|
* |
|
* @return array |
|
*/ |
|
function get_featured_books(): array { |
|
|
|
$featured_books = []; |
|
|
|
foreach ( range( 1, MAX_FEATURED_BOOKS ) as $book ) { |
|
$book = get_option( 'pb_front_page_catalog_book_' . $book ); |
|
if ( $book ) { |
|
$featured_books[] = $book; |
|
} |
|
} |
|
|
|
if ( empty( $featured_books ) ) { |
|
return []; |
|
} |
|
|
|
$args = [ |
|
'site__in' => $featured_books, |
|
'sort_by_featured' => true, |
|
]; |
|
|
|
return get_catalog_data( $args ); |
|
} |
|
|
|
/** |
|
* Get catalog data |
|
* |
|
* @param array $args Query arguments |
|
* @return array[] |
|
*/ |
|
function get_catalog_data( array $args ): array { |
|
$dc = BookDataCollector::init(); |
|
/** |
|
* WordPress site |
|
* |
|
* @var \WP_Site $site |
|
*/ |
|
|
|
$sites_in_catalog = []; |
|
$sites = get_sites( $args ); |
|
foreach ( $sites as $site ) { |
|
$site->pb_title = $dc->get( $site->blog_id, $dc::TITLE ); |
|
$sites_in_catalog[] = $site; |
|
} |
|
$books = []; |
|
foreach ( $sites_in_catalog as $site ) { |
|
$book_information = $dc->get( $site->blog_id, $dc::BOOK_INFORMATION_ARRAY ); |
|
if ( is_array( $book_information ) && ! empty( $book_information ) ) { |
|
$schema = book_information_to_schema( $book_information ); |
|
$book['title'] = $schema['name']; |
|
$book['id'] = $site->blog_id; |
|
$book['link'] = get_blogaddress_by_id( $site->blog_id ); |
|
$book['metadata'] = $schema; |
|
$books[] = $book; |
|
} |
|
} |
|
// Sort by featured books. |
|
if ( isset( $args['sort_by_featured'] ) ) { |
|
usort( $books, function ( $a, $b ) use ( $args ) { |
|
return array_search( $a['id'], $args['site__in'], true ) - array_search($b['id'], |
|
$args['site__in'], true); |
|
} ); |
|
} |
|
|
|
return [ |
|
'books' => $books, |
|
]; |
|
} |
|
|
|
/** |
|
* Get paginated catalog data |
|
* |
|
* @param int $page Catalog page |
|
* @param int $per_page Books per page |
|
* @param string $orderby Sort order |
|
* @param string $license Copyright license |
|
* @param string $subject Subject |
|
* |
|
* @return array |
|
*/ |
|
function get_paginated_catalog_data( $page = 1, $per_page = 10, $orderby = 'title', $license = '', $subject = '' ) { |
|
|
|
if ( ! defined( 'PB_PLUGIN_VERSION' ) ) { |
|
return [ |
|
'pages' => 0, |
|
'books' => [], |
|
]; |
|
} |
|
|
|
$dc = BookDataCollector::init(); |
|
|
|
/** |
|
* Filter the WP_Site_Query args for the catalog display. |
|
* |
|
* @since 1.0.0 |
|
*/ |
|
$args = apply_filters( |
|
'pb_aldine_catalog_query_args', |
|
/** |
|
* Deprecation notice |
|
* |
|
* @deprecated 1.0.0 |
|
* |
|
* @see Pressbooks Publisher |
|
*/ |
|
apply_filters( |
|
'pb_publisher_catalog_query_args', |
|
[ |
|
'number' => 1000000, |
|
'meta_key' => $dc::IN_CATALOG, // @codingStandardsIgnoreLine |
|
'meta_value' => 1, // @codingStandardsIgnoreLine |
|
'public' => 1, |
|
'archived' => 0, |
|
'spam' => 0, |
|
'deleted' => 0, |
|
'network_id' => get_network()->site_id, |
|
] |
|
) |
|
); |
|
|
|
/** |
|
* WordPress site |
|
* |
|
* @var \WP_Site $site |
|
*/ |
|
|
|
$sites_in_catalog = []; |
|
$sites = get_sites( $args ); |
|
foreach ( $sites as $site ) { |
|
$site->pb_title = $dc->get( $site->blog_id, $dc::TITLE ); |
|
$sites_in_catalog[] = $site; |
|
} |
|
if ( $orderby === 'latest' ) { |
|
$sites_in_catalog = wp_list_sort( $sites_in_catalog, 'last_updated', 'DESC' ); |
|
} else { |
|
$sites_in_catalog = wp_list_sort( $sites_in_catalog, 'pb_title', 'ASC' ); |
|
} |
|
|
|
$total_pages = ceil( count( $sites_in_catalog ) / $per_page ); |
|
$offset = ( $page - 1 ) * $per_page; |
|
$books = []; |
|
foreach ( $sites_in_catalog as $i => $site ) { |
|
if ( $i < $offset ) { |
|
continue; |
|
} |
|
|
|
$book_information = $dc->get( $site->blog_id, $dc::BOOK_INFORMATION_ARRAY ); |
|
if ( is_array( $book_information ) && ! empty( $book_information ) ) { |
|
$schema = book_information_to_schema( $book_information ); |
|
$book['title'] = $schema['name']; |
|
$book['date-published'] = $schema['datePublished'] ?? ''; |
|
$book['subject'] = $schema['about'][0]['identifier'] ?? ''; |
|
$book['link'] = get_blogaddress_by_id( $site->blog_id ); |
|
$book['metadata'] = $schema; |
|
$books[] = $book; |
|
} |
|
|
|
if ( count( $books ) >= $per_page ) { |
|
break; |
|
} |
|
} |
|
|
|
return [ |
|
'pages' => $total_pages, |
|
'books' => $books, |
|
]; |
|
} |
|
|
|
/** |
|
* Get licenses for catalog display. |
|
* |
|
* @return array |
|
*/ |
|
function get_catalog_licenses() { |
|
if ( defined( 'PB_PLUGIN_VERSION' ) ) { |
|
$licenses = ( new Licensing() )->getSupportedTypes(); |
|
foreach ( $licenses as $key => $value ) { |
|
$licenses[ $key ] = preg_replace( '/\([^)]+\)/', '', $value['desc'] ); |
|
} |
|
return $licenses; |
|
} |
|
return []; |
|
} |
|
|
|
/** |
|
* Get licenses currently in use. |
|
* |
|
* @param array $catalog_data Catalog data |
|
* |
|
* @return array |
|
*/ |
|
function get_available_licenses( $catalog_data ) { |
|
$licenses = []; |
|
$licensing = new Licensing(); |
|
|
|
foreach ( $catalog_data['books'] as $book ) { |
|
$license = $licensing->getLicenseFromUrl( $book['metadata']['license']['url'] ); |
|
if ( ! in_array( $license, $licenses, true ) ) { |
|
$licenses[] = $license; |
|
} |
|
} |
|
|
|
return $licenses; |
|
} |
|
|
|
/** |
|
* Get institutions for catalog display. |
|
* |
|
* @return array |
|
*/ |
|
function get_institutions(): array { |
|
if ( ! defined( 'PB_PLUGIN_VERSION' ) ) { |
|
return []; |
|
} |
|
|
|
return get_institutions_flattened(); |
|
} |
|
|
|
/** |
|
* Get institutions currently in use. |
|
* |
|
* @param array $catalog_data Catalog data |
|
* |
|
* @return array |
|
*/ |
|
function get_available_institutions( array $catalog_data ): array { |
|
$institution_list = get_institutions(); |
|
$book_institutions = array_reduce( $catalog_data['books'], static function( $carry, $book ) { |
|
$names = array_reduce( $book['metadata']['institutions'] ?? [], static function( $carry, $institution ) { |
|
return array_merge( $carry, [ $institution['name'] ] ); |
|
}, [] ); |
|
|
|
return array_merge( $carry, $names ); |
|
}, [] ); |
|
|
|
return array_intersect( $institution_list, $book_institutions ); |
|
} |
|
|
|
/** |
|
* Get subjects currently in use. |
|
* |
|
* @param array $catalog_data Catalog data |
|
* |
|
* @return array |
|
*/ |
|
function get_available_subjects( $catalog_data ) { |
|
$subjects = []; |
|
foreach ( $catalog_data['books'] as $book ) { |
|
if ( ! empty( $book['subject'] ) && ! is_bisac( $book['subject'] ) ) { |
|
$subjects[ substr( $book['subject'], 0, 1 ) ][] = substr( $book['subject'], 0, 2 ); |
|
} |
|
} |
|
|
|
return $subjects; |
|
} |
|
|
|
/** |
|
* Return the default (non-page) menu items. |
|
* |
|
* @param string $items Items |
|
* |
|
* @return string $items |
|
*/ |
|
function get_default_menu( $items = '' ) { |
|
$item_classes = [ |
|
'prefix' => 'nav--primary-item', |
|
'Home' => 'home', |
|
'Contact' => 'contact', |
|
'SignIn' => 'sign-in', |
|
'SignUp' => 'sign-up', |
|
'Admin' => 'admin', |
|
'CreateANewBook' => 'create-book', |
|
'MyBooks' => 'my-books', |
|
'SignOut' => 'sign-out', |
|
]; |
|
|
|
$link = network_home_url( '/' ); |
|
$items = sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
$link, |
|
__( 'Home', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['Home'] |
|
) . $items; |
|
if ( get_option( 'pb_network_contact_form' ) ) { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
'#contact', |
|
__( 'Contact', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['Contact'] |
|
); |
|
} |
|
if ( ! is_user_logged_in() ) { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
wp_login_url( get_permalink() ), |
|
__( 'Sign In', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['SignIn'] |
|
); |
|
if ( in_array( get_site_option( 'registration' ), [ 'user', 'all' ], true ) ) { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
network_home_url( '/wp-signup.php' ), |
|
__( 'Sign Up', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['SignUp'] |
|
); |
|
} |
|
} else { |
|
if ( is_super_admin() || is_user_member_of_blog() ) { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
admin_url(), |
|
__( 'Admin', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['Admin'] |
|
); |
|
} else { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
user_admin_url(), |
|
__( 'Admin', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['Admin'] |
|
); |
|
} |
|
$user_info = get_userdata( get_current_user_id() ); |
|
if ( $user_info->primary_blog ) { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
get_blogaddress_by_id( $user_info->primary_blog ) . 'wp-admin/index.php?page=pb_catalog', |
|
__( 'My Books', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['MyBooks'] |
|
); |
|
} elseif ( in_array( get_site_option( 'registration' ), [ 'blog', 'all' ], true ) ) { |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
network_home_url( '/wp-signup.php' ), |
|
__( 'Create a New Book', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['CreateANewBook'] |
|
); |
|
} |
|
$items .= sprintf( |
|
'<li class="%3$s %3$s-%4$s"><a href="%1$s">%2$s</a></li>', |
|
wp_logout_url( get_permalink() ), |
|
__( 'Sign Out', 'pressbooks-aldine' ), |
|
$item_classes['prefix'], |
|
$item_classes['SignOut'] |
|
); |
|
} |
|
/* @codingStandardsIgnoreStart $items .= sprintf( |
|
* '<li class="header__search js-search"><div class="header__search__form">%s</div></li>', |
|
* get_search_form( false ) |
|
* ); @codingStandardsIgnoreEnd |
|
*/ |
|
|
|
return $items; |
|
} |
|
|
|
/** |
|
* Echo the default menu. |
|
* |
|
* @param array $args Array |
|
* @param string $items Items |
|
*/ |
|
function default_menu( $args = [], $items = '' ) { |
|
printf( |
|
"<{$args['container']} id='{$args['container_id']}' class='{$args['container_class']}' aria-label='{$args['container_aria_label']}'><ul id='{$args['menu_id']}' class='{$args['menu_class']}'>%s</ul></{$args['container']}>", |
|
get_default_menu( $items ) |
|
); |
|
if ( class_exists( '\PressbooksOAuth\OAuth' ) ) { |
|
add_filter( |
|
'pb_oauth_output_button', function( $bool ) { |
|
return false; |
|
} |
|
); |
|
do_action( 'pressbooks_oauth_connect' ); |
|
} |
|
} |
|
|
|
/** |
|
* |
|
* Handler for contact form submissions. |
|
* |
|
* @return false | array |
|
*/ |
|
function handle_contact_form_submission() { |
|
if ( ! isset( $_POST['pb_root_contact_form_nonce'] ) || ! wp_verify_nonce( $_POST['pb_root_contact_form_nonce'], 'pb_root_contact_form' ) ) { |
|
return false; // Security check failed. |
|
} |
|
if ( isset( $_POST['submitted'] ) ) { |
|
// Check the fake anti-spam honeypot field. |
|
foreach ( $_POST as $pkey => $pval ) { |
|
if ( str_starts_with( $pkey, 'firstname' ) && ! empty( $pval ) ) { |
|
return false; // Honeypot failed. |
|
} |
|
} |
|
$contact_email = get_option( 'pb_network_contact_email', get_option( 'admin_email' ) ); |
|
$output = []; |
|
$name = ( isset( $_POST['visitor_name'] ) ) ? $_POST['visitor_name'] : ''; |
|
$email = ( isset( $_POST['visitor_email'] ) ) ? $_POST['visitor_email'] : ''; |
|
$institution = ( isset( $_POST['visitor_institution'] ) ) ? $_POST['visitor_institution'] : ''; |
|
$message = ( isset( $_POST['message'] ) ) ? $_POST['message'] : ''; |
|
$output['values'] = [ |
|
'visitor_name' => esc_attr( $name ), |
|
'visitor_email' => sanitize_email( $email ), |
|
'visitor_institution' => esc_attr( $institution ), |
|
'message' => esc_textarea( $message ), |
|
]; |
|
if ( empty( $name ) ) { |
|
$output['message'] = __( 'Name is required.', 'pressbooks-aldine' ); |
|
$output['status'] = 'error'; |
|
$output['field'] = 'visitor_name'; |
|
} elseif ( empty( $email ) ) { |
|
$output['message'] = __( 'Email is required.', 'pressbooks-aldine' ); |
|
$output['status'] = 'error'; |
|
$output['field'] = 'visitor_email'; |
|
} elseif ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { |
|
$output['message'] = __( 'Email is invalid.', 'pressbooks-aldine' ); |
|
$output['status'] = 'error'; |
|
$output['field'] = 'visitor_email'; |
|
} elseif ( empty( $institution ) ) { |
|
$output['message'] = __( 'Institution is required.', 'pressbooks-aldine' ); |
|
$output['status'] = 'error'; |
|
$output['field'] = 'visitor_institution'; |
|
} elseif ( empty( $message ) ) { |
|
$output['message'] = __( 'Message is required.', 'pressbooks-aldine' ); |
|
$output['status'] = 'error'; |
|
$output['field'] = 'message'; |
|
} else { |
|
$sent = wp_mail( |
|
$contact_email, |
|
/* translators: %s name of contact for submitter */ |
|
sprintf( __( 'Contact Form Submission from %s', 'pressbooks-aldine' ), $name ), |
|
sprintf( |
|
"From: %1\$s <%2\$s>\nInstitution: %3\$s\n\n%4\$s", |
|
stripslashes( $name ), |
|
$email, |
|
stripslashes( $institution ), |
|
wp_strip_all_tags( $message ) |
|
), |
|
"From: ${email}\r\nReply-To: ${email}\r\n" |
|
); |
|
if ( $sent ) { |
|
$output['message'] = __( 'Your message was sent!', 'pressbooks-aldine' ); |
|
$output['status'] = 'success'; |
|
} else { |
|
$output['message'] = __( 'Your message could not be sent.', 'pressbooks-aldine' ); |
|
$output['status'] = 'error'; |
|
} |
|
} |
|
return $output; |
|
} |
|
return false; |
|
} |
|
|
|
/** |
|
* Does a page have page sections? |
|
* |
|
* @param int $post_id The page. |
|
* |
|
* @return bool |
|
*/ |
|
function has_sections( $post_id ) { |
|
$post_content = get_post_field( 'post_content', $post_id ); |
|
if ( ! empty( $post_content ) ) { |
|
if ( strpos( $post_content, 'page-section' ) || strpos( $post_content, 'aldine_page_section' ) ) { |
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
/** |
|
* Maybe truncate a string to a sensible length. |
|
* |
|
* @param string $string The string. |
|
* @param int $length Max length in characters. |
|
* |
|
* @return string |
|
*/ |
|
function maybe_truncate_string( $string, $length = 40 ) { |
|
if ( strlen( $string ) > $length ) { |
|
return substr( $string, 0, strpos( wordwrap( $string, $length ), "\n" ) ) . '…'; |
|
} |
|
return $string; |
|
} |
|
|
|
/** |
|
* Get catalog page. |
|
* |
|
* @return WP_Post|null |
|
*/ |
|
function get_catalog_page(): ?\WP_Post { |
|
$catalog_pages = get_pages( [ |
|
'meta_key' => '_wp_page_template', |
|
'meta_value' => 'page-catalog.php', //phpcs:ignore HM.Performance.SlowMetaQuery.slow_query_meta_value |
|
]); |
|
return $catalog_pages[0] ?? null; |
|
} |
|
|
|
/** |
|
* This function generate a class to know if the current page is a custom frontpage. |
|
* |
|
* @return string |
|
*/ |
|
function custom_homepage(): string { |
|
$home_page = get_option( 'page_on_front' ); |
|
if ( $home_page ) { |
|
$template = get_page_template_slug( $home_page ); |
|
if ( 'page-catalog.php' === $template ) { |
|
return 'custom-homepage'; |
|
} |
|
} |
|
return ''; |
|
}
|
|
|