Skip to content

Commit 255f8a2

Browse files
authored
Support for field usage attributes in permalink definition (#31)
* Support for permalink fields attributes added. * Tests added for field attributes. Tests namespaced. * Include relatively in main. * Fix the bug which sanitizes unwanted spaces in permalink structure. * Bump version to 1.4.0
1 parent b390f86 commit 255f8a2

23 files changed

+729
-44
lines changed

includes/class-field-attributes.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
/**
3+
* Class Field_Attr
4+
*
5+
* @package WordPress_Custom_Fields_Permalink
6+
*/
7+
8+
namespace CustomFieldsPermalink;
9+
10+
/**
11+
* Class Field_Attr parses attributes string.
12+
*/
13+
class Field_Attributes {
14+
15+
/**
16+
* Extract the metadata value from the post.
17+
*
18+
* @param string $string The attributes string.
19+
*
20+
* @return array
21+
*/
22+
public function parse_attributes( $string ) {
23+
if ( null === $string || '' === trim( $string ) ) {
24+
return array();
25+
}
26+
27+
$result = array();
28+
29+
$parsed = shortcode_parse_atts( $string );
30+
foreach ( $parsed as $key => $value ) {
31+
if ( is_integer( $key ) ) {
32+
$result[ $value ] = true;
33+
} else {
34+
$result[ $key ] = $value;
35+
}
36+
}
37+
38+
return $result;
39+
}
40+
}

includes/class-wp-permalink.php

+31-10
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,22 @@ class WP_Permalink {
2121
*/
2222
private $post_meta;
2323

24+
/**
25+
* Field attributes parser.
26+
*
27+
* @var Field_Attributes
28+
*/
29+
private $field_attributes;
30+
2431
/**
2532
* WP_Permalink constructor.
2633
*
27-
* @param WP_Post_Meta $post_meta Post meta provider.
34+
* @param WP_Post_Meta $post_meta Post meta provider.
35+
* @param Field_Attributes $field_attributes Field attributes parser.
2836
*/
29-
public function __construct( WP_Post_Meta $post_meta ) {
30-
$this->post_meta = $post_meta;
37+
public function __construct( WP_Post_Meta $post_meta, Field_Attributes $field_attributes ) {
38+
$this->post_meta = $post_meta;
39+
$this->field_attributes = $field_attributes;
3140
}
3241

3342
/**
@@ -73,27 +82,39 @@ public function link_post_type( $permalink, $post, $leavename, $sample ) {
7382
*/
7483
private function link_rewrite_fields( $permalink, $post ) {
7584
$that = $this;
76-
$replace_callback = function ( $matches ) use ( &$post, &$that ) {
77-
return $that->link_rewrite_fields_extract( $post, $matches[2] );
85+
$field_attributes = $this->field_attributes;
86+
$replace_callback = function ( $matches ) use ( &$post, &$that, &$field_attributes ) {
87+
$field_name = $matches[ WP_Rewrite_Rules::FIELD_REGEXP_NAME_GROUP ];
88+
89+
if ( isset( $matches[ WP_Rewrite_Rules::FIELD_REGEXP_ATTRIBUTES_GROUP ] ) ) {
90+
$field_attr = $field_attributes->parse_attributes( $matches[ WP_Rewrite_Rules::FIELD_REGEXP_ATTRIBUTES_GROUP ] );
91+
} else {
92+
$field_attr = array();
93+
}
94+
95+
return $that->link_rewrite_fields_extract( $post, $field_name, $field_attr );
7896
};
79-
return preg_replace_callback( '#(%field_(.*?)%)#', $replace_callback, $permalink );
97+
98+
return preg_replace_callback( '#' . WP_Rewrite_Rules::FIELD_REGEXP . '#', $replace_callback, $permalink );
8099
}
81100

82101
/**
83102
* Extract the metadata value from the post.
84103
*
85104
* @param WP_Post $post The post.
86105
* @param string $field_name The metadata key to extract.
106+
* @param array $field_attr The metadata field rewrite permalink attributes.
87107
*
88108
* @return string
89109
*/
90-
public function link_rewrite_fields_extract( $post, $field_name ) {
91-
$post_meta = $this->post_meta->get_post_meta( $post );
92-
if ( ! isset( $post_meta[ $field_name ] ) ) {
110+
public function link_rewrite_fields_extract( $post, $field_name, array $field_attr ) {
111+
$post_meta_value = $this->post_meta->get_post_meta_single( $post, $field_name, $field_attr );
112+
if ( ! isset( $post_meta_value ) ) {
93113
return '';
94114
}
95-
$value = $post_meta[ $field_name ][0];
115+
$value = $post_meta_value[0];
96116
$value = sanitize_title( $value );
117+
97118
return $value;
98119
}
99120
}

includes/class-wp-post-meta.php

+44
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,50 @@ public function get_post_meta( $post ) {
4040
$value = array( $value );
4141
}
4242
}
43+
4344
return $filtered_post_meta;
4445
}
46+
47+
/**
48+
* Get single post meta applying <code>wpcfp_get_post_metadata_single</code> filter.
49+
*
50+
* @param WP_Post $post The post.
51+
* @param string $meta_key Name of metadata field.
52+
* @param array $meta_key_attrs The metadata field rewrite permalink attributes.
53+
*
54+
* @return array
55+
*/
56+
public function get_post_meta_single( $post, $meta_key, array $meta_key_attrs ) {
57+
$post_meta = $this->get_post_meta( $post );
58+
59+
if ( array_key_exists( $meta_key, $post_meta ) ) {
60+
$post_meta_value = $post_meta[ $meta_key ];
61+
} else {
62+
$post_meta_value = null;
63+
}
64+
65+
/**
66+
* Filters of retrieved single metadata of a post to link rewrite.
67+
*
68+
* @since 1.4.0
69+
*
70+
* @param mixed|null $post_meta_value The metadata values returned from get_post_meta.
71+
* @param string $meta_key Name of metadata field.
72+
* @param array $meta_key_attrs The metadata field rewrite permalink attributes.
73+
* @param WP_Post $post The post object.
74+
*/
75+
$filtered_post_meta_value = apply_filters( 'wpcfp_get_post_metadata_single', $post_meta_value, $meta_key, $meta_key_attrs, $post );
76+
if ( null === $filtered_post_meta_value ) {
77+
return null;
78+
}
79+
80+
// Do some fixes after user generated values.
81+
// If it's single value, wrap this in array, as WordPress internally does.
82+
// @see get_post_meta() with $single = false.
83+
if ( ! is_array( $filtered_post_meta_value ) ) {
84+
$filtered_post_meta_value = array( $filtered_post_meta_value );
85+
}
86+
87+
return $filtered_post_meta_value;
88+
}
4589
}

includes/class-wp-request-processor.php

+48-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
*/
1515
class WP_Request_Processor {
1616

17-
const PARAM_CUSTOMFIELD_PARAMES = 'custom_field_params';
17+
const PARAM_CUSTOMFIELD_PARAMS = 'custom_field_params';
18+
const PARAM_CUSTOMFIELD_PARAMS_ATTR = 'custom_field_params_attr';
1819

1920
/**
2021
* Post meta provider.
@@ -43,7 +44,7 @@ public function __construct( WP_Post_Meta $post_meta ) {
4344
* @return mixed
4445
*/
4546
public function register_extra_query_vars( $public_query_vars ) {
46-
array_push( $public_query_vars, self::PARAM_CUSTOMFIELD_PARAMES );
47+
array_push( $public_query_vars, self::PARAM_CUSTOMFIELD_PARAMS, self::PARAM_CUSTOMFIELD_PARAMS_ATTR );
4748

4849
return $public_query_vars;
4950
}
@@ -71,7 +72,7 @@ public function process_request( $query_vars ) {
7172
* 1. Custom field key does not exists or
7273
* 2. Custom field value does not matches.
7374
*
74-
* @param bool $preempt Whether to short-circuit default header status handling. Default false.
75+
* @param bool $preempt Whether to short-circuit default header status handling. Default false.
7576
* @param WP_Query $wp_query WordPress Query object.
7677
*
7778
* @return bool Returning a non-false value from the filter will short-circuit the handling
@@ -88,25 +89,33 @@ public function pre_handle_404( $preempt, $wp_query ) {
8889
$post = $wp_query->post;
8990

9091
// Analyse only if custom field used in query.
91-
if ( ! array_key_exists( self::PARAM_CUSTOMFIELD_PARAMES, $wp_query->query_vars )
92-
|| ! is_array( $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMES ] ) ) {
92+
if ( ! array_key_exists( self::PARAM_CUSTOMFIELD_PARAMS, $wp_query->query_vars )
93+
|| ! is_array( $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS ] )
94+
) {
9395
return false;
9496
}
9597

96-
$query_meta_params = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMES ];
98+
$query_meta_params = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS ];
99+
$query_meta_params_attr = $this->get_param_attr( $wp_query );
97100

98101
$raise_404 = false;
99102

100-
$post_meta = $this->post_meta->get_post_meta( $post );
101-
102103
foreach ( $query_meta_params as $query_meta_key => $query_meta_value ) {
103-
if ( ! array_key_exists( $query_meta_key, $post_meta ) ) {
104+
if ( array_key_exists( $query_meta_key, $query_meta_params_attr ) ) {
105+
$field_attr = $query_meta_params_attr[ $query_meta_key ];
106+
} else {
107+
$field_attr = array();
108+
}
109+
110+
$post_meta_values = $this->post_meta->get_post_meta_single( $post, $query_meta_key, $field_attr );
111+
112+
if ( null === $post_meta_values || ! $post_meta_values ) {
104113
$raise_404 = true;
105114
break;
106115
} else {
107116
// Look for at least one value match.
108117
$value_matched = false;
109-
foreach ( $post_meta[ $query_meta_key ] as $post_meta_value ) {
118+
foreach ( $post_meta_values as $post_meta_value ) {
110119
$post_meta_value_sanitized = sanitize_title( $post_meta_value );
111120

112121
if ( $query_meta_value == $post_meta_value_sanitized ) {
@@ -132,4 +141,33 @@ public function pre_handle_404( $preempt, $wp_query ) {
132141

133142
return false;
134143
}
144+
145+
/**
146+
* Gets custom fields parameters attributes from WP_Query.
147+
*
148+
* @param WP_Query $wp_query WordPress Query object.
149+
*
150+
* @access private
151+
* @return array
152+
*/
153+
private function get_param_attr( WP_Query $wp_query ) {
154+
if ( ! isset( $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS_ATTR ] ) ) {
155+
return array();
156+
}
157+
158+
$attrs = array();
159+
$query_meta_params_attr = $wp_query->query_vars[ self::PARAM_CUSTOMFIELD_PARAMS_ATTR ];
160+
161+
foreach ( $query_meta_params_attr as $attr_field_and_key => $attr_value ) {
162+
list( $field_name, $field_attr_name ) = explode( '::', $attr_field_and_key );
163+
164+
if ( ! array_key_exists( $field_name, $attrs ) ) {
165+
$attrs[ $field_name ] = array();
166+
}
167+
168+
$attrs[ $field_name ][ $field_attr_name ] = $attr_value;
169+
}
170+
171+
return $attrs;
172+
}
135173
}

0 commit comments

Comments
 (0)