diff --git a/blockroll.php b/blockroll.php index 09996ca..1f963b8 100644 --- a/blockroll.php +++ b/blockroll.php @@ -3,7 +3,7 @@ * Plugin Name: Blogroll & Podroll Block * Plugin URI: https://github.com/pfefferle/wordpress-blockroll * Description: Share the blogs and podcasts you follow, and let other people subscribe to your list. - * Version: 2.0.0 + * Version: 2.1.0 * Requires at least: 6.8 * Requires PHP: 7.4 * Author: Matthias Pfefferle diff --git a/build/blogroll/render.php b/build/blogroll/render.php index 88c2a65..16b9750 100644 --- a/build/blogroll/render.php +++ b/build/blogroll/render.php @@ -12,6 +12,7 @@ */ use Blockroll\Links; +use Blockroll\Opml; use Blockroll\Sources; use Blockroll\Xfn; @@ -22,12 +23,18 @@ $blockroll_sortable = $attributes['showSort']; // The HTML anchor is the address of this one list. The sorting and paging -// links carry it, so the reload lands on the list that was clicked, not -// at the top of the page. +// links carry it twice: as the fragment, so the reload lands on the list +// that was clicked, and as the group, the same query var the subscription +// files use, so that sorting and paging mean this list alone. A query +// that names no list means every list, the way the links of the versions +// before this one did. $blockroll_anchor = trim( (string) ( $attributes['anchor'] ?? '' ) ); $blockroll_fragment = '' !== $blockroll_anchor ? '#' . $blockroll_anchor : ''; +$blockroll_named = trim( (string) get_query_var( Opml::GROUP ) ); +$blockroll_meant = '' === $blockroll_named || $blockroll_named === $blockroll_anchor; +$blockroll_group = '' !== $blockroll_anchor ? $blockroll_anchor : false; -$blockroll_sort = $blockroll_sortable ? get_query_var( 'blockroll-sort' ) : ''; +$blockroll_sort = $blockroll_sortable && $blockroll_meant ? get_query_var( 'blockroll-sort' ) : ''; if ( ! in_array( $blockroll_sort, array( 'name', 'added', 'manual' ), true ) ) { $blockroll_sort = $attributes['sortBy']; } @@ -37,7 +44,7 @@ $blockroll_per = (int) $attributes['perPage']; $blockroll_total = count( $blockroll_links ); $blockroll_pages = $blockroll_per > 0 ? max( 1, (int) ceil( $blockroll_total / $blockroll_per ) ) : 1; -$blockroll_page = min( max( 1, (int) get_query_var( 'blockroll-page', 1 ) ), $blockroll_pages ); +$blockroll_page = $blockroll_meant ? min( max( 1, (int) get_query_var( 'blockroll-page', 1 ) ), $blockroll_pages ) : 1; $blockroll_dated = (bool) array_filter( wp_list_pluck( $blockroll_links, 'added' ) ); if ( ! $blockroll_links ) { @@ -48,6 +55,21 @@ $blockroll_links = array_slice( $blockroll_links, ( $blockroll_page - 1 ) * $blockroll_per, $blockroll_per ); } +/** + * The address of another page of this list. + * + * @param int $page Page number. + * @return string URL. + */ +$blockroll_page_url = function ( $page ) use ( $blockroll_group, $blockroll_fragment ) { + return add_query_arg( + array( + 'blockroll-page' => $page, + Opml::GROUP => $blockroll_group, + ) + ) . $blockroll_fragment; +}; + $blockroll_sorts = array( 'name' => __( 'By name', 'blockroll' ), ); @@ -70,6 +92,7 @@ array( 'blockroll-sort' => $blockroll_key, 'blockroll-page' => false, + Opml::GROUP => $blockroll_group, ) ) . $blockroll_fragment; ?> @@ -123,7 +146,7 @@ 1 ) : ?> diff --git a/readme.md b/readme.md index 8d58cf7..f1f9591 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ - Tags: blogroll, podroll, opml, links, feeds - Requires at least: 6.8 - Tested up to: 7.1 -- Stable tag: 2.0.0 +- Stable tag: 2.1.0 - Requires PHP: 7.4 - License: GPL-2.0-or-later - License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -45,8 +45,9 @@ you have met. It shows up as a small note under the entry, and it is readable fo that map who knows whom. **Sorting and paging for visitors.** Long lists get pages, and visitors can sort by name -or by what you added last. There is no JavaScript in the list at all, every click is a -normal page load, and you can switch the sorting off per block. +or by what you added last. On a page with several lists, sorting or paging one leaves the +others as they are. There is no JavaScript in the list at all, every click is a normal +page load, and you can switch the sorting off per block. ## Frequently Asked Questions @@ -132,6 +133,10 @@ routes are described in the Project and support maintained on github at [pfefferle/wordpress-blockroll](https://github.com/pfefferle/wordpress-blockroll). +### 2.1.0 + +* Sorting and paging mean one list now. On a page with several blogrolls, sorting one no longer sorts the others, and paging one no longer pages them. The links say which list they mean, with the name every list has anyway: `?blockroll-sort=name&group=podcasts`. Links from before this version still sort and page every list on the page. Reported in #2. + ### 2.0.0 * Every link is a block of its own now. You can move it, duplicate it, copy it to another page, and edit it where it shows: the name and the description in the list, the address behind the name, the feed and the relationships in the line below, the image by clicking it. diff --git a/src/blogroll/render.php b/src/blogroll/render.php index 88c2a65..16b9750 100644 --- a/src/blogroll/render.php +++ b/src/blogroll/render.php @@ -12,6 +12,7 @@ */ use Blockroll\Links; +use Blockroll\Opml; use Blockroll\Sources; use Blockroll\Xfn; @@ -22,12 +23,18 @@ $blockroll_sortable = $attributes['showSort']; // The HTML anchor is the address of this one list. The sorting and paging -// links carry it, so the reload lands on the list that was clicked, not -// at the top of the page. +// links carry it twice: as the fragment, so the reload lands on the list +// that was clicked, and as the group, the same query var the subscription +// files use, so that sorting and paging mean this list alone. A query +// that names no list means every list, the way the links of the versions +// before this one did. $blockroll_anchor = trim( (string) ( $attributes['anchor'] ?? '' ) ); $blockroll_fragment = '' !== $blockroll_anchor ? '#' . $blockroll_anchor : ''; +$blockroll_named = trim( (string) get_query_var( Opml::GROUP ) ); +$blockroll_meant = '' === $blockroll_named || $blockroll_named === $blockroll_anchor; +$blockroll_group = '' !== $blockroll_anchor ? $blockroll_anchor : false; -$blockroll_sort = $blockroll_sortable ? get_query_var( 'blockroll-sort' ) : ''; +$blockroll_sort = $blockroll_sortable && $blockroll_meant ? get_query_var( 'blockroll-sort' ) : ''; if ( ! in_array( $blockroll_sort, array( 'name', 'added', 'manual' ), true ) ) { $blockroll_sort = $attributes['sortBy']; } @@ -37,7 +44,7 @@ $blockroll_per = (int) $attributes['perPage']; $blockroll_total = count( $blockroll_links ); $blockroll_pages = $blockroll_per > 0 ? max( 1, (int) ceil( $blockroll_total / $blockroll_per ) ) : 1; -$blockroll_page = min( max( 1, (int) get_query_var( 'blockroll-page', 1 ) ), $blockroll_pages ); +$blockroll_page = $blockroll_meant ? min( max( 1, (int) get_query_var( 'blockroll-page', 1 ) ), $blockroll_pages ) : 1; $blockroll_dated = (bool) array_filter( wp_list_pluck( $blockroll_links, 'added' ) ); if ( ! $blockroll_links ) { @@ -48,6 +55,21 @@ $blockroll_links = array_slice( $blockroll_links, ( $blockroll_page - 1 ) * $blockroll_per, $blockroll_per ); } +/** + * The address of another page of this list. + * + * @param int $page Page number. + * @return string URL. + */ +$blockroll_page_url = function ( $page ) use ( $blockroll_group, $blockroll_fragment ) { + return add_query_arg( + array( + 'blockroll-page' => $page, + Opml::GROUP => $blockroll_group, + ) + ) . $blockroll_fragment; +}; + $blockroll_sorts = array( 'name' => __( 'By name', 'blockroll' ), ); @@ -70,6 +92,7 @@ array( 'blockroll-sort' => $blockroll_key, 'blockroll-page' => false, + Opml::GROUP => $blockroll_group, ) ) . $blockroll_fragment; ?> @@ -123,7 +146,7 @@ 1 ) : ?> diff --git a/tests/test-render.php b/tests/test-render.php index 4faf571..b76c05a 100644 --- a/tests/test-render.php +++ b/tests/test-render.php @@ -497,6 +497,108 @@ public function test_wrapper_carries_style_supports() { $this->assertStringContainsString( 'line-height:1.8', $html ); } + /** + * Two lists on a page share the query, so the sorting and the paging + * say which list they mean: the anchor, in the same query var the + * subscription files use. + */ + public function test_sort_applies_to_the_named_list_only() { + $attrs = array( + 'anchor' => 'podcasts', + 'sortBy' => 'manual', + 'links' => array( + array( + 'url' => 'https://b.example/', + 'name' => 'Beta', + ), + array( + 'url' => 'https://a.example/', + 'name' => 'alpha', + ), + ), + ); + + set_query_var( 'blockroll-sort', 'name' ); + + set_query_var( 'group', 'podcasts' ); + $html = $this->render_block_html( $attrs ); + $this->assertLessThan( strpos( $html, 'Beta' ), strpos( $html, 'alpha' ), 'the named list is sorted' ); + + set_query_var( 'group', 'blogs' ); + $html = $this->render_block_html( $attrs ); + $this->assertLessThan( strpos( $html, 'alpha' ), strpos( $html, 'Beta' ), 'another list keeps its own order' ); + + // Links from before the lists had names still sort every list. + set_query_var( 'group', null ); + $html = $this->render_block_html( $attrs ); + $this->assertLessThan( strpos( $html, 'Beta' ), strpos( $html, 'alpha' ) ); + + set_query_var( 'blockroll-sort', null ); + } + + public function test_sort_links_name_their_list() { + $html = $this->render_block_html( + array( + 'anchor' => 'podcasts', + 'links' => self::TWO_DATED_LINKS, + ) + ); + + $this->assertStringContainsString( 'group=podcasts', $html ); + $this->assertStringContainsString( '#podcasts', $html ); + } + + public function test_paging_applies_to_the_named_list_only() { + $attrs = array( + 'anchor' => 'podcasts', + 'perPage' => 1, + 'links' => array( + array( + 'url' => 'https://a.example/', + 'name' => 'A', + ), + array( + 'url' => 'https://b.example/', + 'name' => 'B', + ), + ), + ); + + set_query_var( 'blockroll-page', 2 ); + + set_query_var( 'group', 'podcasts' ); + $html = $this->render_block_html( $attrs ); + $this->assertStringContainsString( 'b.example', $html ); + + set_query_var( 'group', 'blogs' ); + $html = $this->render_block_html( $attrs ); + $this->assertStringContainsString( 'a.example', $html, 'another list stays on its first page' ); + + set_query_var( 'blockroll-page', null ); + set_query_var( 'group', null ); + } + + public function test_paging_links_name_their_list() { + $html = $this->render_block_html( + array( + 'anchor' => 'podcasts', + 'perPage' => 1, + 'links' => array( + array( + 'url' => 'https://a.example/', + 'name' => 'A', + ), + array( + 'url' => 'https://b.example/', + 'name' => 'B', + ), + ), + ) + ); + + $this->assertStringContainsString( 'group=podcasts', $html ); + } + /** * A list that is not in the file of its page still offers its own, so * the download link points at the file of the list.