Skip to content

Commit

Permalink
Add query filters to Course and Lesson archives (#2504)
Browse files Browse the repository at this point in the history
* Add level query filter to Courses archive

* Add topic query filter on course archive

* Enable combining filters

* Correct filter labels

* Add topic, level and language filters to Lessons archive

* Add language filter to Courses archive

* Persist meta query filters
  • Loading branch information
adamwoodnz authored Jun 7, 2024
1 parent 4527063 commit 2fd397a
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 4 deletions.
1 change: 1 addition & 0 deletions wp-content/themes/pub/wporg-learn-2024/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require_once __DIR__ . '/src/learning-pathway-cards/index.php';
require_once __DIR__ . '/src/search-results-context/index.php';
require_once __DIR__ . '/src/upcoming-online-workshops/index.php';
require_once __DIR__ . '/inc/block-config.php';

/**
* Actions and filters.
Expand Down
287 changes: 287 additions & 0 deletions wp-content/themes/pub/wporg-learn-2024/inc/block-config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
<?php
/**
* Set up configuration for dynamic blocks.
*/

namespace WordPressdotorg\Theme\Learn_2024\Block_Config;

use function WPOrg_Learn\Post_Meta\{get_available_post_type_locales};

add_filter( 'wporg_query_filter_options_language', __NAMESPACE__ . '\get_language_options' );
add_filter( 'wporg_query_filter_options_level', __NAMESPACE__ . '\get_level_options' );
add_filter( 'wporg_query_filter_options_topic', __NAMESPACE__ . '\get_topic_options' );
add_action( 'pre_get_posts', __NAMESPACE__ . '\modify_query' );
add_action( 'wporg_query_filter_in_form', __NAMESPACE__ . '\inject_other_filters' );

/**
* Get the current URL.
*
* @return string The current URL.
*/
function get_current_url() {
global $wp;
return home_url( add_query_arg( array(), $wp->request ) );
}

/**
* Get the list of levels for the course and lesson filters.
*
* @param array $options The options for this filter.
* @return array New list of level options.
*/
function get_level_options( $options ) {
global $wp_query;
// Get top 10 levels ordered by count, not empty, filtered by post_type, then sort them alphabetically.
$object_ids = get_posts(
array(
'post_type' => get_post_type(),
'fields' => 'ids',
'numberposts' => -1,
'status' => 'publish',
)
);
$levels = get_terms(
array(
'taxonomy' => 'level',
'orderby' => 'count',
'order' => 'DESC',
'number' => 10,
'hide_empty' => true,
'object_ids' => $object_ids,
)
);
// If there are no levels, or less than 2, don't show the filter.
if ( empty( $levels ) || count( $levels ) < 2 ) {
return array();
}

usort(
$levels,
function ( $a, $b ) {
return strcmp( strtolower( $a->name ), strtolower( $b->name ) );
}
);
// Move the level with value 'Any' to the top, if it exists.
$any_level = array_filter(
$levels,
function ( $level ) {
return 'Any' === $level->name;
}
);
if ( ! empty( $any_level ) ) {
$target_key = key( $any_level );
$target_element = array( $target_key => $levels[ $target_key ] );

unset( $levels[ $target_key ] );

$levels = $target_element + $levels;
}

$selected = isset( $wp_query->query['wporg_lesson_level'] ) ? (array) $wp_query->query['wporg_lesson_level'] : array();
$count = count( $selected );
$label = sprintf(
/* translators: The dropdown label for filtering, %s is the selected term count. */
_n( 'Level <span>%s</span>', 'Level <span>%s</span>', $count, 'wporg-learn' ),
$count
);

return array(
'label' => $label,
'title' => __( 'Level', 'wporg-learn' ),
'key' => 'wporg_lesson_level',
'action' => get_current_url(),
'options' => array_combine( wp_list_pluck( $levels, 'slug' ), wp_list_pluck( $levels, 'name' ) ),
'selected' => $selected,
);
}

/**
* Get the list of topics for the course and lesson filters.
*
* @param array $options The options for this filter.
* @return array New list of topic options.
*/
function get_topic_options( $options ) {
global $wp_query;
// Get top 20 topics ordered by count, not empty, filtered by post_type, then sort them alphabetically.
$object_ids = get_posts(
array(
'post_type' => get_post_type(),
'fields' => 'ids',
'numberposts' => -1,
'status' => 'publish',
)
);
$topics = get_terms(
array(
'taxonomy' => 'topic',
'orderby' => 'count',
'order' => 'DESC',
'number' => 20,
'hide_empty' => true,
'object_ids' => $object_ids,
)
);
// If there are no topics, or less than 2, don't show the filter.
if ( empty( $topics ) || count( $topics ) < 2 ) {
return array();
}

usort(
$topics,
function ( $a, $b ) {
return strcmp( strtolower( $a->name ), strtolower( $b->name ) );
}
);

$selected = isset( $wp_query->query['wporg_workshop_topic'] ) ? (array) $wp_query->query['wporg_workshop_topic'] : array();
$count = count( $selected );
$label = sprintf(
/* translators: The dropdown label for filtering, %s is the selected term count. */
_n( 'Topic <span>%s</span>', 'Topic <span>%s</span>', $count, 'wporg-learn' ),
$count
);

return array(
'label' => $label,
'title' => __( 'Topic', 'wporg-learn' ),
'key' => 'wporg_workshop_topic',
'action' => get_current_url(),
'options' => array_combine( wp_list_pluck( $topics, 'slug' ), wp_list_pluck( $topics, 'name' ) ),
'selected' => $selected,
);
}


/**
* Get the meta query values by key.
*
* @param WP_Query $query The query.
* @param string $key The meta key.
* @return array The meta query values.
*/
function get_meta_query_values_by_key( $query, $key ) {
if ( isset( $query->query_vars['meta_query'] ) ) {
$meta_query = $query->query_vars['meta_query'];

foreach ( $meta_query as $meta ) {
if ( isset( $meta['key'] ) && $meta['key'] === $key && ! empty( $meta['value'] ) ) {
return $meta['value'];
}
}
}

return array();
}

/**
* Get the list of languages for the course and lesson filters.
*
* @param array $options The options for this filter.
* @return array New list of language options.
*/
function get_language_options( $options ) {
global $wp_query;

$languages = get_available_post_type_locales( 'language', get_post_type(), 'publish' );
// If there are no languages, or the only language is en_US, don't show the filter.
if ( empty( $languages ) || ( 1 === count( $languages ) && isset( $languages['en_US'] ) ) ) {
return array();
}
// Otherwise if there are other languages and en_US is not listed, add it to the top,
// as this is the default value for the meta field.
if ( ! isset( $languages['en_US'] ) ) {
$languages = array_merge( array( 'en_US' => 'English' ), $languages );
}

$selected = get_meta_query_values_by_key( $wp_query, 'language' );
$count = count( $selected );
$label = sprintf(
/* translators: The dropdown label for filtering, %s is the selected term count. */
_n( 'Language <span>%s</span>', 'Language <span>%s</span>', $count, 'wporg-learn' ),
$count
);

return array(
'label' => $label,
'title' => __( 'Language', 'wporg-learn' ),
'key' => 'language',
'action' => get_current_url(),
'options' => $languages,
'selected' => $selected,
);
}

/**
* Modify the query by adding meta query for language if set.
*
* @param WP_Query $query The query object.
*/
function modify_query( $query ) {
// Ensure this code runs only for the main query on archive pages
if ( ! is_admin() && $query->is_main_query() && $query->is_archive() ) {
if ( isset( $_GET['language'] ) && is_array( $_GET['language'] ) ) {
$languages = array_map( 'sanitize_text_field', $_GET['language'] );

$meta_query = array( 'relation' => 'OR' );

$meta_query[] = array(
'key' => 'language',
'value' => $languages,
'compare' => 'IN',
);

// If 'en_US' is included, include posts with no language defined
// as this is the default value for the meta field.
if ( in_array( 'en_US', $languages ) ) {
$meta_query[] = array(
'key' => 'language',
'compare' => 'NOT EXISTS',
);
}

$query->set( 'meta_query', $meta_query );
}
}
}

/**
* Add in the other existing filters as hidden inputs in the filter form.
*
* Enables combining filters by building up the correct URL on submit,
* for example courses using a topic and a level:
* ?wporg_workshop_topic[]=extending-wordpress&wporg_lesson_level[]=beginner`
*
* @param string $key The key for the current filter.
*/
function inject_other_filters( $key ) {
global $wp_query;

$query_vars = array( 'wporg_workshop_topic', 'wporg_lesson_level' );
foreach ( $query_vars as $query_var ) {
if ( ! isset( $wp_query->query[ $query_var ] ) ) {
continue;
}
if ( $key === $query_var ) {
continue;
}
$values = (array) $wp_query->query[ $query_var ];
foreach ( $values as $value ) {
printf( '<input type="hidden" name="%s[]" value="%s" />', esc_attr( $query_var ), esc_attr( $value ) );
}
}

$meta_query_vars = array( 'language' );
foreach ( $meta_query_vars as $meta_query_var ) {
$values = (array) get_meta_query_values_by_key( $wp_query, $meta_query_var );
if ( empty( $values ) ) {
continue;
}
if ( $key === $meta_query_var ) {
continue;
}
foreach ( $values as $value ) {
printf( '<input type="hidden" name="%s[]" value="%s" />', esc_attr( $meta_query_var ), esc_attr( $value ) );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@
</div>
<!-- /wp:group -->

<!-- wp:group {"align":"wide","style":{"spacing":{"margin":{"top":"0","bottom":"var:preset|spacing|50"}}}} -->
<div id="wporg-search" class="wp-block-group alignwide" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--50)">
<!-- wp:group {"align":"wide","layout":{"type":"flex","flexWrap":"wrap","justifyContent":"space-between"},"style":{"spacing":{"margin":{"top":"0","bottom":"var:preset|spacing|50"}}}} -->
<div class="wp-block-group alignwide" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--50)">

<!-- wp:search {"label":"<?php esc_attr_e( 'Search', 'wporg-learn' ); ?>","showLabel":false,"placeholder":"<?php esc_attr_e( 'Search courses', 'wporg-learn' ); ?>","width":290,"widthUnit":"px","buttonText":"<?php esc_attr_e( 'Search', 'wporg-learn' ); ?>","buttonPosition":"button-inside","buttonUseIcon":true,"query":{"post_type":"course"}} /-->

<!-- wp:group {"style":{"spacing":{"blockGap":"0"}},"layout":{"type":"flex","flexWrap":"nowrap"},"className":"wporg-query-filters"} -->
<div class="wp-block-group wporg-query-filters">
<!-- wp:wporg/query-filter {"key":"language"} /-->
<!-- wp:wporg/query-filter {"key":"topic"} /-->
<!-- wp:wporg/query-filter {"key":"level"} /-->
</div>
<!-- /wp:group -->

</div>
<!-- /wp:group -->


<!-- wp:query {"queryId":1,"query":{"perPage":12,"postType":"course","courseFeatured":false,"inherit":true},"namespace":"wporg-learn/course-grid","align":"wide","className":"wporg-learn-course-grid"} -->
<div class="wp-block-query alignwide wporg-learn-course-grid">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,19 @@
</div>
<!-- /wp:group -->

<!-- wp:group {"align":"wide","style":{"spacing":{"margin":{"top":"0","bottom":"var:preset|spacing|50"}}}} -->
<div id="wporg-search" class="wp-block-group alignwide" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--50)">
<!-- wp:group {"align":"wide","layout":{"type":"flex","flexWrap":"wrap","justifyContent":"space-between"},"style":{"spacing":{"margin":{"top":"0","bottom":"var:preset|spacing|50"}}}} -->
<div class="wp-block-group alignwide" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--50)">

<!-- wp:search {"label":"<?php esc_attr_e( 'Search', 'wporg-learn' ); ?>","showLabel":false,"placeholder":"<?php esc_attr_e( 'Search lessons', 'wporg-learn' ); ?>","width":290,"widthUnit":"px","buttonText":"<?php esc_attr_e( 'Search', 'wporg-learn' ); ?>","buttonPosition":"button-inside","buttonUseIcon":true,"query":{"post_type":"lesson"}} /-->

<!-- wp:group {"style":{"spacing":{"blockGap":"0"}},"layout":{"type":"flex","flexWrap":"nowrap"},"className":"wporg-query-filters"} -->
<div class="wp-block-group wporg-query-filters">
<!-- wp:wporg/query-filter {"key":"language"} /-->
<!-- wp:wporg/query-filter {"key":"topic"} /-->
<!-- wp:wporg/query-filter {"key":"level"} /-->
</div>
<!-- /wp:group -->

</div>
<!-- /wp:group -->

Expand Down

0 comments on commit 2fd397a

Please sign in to comment.