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( '
  • %2$s
  • ', $link, __( 'Home', 'pressbooks-aldine' ), $item_classes['prefix'], $item_classes['Home'] ) . $items; if ( get_option( 'pb_network_contact_form' ) ) { $items .= sprintf( '
  • %2$s
  • ', '#contact', __( 'Contact', 'pressbooks-aldine' ), $item_classes['prefix'], $item_classes['Contact'] ); } if ( ! is_user_logged_in() ) { $items .= sprintf( '
  • %2$s
  • ', 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( '
  • %2$s
  • ', 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( '
  • %2$s
  • ', admin_url(), __( 'Admin', 'pressbooks-aldine' ), $item_classes['prefix'], $item_classes['Admin'] ); } else { $items .= sprintf( '
  • %2$s
  • ', 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( '
  • %2$s
  • ', 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( '
  • %2$s
  • ', network_home_url( '/wp-signup.php' ), __( 'Create a New Book', 'pressbooks-aldine' ), $item_classes['prefix'], $item_classes['CreateANewBook'] ); } $items .= sprintf( '
  • %2$s
  • ', wp_logout_url( get_permalink() ), __( 'Sign Out', 'pressbooks-aldine' ), $item_classes['prefix'], $item_classes['SignOut'] ); } /* @codingStandardsIgnoreStart $items .= sprintf( * '', * 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']}'>", 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 ''; }