Skip to content

Commit e47f6a4

Browse files
committed
Merge branch 'master' of github.com:athlan/wordpress-custom-fields-permalink-plugin
2 parents 72b3696 + ae90d99 commit e47f6a4

File tree

4 files changed

+142
-26
lines changed

4 files changed

+142
-26
lines changed

includes/class-customfieldspermalink.php

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@ class CustomFieldsPermalink {
1313
const PARAM_CUSTOMFIELD_KEY = 'custom_field_key';
1414
const PARAM_CUSTOMFIELD_VALUE = 'custom_field_value';
1515

16-
/**
17-
* Do check against meta value or not.
18-
*
19-
* @var bool
20-
*/
21-
private static $check_custom_field_value = false;
22-
2316
/**
2417
* Filters the permalink structure for a post before token replacement occurs..
2518
* The pre_post_link filter implementation.
@@ -78,7 +71,7 @@ private static function link_rewrite_fields( $permalink, $post ) {
7871
* @return string
7972
*/
8073
public static function link_rewrite_fields_extract( $post, $field_name ) {
81-
$post_meta = get_post_meta( $post->ID );
74+
$post_meta = self::get_post_meta( $post );
8275

8376
if ( ! isset( $post_meta[ $field_name ] ) ) {
8477
return '';
@@ -120,24 +113,74 @@ public static function register_extra_query_vars( $public_query_vars ) {
120113
public static function process_request( $query_vars ) {
121114
// Additional parameters added to WordPress.
122115
// Main Loop query.
123-
if ( array_key_exists( self::PARAM_CUSTOMFIELD_KEY, $query_vars ) ) {
124-
$query_vars['meta_key'] = $query_vars[ self::PARAM_CUSTOMFIELD_KEY ];
116+
return $query_vars;
117+
}
118+
119+
/**
120+
* Filters whether to short-circuit default header status handling.
121+
*
122+
* Raises 404 if post has been rewrited, but:
123+
* 1. Custom field key does not exists or
124+
* 2. Custom field value does not matches.
125+
*
126+
* @param bool $preempt Whether to short-circuit default header status handling. Default false.
127+
* @param WP_Query $wp_query WordPress Query object.
128+
*
129+
* @return bool Returning a non-false value from the filter will short-circuit the handling
130+
* and return early.
131+
*
132+
* @link https://developer.wordpress.org/reference/hooks/pre_handle_404/
133+
*/
134+
public static function pre_handle_404( $preempt, $wp_query ) {
135+
// Analyse only if there is post parsed.
136+
if ( ! is_single() ) {
137+
return false;
138+
}
139+
140+
$post = $wp_query->post;
141+
142+
// Analyse only if custom field used in query.
143+
if ( ! array_key_exists( self::PARAM_CUSTOMFIELD_KEY, $wp_query->query_vars ) ) {
144+
return false;
145+
}
146+
147+
$raise_404 = false;
148+
149+
$post_meta = self::get_post_meta( $post );
125150

126-
// Remove temporary injected parameter.
127-
unset( $query_vars[ self::PARAM_CUSTOMFIELD_KEY ] );
151+
$query_meta_key = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_KEY ];
128152

129-
// Do not check field's value for this moment.
130-
if ( true === self::$check_custom_field_value ) {
131-
if ( array_key_exists( self::PARAM_CUSTOMFIELD_VALUE, $query_vars ) ) {
132-
$query_vars['meta_value'] = $query_vars[ self::PARAM_CUSTOMFIELD_VALUE ];
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 ];
133157

134-
// Remove temporary injected parameter.
135-
unset( $query_vars[ self::PARAM_CUSTOMFIELD_VALUE ] );
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;
136166
}
137167
}
168+
169+
if ( ! $value_matched ) {
170+
$raise_404 = true;
171+
}
138172
}
139173

140-
return $query_vars;
174+
if ( $raise_404 ) {
175+
$wp_query->set_404();
176+
status_header( 404 );
177+
nocache_headers();
178+
179+
// 404 already raised, break the circuit.
180+
return true;
181+
}
182+
183+
return false;
141184
}
142185

143186
/**
@@ -181,4 +224,36 @@ public static function rewrite_rules_array_filter( $rules ) {
181224

182225
return $rules;
183226
}
227+
228+
/**
229+
* Get post meta applying <code>wpcfp_get_post_metadata</code> filter.
230+
*
231+
* @param WP_Post $post The post.
232+
*
233+
* @return array
234+
*/
235+
private static function get_post_meta( $post ) {
236+
$post_meta = get_post_meta( $post->ID );
237+
238+
/**
239+
* Filters of retrieved metadata of a post to link rewrite.
240+
*
241+
* @since 1.2.0
242+
*
243+
* @param array $post_meta The metadata returned from get_post_meta.
244+
* @param WP_Post $post The post object.
245+
*/
246+
$filtered_post_meta = apply_filters( 'wpcfp_get_post_metadata', $post_meta, $post );
247+
248+
// Do some fixes after user generated values.
249+
// If it's single value, wrap this in array, as WordPress internally does.
250+
// @see get_post_meta() with $single = false.
251+
foreach ( $filtered_post_meta as $key => &$value ) {
252+
if ( ! is_array( $value ) ) {
253+
$value = array( $value );
254+
}
255+
}
256+
257+
return $filtered_post_meta;
258+
}
184259
}

readme.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ We would be very grateful in any contribution. If you have a idea for the featur
5050
When the assumptions are ready, please
5151
<a href="https://github.com/athlan/wordpress-custom-fields-permalink-plugin/pulls">make a pull request</a> at GitHub.
5252

53+
= How to generate missing custom post meta keys and values =
54+
55+
In case of missing custom post field values you can generate them on-the-fly using <a href="https://github.com/athlan/wordpress-custom-fields-permalink-plugin/wiki/Plugin-hooks#generate_dynamic_metadata"><code>generate_dynamic_metadata</code></a> filter.
56+
57+
Read <a href="https://github.com/athlan/wordpress-custom-fields-permalink-plugin/wiki/FAQ#how-to-generate-missing-custom-post-meta-keys-and-values">the example</a>.
58+
59+
= How to generate calculated dynamic custom post meta keys and values =
60+
61+
You can generate custom post fields dynamically coding some logic using <a href="https://github.com/athlan/wordpress-custom-fields-permalink-plugin/wiki/Plugin-hooks#generate_dynamic_metadata"><code>generate_dynamic_metadata</code></a> filter.
62+
63+
Read <a href="https://github.com/athlan/wordpress-custom-fields-permalink-plugin/wiki/FAQ#how-to-generate-calculated-dynamic-custom-post-meta-keys-and-values">the example</a>.
64+
5365
== Screenshots ==
5466

5567
1. Pemralink settings

test/suites/MetaKeyPermalinkStructure/PostWithDynamicallyCreatedMetaKey.php

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,29 @@
1010
*/
1111
class PostWithDynamicallyCreatedMetaKey extends BaseTestCase {
1212

13+
/**
14+
* Sample custom metadata filter that adds some metadata to the array.
15+
*
16+
* @param array $post_meta The metadata returned from get_post_meta.
17+
* @param WP_Post $post The post object.
18+
*
19+
* @return array metadata
20+
*/
21+
function generate_dynamic_metadata( $post_meta = null, $post = null ) {
22+
if ( ! array_key_exists( 'some_meta_key', $post_meta ) ) {
23+
$post_meta['some_meta_key'] = 'Default value';
24+
}
25+
26+
return $post_meta;
27+
}
28+
29+
/**
30+
* Test step that hook wpcfp_get_post_metadata has been registered.
31+
*/
32+
private function given_hook_registered() {
33+
add_filter( 'wpcfp_get_post_metadata', array( $this, 'generate_dynamic_metadata' ), 1, 2 );
34+
}
35+
1336
/**
1437
* Test case.
1538
*/
@@ -26,14 +49,16 @@ function test_generates_permalink_to_post_while_missing_meta_key() {
2649
);
2750
$created_post_id = $this->factory()->post->create( $post_params );
2851

52+
$this->given_hook_registered();
53+
2954
// when & then.
30-
$this->permalink_asserter->has_permalink( $created_post_id, '/some-post-title/' );
55+
$this->permalink_asserter->has_permalink( $created_post_id, '/default-value/some-post-title/' );
3156
}
3257

3358
/**
3459
* Test case.
3560
*/
36-
function test_404_when_missing_meta_key() {
61+
function test_go_to_post_when_dynamic_generated_meta_value_without_hook() {
3762
// given.
3863
$this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
3964

@@ -47,7 +72,7 @@ function test_404_when_missing_meta_key() {
4772
$created_post_id = $this->factory()->post->create( $post_params );
4873

4974
// when.
50-
$this->go_to( '/inexisting-meta-value/some-post-title/' );
75+
$this->go_to( '/default-value/some-post-title/' );
5176

5277
// then.
5378
$this->navigation_asserter->then_not_displayed_post( $created_post_id )
@@ -58,22 +83,25 @@ function test_404_when_missing_meta_key() {
5883
/**
5984
* Test case.
6085
*/
61-
function test_not_go_to_the_post_when_missing_meta_key_part_in_url() {
86+
function test_go_to_post_when_dynamic_generated_meta_value_with_hook() {
6287
// given.
6388
$this->permalink_steps->given_permalink_structure( '/%field_some_meta_key%/%postname%/' );
6489

6590
$post_params = array(
6691
'post_title' => 'Some post title',
6792
'meta_input' => array(
68-
'some_meta_key' => 'Some meta value',
93+
// There is missing meta key here
94+
// 'some_meta_key' => 'Some meta value', .
6995
),
7096
);
7197
$created_post_id = $this->factory()->post->create( $post_params );
7298

99+
$this->given_hook_registered();
100+
73101
// when.
74-
$this->go_to( '/some-post-title/' );
102+
$this->go_to( '/default-value/some-post-title/' );
75103

76104
// then.
77-
$this->navigation_asserter->then_not_displayed_post( $created_post_id );
105+
$this->navigation_asserter->then_displayed_post( $created_post_id );
78106
}
79107
}

wordpress-custom-fields-permalink-plugin.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
add_filter( 'rewrite_rules_array', array( 'CustomFieldsPermalink', 'rewrite_rules_array_filter' ) );
2222
add_filter( 'query_vars', array( 'CustomFieldsPermalink', 'register_extra_query_vars' ), 10, 1 );
2323
add_filter( 'request', array( 'CustomFieldsPermalink', 'process_request' ), 10, 1 );
24+
add_filter( 'pre_handle_404', array( 'CustomFieldsPermalink', 'pre_handle_404' ), 10, 2 );

0 commit comments

Comments
 (0)