Skip to content

Commit 0ae3eb5

Browse files
authored
Support for multiple custom fields in url (#23)
* Tests added * Support multiple values. * Flush rules after plugin update
1 parent d298dbe commit 0ae3eb5

File tree

7 files changed

+226
-34
lines changed

7 files changed

+226
-34
lines changed

bin/bump-version.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ handle_plugin_version() {
2424
echo "Starting bumping plugin version to $version_to_bump"
2525

2626
sed -i -E "s/Version: (.+)/Version: $version_to_bump/" "$file_plugin_main"
27+
sed -i -E "s/'WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION', '(.+)'/'WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION', '$version_to_bump'/" "$file_plugin_main"
2728
echo "Version bumped in $file_plugin_main"
2829

2930
sed -i -E "s/Stable tag: (.+)/Stable tag: $version_to_bump/" "$file_readme_repo"

includes/class-customfieldspermalink.php

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
*/
1111
class CustomFieldsPermalink {
1212

13-
const PARAM_CUSTOMFIELD_KEY = 'custom_field_key';
14-
const PARAM_CUSTOMFIELD_VALUE = 'custom_field_value';
13+
const PARAM_CUSTOMFIELD_PARAMES = 'custom_field_params';
1514

1615
/**
1716
* Filters the permalink structure for a post before token replacement occurs..
@@ -95,7 +94,7 @@ public static function link_rewrite_fields_extract( $post, $field_name ) {
9594
* @return mixed
9695
*/
9796
public static function register_extra_query_vars( $public_query_vars ) {
98-
array_push( $public_query_vars, self::PARAM_CUSTOMFIELD_KEY, self::PARAM_CUSTOMFIELD_VALUE );
97+
array_push( $public_query_vars, self::PARAM_CUSTOMFIELD_PARAMES );
9998

10099
return $public_query_vars;
101100
}
@@ -140,34 +139,36 @@ public static function pre_handle_404( $preempt, $wp_query ) {
140139
$post = $wp_query->post;
141140

142141
// Analyse only if custom field used in query.
143-
if ( ! array_key_exists( self::PARAM_CUSTOMFIELD_KEY, $wp_query->query_vars ) ) {
142+
if ( ! array_key_exists( self::PARAM_CUSTOMFIELD_PARAMES, $wp_query->query_vars )
143+
|| ! is_array( $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMES ] ) ) {
144144
return false;
145145
}
146146

147+
$query_meta_params = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMES ];
148+
147149
$raise_404 = false;
148150

149151
$post_meta = self::get_post_meta( $post );
150152

151-
$query_meta_key = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_KEY ];
152-
153-
if ( ! array_key_exists( $query_meta_key, $post_meta ) ) {
154-
$raise_404 = true;
155-
} else {
156-
$query_meta_value = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_VALUE ];
157-
158-
// Look for at least one value match.
159-
$value_matched = false;
160-
foreach ( $post_meta[ $query_meta_key ] as $post_meta_value ) {
161-
$post_meta_value_sanitized = sanitize_title( $post_meta_value );
162-
163-
if ( $query_meta_value == $post_meta_value_sanitized ) {
164-
$value_matched = true;
165-
break;
153+
foreach ( $query_meta_params as $query_meta_key => $query_meta_value ) {
154+
if ( ! array_key_exists( $query_meta_key, $post_meta ) ) {
155+
$raise_404 = true;
156+
break;
157+
} else {
158+
// Look for at least one value match.
159+
$value_matched = false;
160+
foreach ( $post_meta[ $query_meta_key ] as $post_meta_value ) {
161+
$post_meta_value_sanitized = sanitize_title( $post_meta_value );
162+
163+
if ( $query_meta_value == $post_meta_value_sanitized ) {
164+
$value_matched = true;
165+
break;
166+
}
166167
}
167-
}
168168

169-
if ( ! $value_matched ) {
170-
$raise_404 = true;
169+
if ( ! $value_matched ) {
170+
$raise_404 = true;
171+
}
171172
}
172173
}
173174

@@ -194,14 +195,9 @@ public static function pre_handle_404( $preempt, $wp_query ) {
194195
* @return array
195196
*/
196197
public static function rewrite_rules_array_filter( $rules ) {
197-
$keys = array_keys( $rules );
198-
$tmp = $rules;
199-
$rules = array();
200-
201-
$j = sizeof( $keys );
202-
for ( $i = 0; $i < $j; ++ $i ) {
203-
$key = $keys[ $i ];
198+
$new_rules = array();
204199

200+
foreach ( $rules as $key => $rule ) {
205201
if ( preg_match( '/%field_([^%]*?)%/', $key ) ) {
206202
$key_new = preg_replace(
207203
'/%field_([^%]*?)%/',
@@ -210,19 +206,19 @@ public static function rewrite_rules_array_filter( $rules ) {
210206
// Detect them automatically and add next $matches indices.
211207
$key
212208
);
213-
$rules[ $key_new ] = preg_replace(
209+
$new_rules[ $key_new ] = preg_replace(
214210
'/%field_([^%]*?)%/',
215-
sprintf( '%s=$1&%s=', self::PARAM_CUSTOMFIELD_KEY, self::PARAM_CUSTOMFIELD_VALUE ),
211+
sprintf( '%s[$1]=', self::PARAM_CUSTOMFIELD_PARAMES ),
216212
// Here on the end will be pasted $matches[$i] from $keyNew,
217213
// so we can grab it it the future in self::PARAM_CUSTOMFIELD_VALUE parameter.
218-
$tmp[ $key ]
214+
$rule
219215
);
220216
} else {
221-
$rules[ $key ] = $tmp[ $key ];
217+
$new_rules[ $key ] = $rule;
222218
}
223219
}
224220

225-
return $rules;
221+
return $new_rules;
226222
}
227223

228224
/**
@@ -256,4 +252,30 @@ private static function get_post_meta( $post ) {
256252

257253
return $filtered_post_meta;
258254
}
255+
256+
/**
257+
* This hook is called once any activated plugins have been loaded.
258+
*
259+
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/plugins_loaded
260+
*/
261+
public static function on_init() {
262+
$version_option_name = '_wordpress_custom_fields_permalink_plugin_version';
263+
$version_from = get_option( $version_option_name, null );
264+
$version_to = WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION;
265+
266+
if ( $version_from != $version_to ) {
267+
self::update_plugin( $version_from, $version_to );
268+
update_option( $version_option_name, $version_to, true );
269+
}
270+
}
271+
272+
/**
273+
* Upgrades the plugin.
274+
*
275+
* @param string $version_from Currently running version.
276+
* @param string $version_to Version upgrade to.
277+
*/
278+
public static function update_plugin( $version_from, $version_to ) {
279+
flush_rewrite_rules();
280+
}
259281
}

includes/main.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
add_filter( 'query_vars', array( 'CustomFieldsPermalink', 'register_extra_query_vars' ), 10, 1 );
1515
add_filter( 'request', array( 'CustomFieldsPermalink', 'process_request' ), 10, 1 );
1616
add_filter( 'pre_handle_404', array( 'CustomFieldsPermalink', 'pre_handle_404' ), 10, 2 );
17+
add_action( 'init', array( 'CustomFieldsPermalink', 'on_init' ) );

test/bootstrap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ function _manually_load_plugin() {
3535
require 'class-customposttypesteps.php';
3636
require 'class-permalinkasserter.php';
3737
require 'class-navigationasserter.php';
38+
39+
define( 'WP_RUN_CORE_TESTS', true );
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
/**
3+
* Tests case.
4+
*
5+
* @package WordPress_Custom_Fields_Permalink
6+
*/
7+
8+
/**
9+
* Class PostWithMetaKeyMultiple
10+
*/
11+
class PostWithMetaKeyMultiple extends BaseTestCase {
12+
13+
/**
14+
* Test case.
15+
*/
16+
function test_generates_permalink_to_post_using_meta_key() {
17+
// given.
18+
$this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
19+
20+
$post_params = array(
21+
'post_title' => 'Some post title',
22+
'meta_input' => array(
23+
'some_meta_key' => 'Some meta value',
24+
'some_meta_key2' => 'Some second meta value',
25+
'some_other_meta_key' => 'Some other meta value',
26+
),
27+
);
28+
$created_post_id = $this->factory()->post->create( $post_params );
29+
30+
// when & then.
31+
$this->permalink_asserter->has_permalink( $created_post_id, '/some-meta-value/some-second-meta-value/some-post-title/' );
32+
}
33+
34+
/**
35+
* Test case.
36+
*/
37+
function test_go_to_post_using_meta_key_permalink_structure() {
38+
// given.
39+
$this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
40+
41+
$post_params = array(
42+
'post_title' => 'Some post title',
43+
'meta_input' => array(
44+
'some_meta_key' => 'Some meta value',
45+
'some_meta_key2' => 'Some second meta value',
46+
'some_other_meta_key' => 'Some other meta value',
47+
),
48+
);
49+
$created_post_id = $this->factory()->post->create( $post_params );
50+
51+
// when.
52+
// Little hacky with "1" at the end, but wrong route is matched during the tests.
53+
$this->go_to( '/some-meta-value/some-second-meta-value/some-post-title/1' );
54+
55+
// then.
56+
$this->navigation_asserter->then_displayed_post( $created_post_id );
57+
}
58+
59+
/**
60+
* Test case.
61+
*/
62+
function test_not_go_to_the_post_when_invalid_first_value_of_meta_key_part_in_url() {
63+
// given.
64+
$this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
65+
66+
$post_params = array(
67+
'post_title' => 'Some post title',
68+
'meta_input' => array(
69+
'some_meta_key' => 'Some meta value',
70+
'some_meta_key2' => 'Some second meta value',
71+
),
72+
);
73+
$created_post_id = $this->factory()->post->create( $post_params );
74+
75+
// when.
76+
$this->go_to( '/some-different-meta-value/some-second-meta-value/some-post-title/1' );
77+
78+
// then.
79+
$this->navigation_asserter->then_not_displayed_post( $created_post_id );
80+
}
81+
82+
/**
83+
* Test case.
84+
*/
85+
function test_not_go_to_the_post_when_invalid_second_value_of_meta_key_part_in_url() {
86+
// given.
87+
$this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%field_some_meta_key2%/%postname%/' );
88+
89+
$post_params = array(
90+
'post_title' => 'Some post title',
91+
'meta_input' => array(
92+
'some_meta_key' => 'Some meta value',
93+
'some_meta_key2' => 'Some second meta value',
94+
),
95+
);
96+
$created_post_id = $this->factory()->post->create( $post_params );
97+
98+
// when.
99+
$this->go_to( '/some-meta-value/some-different-meta-value/some-post-title/1' );
100+
101+
// then.
102+
$this->navigation_asserter->then_not_displayed_post( $created_post_id );
103+
}
104+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Tests case.
4+
*
5+
* @package WordPress_Custom_Fields_Permalink
6+
*/
7+
8+
/**
9+
* Class PluginUpgrade
10+
*/
11+
class PluginUpgrade extends BaseTestCase {
12+
13+
/**
14+
* Test case.
15+
*/
16+
function test_flushes_rules_after_plugin_upgrade() {
17+
// given.
18+
global $wp_rewrite;
19+
20+
$this->given_stored_plugin_version( null );
21+
$this->given_rewrite_rules_are_corrupted();
22+
23+
// when.
24+
CustomFieldsPermalink::on_init();
25+
26+
// then.
27+
$rules = $wp_rewrite->wp_rewrite_rules();
28+
29+
$this->assertNotEquals( 'CORRUPTED', $rules );
30+
$this->assertPluginVersionUpdated();
31+
}
32+
33+
/**
34+
* Update plugin version.
35+
*
36+
* @param string $version The plugin version.
37+
*/
38+
private function given_stored_plugin_version( $version ) {
39+
update_option( '_wordpress_custom_fields_permalink_plugin_version', $version );
40+
}
41+
42+
/**
43+
* Makes rewrite rules corrupted.
44+
*/
45+
private function given_rewrite_rules_are_corrupted() {
46+
global $wp_rewrite;
47+
48+
update_option( 'rewrite_rules', 'CORRUPTED' );
49+
$rules = $wp_rewrite->wp_rewrite_rules();
50+
51+
// Sanity check.
52+
$this->assertEquals( 'CORRUPTED', $rules );
53+
}
54+
55+
/**
56+
* Assert if plugin version is up to date.
57+
*/
58+
private function assertPluginVersionUpdated() {
59+
$this->assertEquals( WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION, get_option( '_wordpress_custom_fields_permalink_plugin_version' ) );
60+
}
61+
}

wordpress-custom-fields-permalink-plugin.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
*/
1515

1616
// Require main entry point.
17+
define( 'WORDPRESS_CUSTOM_FIELDS_PERMALINK_PLUGIN_VERSION', '1.2.0' );
1718
require 'includes/main.php';

0 commit comments

Comments
 (0)