ay( $this->terms, &$this ) ); if ( null !== $this->terms ) { return $this->terms; } if ( $args['cache_results'] ) { $cache_key = $this->generate_cache_key( $args, $this->request ); $cache = wp_cache_get( $cache_key, 'term-queries' ); if ( false !== $cache ) { if ( 'ids' === $_fields ) { $cache = array_map( 'intval', $cache ); } elseif ( 'count' !== $_fields ) { if ( ( 'all_with_object_id' === $_fields && ! empty( $args['object_ids'] ) ) || ( 'all' === $_fields && $args['pad_counts'] || $fields_is_filtered ) ) { $term_ids = wp_list_pluck( $cache, 'term_id' ); } else { $term_ids = array_map( 'intval', $cache ); } _prime_term_caches( $term_ids, $args['update_term_meta_cache'] ); $term_objects = $this->populate_terms( $cache ); $cache = $this->format_terms( $term_objects, $_fields ); } $this->terms = $cache; return $this->terms; } } if ( 'count' === $_fields ) { $count = $wpdb->get_var( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( $args['cache_results'] ) { wp_cache_set( $cache_key, $count, 'term-queries' ); } return $count; } $terms = $wpdb->get_results( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared if ( empty( $terms ) ) { if ( $args['cache_results'] ) { wp_cache_add( $cache_key, array(), 'term-queries' ); } return array(); } $term_ids = wp_list_pluck( $terms, 'term_id' ); _prime_term_caches( $term_ids, false ); $term_objects = $this->populate_terms( $terms ); if ( $child_of ) { foreach ( $taxonomies as $_tax ) { $children = _get_term_hierarchy( $_tax ); if ( ! empty( $children ) ) { $term_objects = _get_term_children( $child_of, $term_objects, $_tax ); } } } // Update term counts to include children. if ( $args['pad_counts'] && 'all' === $_fields ) { foreach ( $taxonomies as $_tax ) { _pad_term_counts( $term_objects, $_tax ); } } // Make sure we show empty categories that have children. if ( $hierarchical && $args['hide_empty'] && is_array( $term_objects ) ) { foreach ( $term_objects as $k => $term ) { if ( ! $term->count ) { $children = get_term_children( $term->term_id, $term->taxonomy ); if ( is_array( $children ) ) { foreach ( $children as $child_id ) { $child = get_term( $child_id, $term->taxonomy ); if ( $child->count ) { continue 2; } } } // It really is empty. unset( $term_objects[ $k ] ); } } } // Hierarchical queries are not limited, so 'offset' and 'number' must be handled now. if ( $hierarchical && $number && is_array( $term_objects ) ) { if ( $offset >= count( $term_objects ) ) { $term_objects = array(); } else { $term_objects = array_slice( $term_objects, $offset, $number, true ); } } // Prime termmeta cache. if ( $args['update_term_meta_cache'] ) { $term_ids = wp_list_pluck( $term_objects, 'term_id' ); wp_lazyload_term_meta( $term_ids ); } if ( 'all_with_object_id' === $_fields && ! empty( $args['object_ids'] ) ) { $term_cache = array(); foreach ( $term_objects as $term ) { $object = new stdClass(); $object->term_id = $term->term_id; $object->object_id = $term->object_id; $term_cache[] = $object; } } elseif ( 'all' === $_fields && $args['pad_counts'] ) { $term_cache = array(); foreach ( $term_objects as $term ) { $object = new stdClass(); $object->term_id = $term->term_id; $object->count = $term->count; $term_cache[] = $object; } } elseif ( $fields_is_filtered ) { $term_cache = $term_objects; } else { $term_cache = wp_list_pluck( $term_objects, 'term_id' ); } if ( $args['cache_results'] ) { wp_cache_add( $cache_key, $term_cache, 'term-queries' ); } $this->terms = $this->format_terms( $term_objects, $_fields ); return $this->terms; } /** * Parse and sanitize 'orderby' keys passed to the term query. * * @since 4.6.0 * * @param string $orderby_raw Alias for the field to order by. * @return string|false Value to used in the ORDER clause. False otherwise. */ protected function parse_orderby( $orderby_raw ) { $_orderby = strtolower( $orderby_raw ); $maybe_orderby_meta = false; if ( in_array( $_orderby, array( 'term_id', 'name', 'slug', 'term_group' ), true ) ) { $orderby = "t.$_orderby"; } elseif ( in_array( $_orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id', 'description' ), true ) ) { $orderby = "tt.$_orderby"; } elseif ( 'term_order' === $_orderby ) { $orderby = 'tr.term_order'; } elseif ( 'include' === $_orderby && ! empty( $this->query_vars['include'] ) ) { $include = implode( ',', wp_parse_id_list( $this->query_vars['include'] ) ); $orderby = "FIELD( t.term_id, $include )"; } elseif ( 'slug__in' === $_orderby && ! empty( $this->query_vars['slug'] ) && is_array( $this->query_vars['slug'] ) ) { $slugs = implode( "', '", array_map( 'sanitize_title_for_query', $this->query_vars['slug'] ) ); $orderby = "FIELD( t.slug, '" . $slugs . "')"; } elseif ( 'none' === $_orderby ) { $orderby = ''; } elseif ( empty( $_orderby ) || 'id' === $_orderby || 'term_id' === $_orderby ) { $orderby = 't.term_id'; } else { $orderby = 't.name'; // This may be a value of orderby related to meta. $maybe_orderby_meta = true; } /** * Filters the ORDERBY clause of the terms query. * * @since 2.8.0 * * @param string $orderby `ORDERBY` clause of the terms query. * @param array $args An array of term query arguments. * @param string[] $taxonomies An array of taxonomy names. */ $orderby = apply_filters( 'get_terms_orderby', $orderby, $this->query_vars, $this->query_vars['taxonomy'] ); // Run after the 'get_terms_orderby' filter for backward compatibility. if ( $maybe_orderby_meta ) { $maybe_orderby_meta = $this->parse_orderby_meta( $_orderby ); if ( $maybe_orderby_meta ) { $orderby = $maybe_orderby_meta; } } return $orderby; } /** * Format response depending on field requested. * * @since 6.0.0 * * @param WP_Term[] $term_objects Array of term objects. * @param string $_fields Field to format. * * @return WP_Term[]|int[]|string[] Array of terms / strings / ints depending on field requested. */ protected function format_terms( $term_objects, $_fields ) { $_terms = array(); if ( 'id=>parent' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[ $term->term_id ] = $term->parent; } } elseif ( 'ids' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[] = (int) $term->term_id; } } elseif ( 'tt_ids' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[] = (int) $term->term_taxonomy_id; } } elseif ( 'names' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[] = $term->name; } } elseif ( 'slugs' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[] = $term->slug; } } elseif ( 'id=>name' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[ $term->term_id ] = $term->name; } } elseif ( 'id=>slug' === $_fields ) { foreach ( $term_objects as $term ) { $_terms[ $term->term_id ] = $term->slug; } } elseif ( 'all' === $_fields || 'all_with_object_id' === $_fields ) { $_terms = $term_objects; } return $_terms; } /** * Generate the ORDER BY clause for an 'orderby' param that is potentially related to a meta query. * * @since 4.6.0 * * @param string $orderby_raw Raw 'orderby' value passed to WP_Term_Query. * @return string ORDER BY clause. */ protected function parse_orderby_meta( $orderby_raw ) { $orderby = ''; // Tell the meta query to generate its SQL, so we have access to table aliases. $this->meta_query->get_sql( 'term', 't', 'term_id' ); $meta_clauses = $this->meta_query->get_clauses(); if ( ! $meta_clauses || ! $orderby_raw ) { return $orderby; } $allowed_keys = array(); $primary_meta_key = null; $primary_meta_query = reset( $meta_clauses ); if ( ! empty( $primary_meta_query['key'] ) ) { $primary_meta_key = $primary_meta_query['key']; $allowed_keys[] = $primary_meta_key; } $allowed_keys[] = 'meta_value'; $allowed_keys[] = 'meta_value_num'; $allowed_keys = array_merge( $allowed_keys, array_keys( $meta_clauses ) ); if ( ! in_array( $orderby_raw, $allowed_keys, true ) ) { return $orderby; } switch ( $orderby_raw ) { case $primary_meta_key: case 'meta_value': if ( ! empty( $primary_meta_query['type'] ) ) { $orderby = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})"; } else { $orderby = "{$primary_meta_query['alias']}.meta_value"; } break; case 'meta_value_num': $orderby = "{$primary_meta_query['alias']}.meta_value+0"; break; default: if ( array_key_exists( $orderby_raw, $meta_clauses ) ) { // $orderby corresponds to a meta_query clause. $meta_clause = $meta_clauses[ $orderby_raw ]; $orderby = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})"; } break; } return $orderby; } /** * Parse an 'order' query variable and cast it to ASC or DESC as necessary. * * @since 4.6.0 * * @param string $order The 'order' query variable. * @return string The sanitized 'order' query variable. */ protected function parse_order( $order ) { if ( ! is_string( $order ) || empty( $order ) ) { return 'DESC'; } if ( 'ASC' === strtoupper( $order ) ) { return 'ASC'; } else { return 'DESC'; } } /** * Used internally to generate a SQL string related to the 'search' parameter. * * @since 4.6.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $search Search string. * @return string Search SQL. */ protected function get_search_sql( $search ) { global $wpdb; $like = '%' . $wpdb->esc_like( $search ) . '%'; return $wpdb->prepare( '((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like ); } /** * Creates an array of term objects from an array of term IDs. * * Also discards invalid term objects. * * @since 4.9.8 * * @param Object[]|int[] $terms List of objects or term ids. * @return WP_Term[] Array of `WP_Term` objects. */ protected function populate_terms( $terms ) { $term_objects = array(); if ( ! is_array( $terms ) ) { return $term_objects; } foreach ( $terms as $key => $term_data ) { if ( is_object( $term_data ) && property_exists( $term_data, 'term_id' ) ) { $term = get_term( $term_data->term_id ); if ( property_exists( $term_data, 'object_id' ) ) { $term->object_id = (int) $term_data->object_id; } if ( property_exists( $term_data, 'count' ) ) { $term->count = (int) $term_data->count; } } else { $term = get_term( $term_data ); } if ( $term instanceof WP_Term ) { $term_objects[ $key ] = $term; } } return $term_objects; } /** * Generate cache key. * * @since 6.2.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $args WP_Term_Query arguments. * @param string $sql SQL statement. * * @return string Cache key. */ protected function generate_cache_key( array $args, $sql ) { global $wpdb; // $args can be anything. Only use the args defined in defaults to compute the key. $cache_args = wp_array_slice_assoc( $args, array_keys( $this->query_var_defaults ) ); unset( $cache_args['cache_results'], $cache_args['update_term_meta_cache'] ); if ( 'count' !== $args['fields'] && 'all_with_object_id' !== $args['fields'] ) { $cache_args['fields'] = 'all'; } // Replace wpdb placeholder in the SQL statement used by the cache key. $sql = $wpdb->remove_placeholder_escape( $sql ); $key = md5( serialize( $cache_args ) . $sql ); $last_changed = wp_cache_get_last_changed( 'terms' ); return "get_terms:$key:$last_changed"; } } /** * Returns the next and previous posts pagination. * * @param int $total Total pages. * @param int $current The current page. * @return string The HTML output for the posts pagination. */ function tripp_next_previous_pagination( $total = 0, $current = 0 ) { if ( ! $current ) { $current = max( 1, get_query_var( 'paged' ) ); } $pagination = ''; // Previous link. if ( $current > 1 ) { $label = '' . esc_html__( 'Newer', 'tripp' ) . ''; $pagination = get_previous_posts_link( $label ); } // Current link. if ( $total > 1 ) { $pagination .= '' . esc_html( $current ) . ''; } // Next link. $nextpage = absint( $current ) + 1; if ( $nextpage <= $total ) { $label = '' . esc_html__( 'Older', 'tripp' ) . ''; $pagination .= get_next_posts_link( $label, $total ); } return $pagination; } /** * Retrieves a numbered pagination. * * @param array $args { * Optional. Default pagination arguments, see paginate_links(). * * @type string $screen_reader_text Screen reader text for navigation element. * Default 'Posts navigation'. * @type string $aria_label ARIA label text for the nav element. Default 'Posts'. * @type string $class Custom class for the nav element. Default 'pagination'. * } * @return string Markup for pagination links. */ function tripp_numbered_pagination( $args = array() ) { // Make sure the nav element has an aria-label attribute: fallback to the screen reader text. if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) { $args['aria_label'] = $args['screen_reader_text']; } $args = wp_parse_args( $args, array( 'end_size' => 0, 'mid_size' => 1, 'prev_text' => sprintf( '%s', esc_html__( 'Newer', 'tripp' ) ), 'next_text' => sprintf( '%s', esc_html__( 'Older', 'tripp' ) ), ) ); // Make sure we get a string back. Plain is the next best thing. if ( isset( $args['type'] ) && 'array' === $args['type'] ) { $args['type'] = 'plain'; } // Set up paginated links. return paginate_links( $args ); } /** * Gets the pagination navigation. * * @param string $page_links The page links. * @param string $class The pagination class name. * @return string The HTML output for the posts pagination. */ function tripp_get_pagination( $page_links = '', $class = '' ) { if ( empty( $page_links ) ) { return ''; } $output = sprintf( '', $class, $page_links ); return $output; } /** * Returns the URL of the post page. * * @global WP_Rewrite $wp_rewrite * * @param int $i Page number. * @return string URL of the post page. */ function tripp_link_page_url( $i ) { global $wp_rewrite; $post = get_post(); $query_args = array(); if ( 1 === $i ) { $url = get_permalink(); } else { $permalink = get_option( 'permalink_structure' ); if ( empty( $permalink ) || in_array( $post->post_status, array( 'draft', 'pending' ), true ) ) { $url = add_query_arg( 'page', $i, get_permalink() ); } elseif ( 'page' === get_option( 'show_on_front' ) && absint( get_option( 'page_on_front' ) ) === $post->ID ) { $url = trailingslashit( get_permalink() ) . user_trailingslashit( "$wp_rewrite->pagination_base/" . $i, 'single_paged' ); } else { $url = trailingslashit( get_permalink() ) . user_trailingslashit( $i, 'single_paged' ); } } if ( is_preview() ) { if ( ( 'draft' !== $post->post_status ) && isset( $_GET['preview_id'], $_GET['preview_nonce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['preview_id'] = absint( wp_unslash( $_GET['preview_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['preview_nonce'] = sanitize_key( $_GET['preview_nonce'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } $url = get_preview_post_link( $post, $query_args, $url ); } return $url; } /** * Returns whether the footer can be displayed. * * @param int $id The post ID. * @return bool Whether the footer can be displayed. */ function tripp_has_footer( $id = 0 ) { if ( empty( $id ) ) { $id = tripp_get_page_id(); } return false === (bool) get_post_meta( $id, '_tripp_hide_footer', true ); } /** * Return whether the footer gap is visible. * * @param int $id The post ID. * @return bool Whether the footer gap is visible. */ function tripp_has_footer_gap( $id = 0 ) { if ( ( is_archive() && ! is_post_type_archive() ) ) { return true; } if ( empty( $id ) ) { $id = tripp_get_page_id(); } return false === (bool) get_post_meta( $id, '_tripp_hide_footer_gap', true ); } /** * Determines if the Footer Logo can be displayed. * * @return bool Whether the Footer Logo can be displayed. */ function tripp_has_footer_logo() { return (bool) get_theme_mod( 'footer_logo', 0 ); } /** * Prints out the footer widgets class. * * @param string $class Space-separated string. * @param int $columns Number of columns. */ function tripp_footer_widgets_class( $class = '', $columns = 1 ) { $classes = array( $class ); if ( absint( $columns ) > 1 ) { $classes[] = "tripp-grid has-{$columns}-columns"; } else { $classes[] = 'has-one-column'; } echo esc_attr( implode( ' ', $classes ) ); } /** * Prints out the footer columns and widgets. * * @param int $columns Number of columns. */ function tripp_footer_columns( $columns = 1 ) { $is_preview = is_customize_preview(); $max = $is_preview ? 4 : $columns; for ( $i = 1; $i <= $max; $i++ ) { $name = 'footer-' . $i; $class = 'footer-col-' . esc_attr( $i ); if ( $is_preview && $i > $columns ) { $class .= ' is-hidden'; } echo '
'; dynamic_sidebar( $name ); echo '
'; } } /** * Displays footer widgets. */ function tripp_footer_widgets() { $columns = get_theme_mod( 'footer_widgets', 0 ); if ( absint( $columns ) > 0 ) { get_template_part( 'template-parts/footer/footer', 'widgets', array( 'columns' => $columns ) ); } } /** * Displays footer info. */ function tripp_footer_info() { get_template_part( 'template-parts/footer/footer', 'info' ); } /** * Displays Footer Logo. */ function tripp_footer_logo() { $html = ''; $footer_logo_id = absint( get_theme_mod( 'footer_logo', 0 ) ); // We have a logo. Logo is go. if ( $footer_logo_id ) { $footer_logo_attr = array(); $footer_logo_retina_id = absint( get_theme_mod( 'footer_logo_retina', 0 ) ); if ( $footer_logo_retina_id ) { $srcsets = array(); $srcsets[] = wp_get_attachment_image_url( $footer_logo_id, 'full' ) . ' 1x'; $srcsets[] = wp_get_attachment_image_url( $footer_logo_retina_id, 'full' ) . ' 2x'; $footer_logo_attr['srcset'] = implode( ', ', $srcsets ); unset( $footer_logo_attr['sizes'] ); } /* * If the logo alt attribute is empty, get the site title and explicitly * pass it to the attributes used by wp_get_attachment_image(). */ $image_alt = get_post_meta( $footer_logo_id, '_wp_attachment_image_alt', true ); if ( empty( $image_alt ) ) { $footer_logo_attr['alt'] = get_bloginfo( 'name', 'display' ); } /* * If the alt attribute is not empty, there's no need to explicitly pass * it because wp_get_attachment_image() already adds the alt attribute. */ echo sprintf( '%2$s', esc_url( tripp_logo_url() ), wp_get_attachment_image( $footer_logo_id, 'full', false, $footer_logo_attr ) ); } elseif ( is_customize_preview() ) { // If no logo is set but we're in the Customizer, leave a placeholder (needed for the live preview). echo sprintf( '', esc_url( tripp_logo_url() ) ); } } /** * Displays footer menu. */ function tripp_footer_menu() { if ( ( 'show' === get_theme_mod( 'footer_menu', '' ) || is_customize_preview() ) && has_nav_menu( 'footer' ) ) { echo ''; } } /** * Displays footer social links. */ function tripp_footer_social_links() { $footer_links = get_theme_mod( 'footer_links', '' ); if ( function_exists( 'flextension_social_icons_widget' ) && ( ! empty( $footer_links ) || is_customize_preview() ) ) { echo ''; } } /** * Displays language switcher in the footer. * * @since 1.2.2 */ function tripp_footer_language_switcher() { if ( function_exists( 'wpml_footer_language_selector_action' ) && class_exists( 'WPML_Language_Switcher', false ) ) { global $wpml_language_switcher; if ( $wpml_language_switcher instanceof WPML_Language_Switcher ) { $footer_slot = $wpml_language_switcher->get_slot( 'statics', 'footer' ); if ( true === (bool) $footer_slot->get( 'show' ) ) { wpml_footer_language_selector_action(); } } } } /** * Returns default Site Info. * * @return string Default site info. */ function tripp_default_site_info() { $site_title = get_bloginfo( 'name' ); if ( empty( $site_title ) ) { $site_title = 'Tripp'; } return '© ' . gmdate( 'Y' ) . ' ' . $site_title . '. Proudly powered by WordPress.'; } /** * Displays Site Info in the footer. */ function tripp_footer_text() { $html = get_theme_mod( 'footer_text', tripp_default_site_info() ); if ( ! empty( $html ) || is_customize_preview() ) { echo '' . wp_kses_data( $html ) . ''; } }