Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions phpunit-bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
require_once WP_PLUGIN_DIR . '/wordcamp-payments-network/tests/bootstrap.php';
require_once SUT_WPMU_PLUGIN_DIR . '/tests/bootstrap.php';
require_once WP_PLUGIN_DIR . '/wordcamp-coming-soon-page/tests/bootstrap.php';
require_once SUT_WP_CONTENT_DIR . '/themes/wporg-events-2023/tests/bootstrap.php';

/*
* This has to be the last plugin bootstrapper, because it includes the Core test bootstrapper, which would
Expand Down
6 changes: 6 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
./public_html/wp-content/plugins/wordcamp-coming-soon-page/tests/
</directory>
</testsuite>

<testsuite name="Events Theme">
<directory prefix="test-" suffix=".php">
./public_html/wp-content/themes/wporg-events-2023/tests/
</directory>
</testsuite>
</testsuites>

<coverage cacheDirectory=".phpunit/coverage-cache">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
add_action( 'wporg_query_filter_in_form', __NAMESPACE__ . '\inject_other_filters' );
add_filter( 'document_title_parts', __NAMESPACE__ . '\add_filters_to_page_title' );
add_filter( 'wporg_query_total_label', __NAMESPACE__ . '\update_query_total_label', 10, 3 );
add_filter( 'render_block_core/search', __NAMESPACE__ . '\inject_filters_into_search_form' );
add_filter( 'wporg_query_filter_options_format_type', __NAMESPACE__ . '\get_format_type_options' );
add_filter( 'wporg_query_filter_options_event_type', __NAMESPACE__ . '\get_event_type_options' );
add_filter( 'wporg_query_filter_options_month', __NAMESPACE__ . '\get_month_options' );
Expand Down Expand Up @@ -329,6 +330,52 @@ function inject_other_filters( string $key ): void {
}
}

/**
* Inject active filter values as hidden inputs into the search form.
*
* The core/search block submits only `?s=term` to the home URL, losing any
* active filters and redirecting away from the events page. This modifies
* the form to submit to the events page and includes active filters as
* hidden inputs.
*
* @param string $block_content The block HTML.
*
* @return string Modified block HTML with hidden filter inputs.
*/
function inject_filters_into_search_form( string $block_content ): string {
$query_vars = array( 'event_type', 'format_type', 'month', 'country' );
$hidden_inputs = '';

foreach ( $query_vars as $query_var ) {
$values = (array) get_query_var( $query_var, array() );

foreach ( $values as $value ) {
if ( '' !== $value ) {
$hidden_inputs .= sprintf(
'<input type="hidden" name="%s[]" value="%s" />',
esc_attr( $query_var ),
esc_attr( $value )
);
}
}
}

// Update the form action to stay on the events page rather than going to
// the default WordPress search results page.
$action_url = build_form_action_url();
$block_content = preg_replace(
'/action="[^"]*"/',
'action="' . esc_url( $action_url ) . '"',
$block_content
);
Comment on lines +363 to +370

if ( $hidden_inputs ) {
$block_content = str_replace( '</form>', $hidden_inputs . '</form>', $block_content );
}

return $block_content;
}

/**
* Append facets to the page title.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace WordPressdotorg\Events_2023\Tests;

if ( 'cli' !== php_sapi_name() ) {
return;
}

/**
* Load the theme files needed for tests.
*/
function manually_load_theme() {
require_once dirname( __DIR__ ) . '/inc/events-query.php';
}

tests_add_filter( 'after_setup_theme', __NAMESPACE__ . '\manually_load_theme' );
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<?php

namespace WordPressdotorg\Events_2023\Tests;

use WP_UnitTestCase;

defined( 'WPINC' ) || die();

/**
* @group wporg-events-2023
*
* @coversDefaultClass \WordPressdotorg\Events_2023
*/
class Test_Events_Query extends WP_UnitTestCase {

/**
* Sample search form HTML to use in tests.
*
* @var string
*/
private $sample_form = '<form role="search" method="get" action="http://example.org/" class="wp-block-search__button-outside"><label class="wp-block-search__label" for="wp-block-search__input-1">Search</label><div class="wp-block-search__inside-wrapper"><input class="wp-block-search__input" id="wp-block-search__input-1" placeholder="" value="" name="s" /><button aria-label="Search" class="wp-block-search__button" type="submit">Search</button></div></form>';

/**
* Clean up query vars after each test.
*/
public function tear_down(): void {
global $wp_query;

set_query_var( 'event_type', '' );
set_query_var( 'format_type', '' );
set_query_var( 'month', '' );
set_query_var( 'country', '' );

parent::tear_down();
}

/**
* Test that hidden inputs are injected when active filters exist.
*
* @covers ::inject_filters_into_search_form
*/
public function test_injects_hidden_inputs_for_active_filters(): void {
set_query_var( 'event_type', array( 'meetup' ) );
set_query_var( 'country', array( 'US' ) );

$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

$this->assertStringContainsString(
'<input type="hidden" name="event_type[]" value="meetup" />',
$result
);
$this->assertStringContainsString(
'<input type="hidden" name="country[]" value="US" />',
$result
);
}

/**
* Test that multiple values for a single filter produce multiple hidden inputs.
*
* @covers ::inject_filters_into_search_form
*/
Comment on lines +9 to +62
public function test_injects_multiple_values_for_same_filter(): void {
set_query_var( 'event_type', array( 'meetup', 'wordcamp' ) );

$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

$this->assertStringContainsString(
'<input type="hidden" name="event_type[]" value="meetup" />',
$result
);
$this->assertStringContainsString(
'<input type="hidden" name="event_type[]" value="wordcamp" />',
$result
);
}

/**
* Test that hidden inputs are placed before the closing form tag.
*
* @covers ::inject_filters_into_search_form
*/
public function test_hidden_inputs_placed_before_closing_form_tag(): void {
set_query_var( 'event_type', array( 'meetup' ) );

$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

$this->assertStringContainsString(
'value="meetup" /></form>',
$result
);
}

/**
* Test that form HTML has no hidden inputs when no filters are active.
*
* @covers ::inject_filters_into_search_form
*/
public function test_no_hidden_inputs_when_no_filters_active(): void {
$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

$this->assertStringNotContainsString( '<input type="hidden"', $result );
}

/**
* Test that the form action URL is updated.
*
* @covers ::inject_filters_into_search_form
*/
public function test_form_action_url_is_updated(): void {
$post_id = self::factory()->post->create( array(
'post_title' => 'Upcoming Events',
'post_status' => 'publish',
) );

$this->go_to( get_permalink( $post_id ) );

$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

// The action should no longer be the original example.org URL.
$this->assertStringNotContainsString( 'action="http://example.org/"', $result );
// It should contain an action attribute with a URL pointing to the post.
$this->assertMatchesRegularExpression( '/action="https?:\/\/[^"]+?"/', $result );
Comment on lines +120 to +123
}

/**
* Test that empty filter values are not injected.
*
* @covers ::inject_filters_into_search_form
*/
public function test_empty_filter_values_are_not_injected(): void {
set_query_var( 'event_type', array( '' ) );
set_query_var( 'month', array( '' ) );

$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

$this->assertStringNotContainsString( '<input type="hidden"', $result );
}

/**
* Test that filter values are properly escaped in HTML output.
*
* @covers ::inject_filters_into_search_form
*/
public function test_filter_values_are_escaped(): void {
set_query_var( 'event_type', array( '<script>alert(1)</script>' ) );

$result = \WordPressdotorg\Events_2023\inject_filters_into_search_form( $this->sample_form );

$this->assertStringNotContainsString( '<script>', $result );
$this->assertStringContainsString( '&lt;script&gt;', $result );
}
}
Loading