Skip to content

Commit aaca9cd

Browse files
lint fixes
1 parent aa25b28 commit aaca9cd

4 files changed

Lines changed: 434 additions & 39 deletions

File tree

src/wp-includes/abilities.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,5 @@ function wp_register_core_abilities(): void {
270270
);
271271

272272
WP_Settings_Abilities::register();
273+
WP_Post_Type_Abilities::register();
273274
}

src/wp-includes/abilities/class-wp-post-type-abilities.php

Lines changed: 189 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -879,9 +879,9 @@ private static function execute_get_single( int $post_id, WP_Post_Type $post_typ
879879
*
880880
* @param WP_Post_Type $post_type_object The post type object.
881881
* @param array $input The input parameters.
882-
* @return array Query results with posts, total, and total_pages.
882+
* @return array|WP_Error Query results with posts, total, and total_pages, or error.
883883
*/
884-
private static function execute_get_query( WP_Post_Type $post_type_object, array $input ): array {
884+
private static function execute_get_query( WP_Post_Type $post_type_object, array $input ) {
885885
$per_page = $input['per_page'] ?? 10;
886886
$page = $input['page'] ?? 1;
887887

@@ -939,6 +939,23 @@ private static function execute_get_query( WP_Post_Type $post_type_object, array
939939
$query_input = $input['query'];
940940

941941
if ( ! empty( $query_input['tax'] ) ) {
942+
// Validate that all taxonomies in the query are public.
943+
$taxonomies_in_query = self::extract_taxonomies_from_query( $query_input['tax'] );
944+
$allowed_taxonomies = self::get_allowed_taxonomies( $post_type_object->name );
945+
$invalid_taxonomies = array_diff( $taxonomies_in_query, $allowed_taxonomies );
946+
947+
if ( ! empty( $invalid_taxonomies ) ) {
948+
return new WP_Error(
949+
'invalid_taxonomy',
950+
sprintf(
951+
/* translators: %s: Comma-separated list of invalid taxonomy slugs. */
952+
__( 'The following taxonomies are not allowed: %s' ),
953+
implode( ', ', $invalid_taxonomies )
954+
),
955+
array( 'status' => 400 )
956+
);
957+
}
958+
942959
$tax_query = self::process_query_recursive(
943960
$query_input['tax'],
944961
array( __CLASS__, 'process_tax_clause' )
@@ -949,6 +966,23 @@ private static function execute_get_query( WP_Post_Type $post_type_object, array
949966
}
950967

951968
if ( ! empty( $query_input['meta'] ) ) {
969+
// Validate that all meta keys in the query have show_in_abilities enabled.
970+
$meta_keys_in_query = self::extract_meta_keys_from_query( $query_input['meta'] );
971+
$allowed_meta_keys = self::get_allowed_meta_keys( $post_type_object->name );
972+
$invalid_keys = array_diff( $meta_keys_in_query, $allowed_meta_keys );
973+
974+
if ( ! empty( $invalid_keys ) ) {
975+
return new WP_Error(
976+
'invalid_meta_key',
977+
sprintf(
978+
/* translators: %s: Comma-separated list of invalid meta keys. */
979+
__( 'The following meta keys are not allowed: %s' ),
980+
implode( ', ', $invalid_keys )
981+
),
982+
array( 'status' => 400 )
983+
);
984+
}
985+
952986
$meta_query = self::process_query_recursive(
953987
$query_input['meta'],
954988
array( __CLASS__, 'process_meta_clause' )
@@ -1025,8 +1059,8 @@ private static function format_post( WP_Post $post, WP_Post_Type $post_type_obje
10251059
}
10261060

10271061
if ( post_type_supports( $slug, 'author' ) ) {
1028-
$author = get_userdata( (int) $post->post_author );
1029-
$data['author'] = array(
1062+
$author = get_userdata( (int) $post->post_author );
1063+
$data['author'] = array(
10301064
'id' => (int) $post->post_author,
10311065
'display_name' => $author ? $author->display_name : '',
10321066
);
@@ -1042,8 +1076,8 @@ private static function format_post( WP_Post $post, WP_Post_Type $post_type_obje
10421076
}
10431077

10441078
if ( post_type_supports( $slug, 'post-formats' ) ) {
1045-
$format = get_post_format( $post );
1046-
$data['format'] = $format ? $format : 'standard';
1079+
$format = get_post_format( $post );
1080+
$data['format'] = $format ? $format : 'standard';
10471081
}
10481082

10491083
if ( post_type_supports( $slug, 'comments' ) ) {
@@ -1084,13 +1118,19 @@ static function ( $term ): array {
10841118
}
10851119

10861120
if ( ! empty( $include['meta'] ) && post_type_supports( $slug, 'custom-fields' ) ) {
1087-
$meta = get_post_meta( $post->ID );
1088-
$public_meta = array();
1121+
$meta = get_post_meta( $post->ID );
1122+
$public_meta = array();
1123+
$allowed_meta_keys = self::get_allowed_meta_keys( $slug );
10891124

10901125
foreach ( $meta as $key => $values ) {
1126+
// Skip protected meta keys.
10911127
if ( is_protected_meta( $key, 'post' ) ) {
10921128
continue;
10931129
}
1130+
// Only include meta keys that are registered with show_in_abilities enabled.
1131+
if ( ! in_array( $key, $allowed_meta_keys, true ) ) {
1132+
continue;
1133+
}
10941134
$public_meta[ $key ] = count( $values ) === 1 ? $values[0] : $values;
10951135
}
10961136

@@ -1218,19 +1258,38 @@ private static function process_meta_clause( array $clause ): ?array {
12181258
}
12191259

12201260
$allowed_compare = array(
1221-
'=', '!=', '>', '>=', '<', '<=',
1222-
'LIKE', 'NOT LIKE', 'IN', 'NOT IN',
1223-
'BETWEEN', 'NOT BETWEEN',
1224-
'EXISTS', 'NOT EXISTS',
1225-
'REGEXP', 'NOT REGEXP', 'RLIKE',
1261+
'=',
1262+
'!=',
1263+
'>',
1264+
'>=',
1265+
'<',
1266+
'<=',
1267+
'LIKE',
1268+
'NOT LIKE',
1269+
'IN',
1270+
'NOT IN',
1271+
'BETWEEN',
1272+
'NOT BETWEEN',
1273+
'EXISTS',
1274+
'NOT EXISTS',
1275+
'REGEXP',
1276+
'NOT REGEXP',
1277+
'RLIKE',
12261278
);
12271279
if ( ! empty( $clause['compare'] ) && in_array( $clause['compare'], $allowed_compare, true ) ) {
12281280
$result['compare'] = $clause['compare'];
12291281
}
12301282

12311283
$allowed_types = array(
1232-
'NUMERIC', 'CHAR', 'DATE', 'DATETIME',
1233-
'TIME', 'BINARY', 'SIGNED', 'UNSIGNED', 'DECIMAL',
1284+
'NUMERIC',
1285+
'CHAR',
1286+
'DATE',
1287+
'DATETIME',
1288+
'TIME',
1289+
'BINARY',
1290+
'SIGNED',
1291+
'UNSIGNED',
1292+
'DECIMAL',
12341293
);
12351294
if ( ! empty( $clause['type'] ) && in_array( $clause['type'], $allowed_types, true ) ) {
12361295
$result['type'] = $clause['type'];
@@ -1251,9 +1310,16 @@ private static function process_date_clause( array $clause ): ?array {
12511310
$result = array();
12521311

12531312
$int_fields = array(
1254-
'year', 'month', 'week', 'day',
1255-
'hour', 'minute', 'second',
1256-
'dayofweek', 'dayofweek_iso', 'dayofyear',
1313+
'year',
1314+
'month',
1315+
'week',
1316+
'day',
1317+
'hour',
1318+
'minute',
1319+
'second',
1320+
'dayofweek',
1321+
'dayofweek_iso',
1322+
'dayofyear',
12571323
);
12581324

12591325
foreach ( $int_fields as $field ) {
@@ -1315,4 +1381,109 @@ private static function process_date_top_level( array $input, array &$result ):
13151381
$result['column'] = $input['column'];
13161382
}
13171383
}
1384+
1385+
/**
1386+
* Returns all meta keys that are registered with show_in_abilities enabled for a post type.
1387+
*
1388+
* @since 7.0.0
1389+
*
1390+
* @param string $post_type_slug The post type slug.
1391+
* @return string[] List of allowed meta keys.
1392+
*/
1393+
private static function get_allowed_meta_keys( string $post_type_slug ): array {
1394+
$registered_meta = array_merge(
1395+
get_registered_meta_keys( 'post', $post_type_slug ),
1396+
get_registered_meta_keys( 'post' )
1397+
);
1398+
1399+
$allowed = array();
1400+
foreach ( $registered_meta as $key => $args ) {
1401+
if ( ! empty( $args['show_in_abilities'] ) ) {
1402+
$allowed[] = $key;
1403+
}
1404+
}
1405+
1406+
return $allowed;
1407+
}
1408+
1409+
/**
1410+
* Extracts all meta keys from a meta query structure recursively.
1411+
*
1412+
* @since 7.0.0
1413+
*
1414+
* @param array $query The meta query input.
1415+
* @return string[] List of meta keys found in the query.
1416+
*/
1417+
private static function extract_meta_keys_from_query( array $query ): array {
1418+
$keys = array();
1419+
1420+
if ( ! empty( $query['queries'] ) && is_array( $query['queries'] ) ) {
1421+
foreach ( $query['queries'] as $sub_query ) {
1422+
if ( ! is_array( $sub_query ) ) {
1423+
continue;
1424+
}
1425+
1426+
if ( isset( $sub_query['queries'] ) ) {
1427+
// Nested group: recurse.
1428+
$keys = array_merge( $keys, self::extract_meta_keys_from_query( $sub_query ) );
1429+
} elseif ( ! empty( $sub_query['key'] ) ) {
1430+
// Leaf clause with a key.
1431+
$keys[] = sanitize_key( $sub_query['key'] );
1432+
}
1433+
}
1434+
}
1435+
1436+
return array_unique( $keys );
1437+
}
1438+
1439+
/**
1440+
* Returns all public taxonomies associated with a post type.
1441+
*
1442+
* @since 7.0.0
1443+
*
1444+
* @param string $post_type_slug The post type slug.
1445+
* @return string[] List of allowed taxonomy slugs.
1446+
*/
1447+
private static function get_allowed_taxonomies( string $post_type_slug ): array {
1448+
$taxonomies = get_object_taxonomies( $post_type_slug, 'objects' );
1449+
$allowed = array();
1450+
1451+
foreach ( $taxonomies as $taxonomy ) {
1452+
if ( $taxonomy->public ) {
1453+
$allowed[] = $taxonomy->name;
1454+
}
1455+
}
1456+
1457+
return $allowed;
1458+
}
1459+
1460+
/**
1461+
* Extracts all taxonomy slugs from a taxonomy query structure recursively.
1462+
*
1463+
* @since 7.0.0
1464+
*
1465+
* @param array $query The taxonomy query input.
1466+
* @return string[] List of taxonomy slugs found in the query.
1467+
*/
1468+
private static function extract_taxonomies_from_query( array $query ): array {
1469+
$taxonomies = array();
1470+
1471+
if ( ! empty( $query['queries'] ) && is_array( $query['queries'] ) ) {
1472+
foreach ( $query['queries'] as $sub_query ) {
1473+
if ( ! is_array( $sub_query ) ) {
1474+
continue;
1475+
}
1476+
1477+
if ( isset( $sub_query['queries'] ) ) {
1478+
// Nested group: recurse.
1479+
$taxonomies = array_merge( $taxonomies, self::extract_taxonomies_from_query( $sub_query ) );
1480+
} elseif ( ! empty( $sub_query['taxonomy'] ) ) {
1481+
// Leaf clause with a taxonomy.
1482+
$taxonomies[] = sanitize_key( $sub_query['taxonomy'] );
1483+
}
1484+
}
1485+
}
1486+
1487+
return array_unique( $taxonomies );
1488+
}
13181489
}

src/wp-includes/meta.php

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,7 @@ function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype =
13961396
* @since 5.5.0 The `$default` argument was added to the arguments array.
13971397
* @since 6.4.0 The `$revisions_enabled` argument was added to the arguments array.
13981398
* @since 6.7.0 The `label` argument was added to the arguments array.
1399+
* @since 7.0.0 The `show_in_abilities` argument was added to the arguments array.
13991400
*
14001401
* @global array $wp_meta_keys Global registry for meta keys.
14011402
*
@@ -1419,13 +1420,15 @@ function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype =
14191420
* @type callable $sanitize_callback A function or method to call when sanitizing `$meta_key` data.
14201421
* @type callable $auth_callback Optional. A function or method to call when performing edit_post_meta,
14211422
* add_post_meta, and delete_post_meta capability checks.
1422-
* @type bool|array $show_in_rest Whether data associated with this meta key can be considered public and
1423-
* should be accessible via the REST API. A custom post type must also declare
1424-
* support for custom fields for registered meta to be accessible via REST.
1425-
* When registering complex meta values this argument may optionally be an
1426-
* array with 'schema' or 'prepare_callback' keys instead of a boolean.
1427-
* @type bool $revisions_enabled Whether to enable revisions support for this meta_key. Can only be used when the
1428-
* object type is 'post'.
1423+
* @type bool|array $show_in_rest Whether data associated with this meta key can be considered public and
1424+
* should be accessible via the REST API. A custom post type must also declare
1425+
* support for custom fields for registered meta to be accessible via REST.
1426+
* When registering complex meta values this argument may optionally be an
1427+
* array with 'schema' or 'prepare_callback' keys instead of a boolean.
1428+
* @type bool $show_in_abilities Whether this meta key should be exposed through the Abilities API.
1429+
* Default false.
1430+
* @type bool $revisions_enabled Whether to enable revisions support for this meta_key. Can only be used when the
1431+
* object type is 'post'.
14291432
* }
14301433
* @param string|array $deprecated Deprecated. Use `$args` instead.
14311434
* @return bool True if the meta key was successfully registered in the global array, false if not.
@@ -1440,16 +1443,17 @@ function register_meta( $object_type, $meta_key, $args, $deprecated = null ) {
14401443
}
14411444

14421445
$defaults = array(
1443-
'object_subtype' => '',
1444-
'type' => 'string',
1445-
'label' => '',
1446-
'description' => '',
1447-
'default' => '',
1448-
'single' => false,
1449-
'sanitize_callback' => null,
1450-
'auth_callback' => null,
1451-
'show_in_rest' => false,
1452-
'revisions_enabled' => false,
1446+
'object_subtype' => '',
1447+
'type' => 'string',
1448+
'label' => '',
1449+
'description' => '',
1450+
'default' => '',
1451+
'single' => false,
1452+
'sanitize_callback' => null,
1453+
'auth_callback' => null,
1454+
'show_in_rest' => false,
1455+
'show_in_abilities' => false,
1456+
'revisions_enabled' => false,
14531457
);
14541458

14551459
// There used to be individual args for sanitize and auth callbacks.

0 commit comments

Comments
 (0)