> */ function get_fields() { $fields = array( 'bm_project' => array( 'bm_client' => array( 'type' => 'string', 'label' => __( 'Client', 'blockmason-core' ), ), 'bm_location' => array( 'type' => 'string', 'label' => __( 'Location', 'blockmason-core' ), 'help' => __( 'City or area, e.g. "Milan, Italy".', 'blockmason-core' ), ), 'bm_year' => array( 'type' => 'integer', 'label' => __( 'Year', 'blockmason-core' ), ), 'bm_area' => array( 'type' => 'number', 'label' => __( 'Area (m²)', 'blockmason-core' ), ), 'bm_duration' => array( 'type' => 'string', 'label' => __( 'Duration', 'blockmason-core' ), 'help' => __( 'E.g. "8 months".', 'blockmason-core' ), ), 'bm_before_image' => array( 'type' => 'image', 'label' => __( 'Before image', 'blockmason-core' ), ), 'bm_after_image' => array( 'type' => 'image', 'label' => __( 'After image', 'blockmason-core' ), ), 'bm_services' => array( 'type' => 'posts', 'posts' => 'bm_service', 'label' => __( 'Services', 'blockmason-core' ), 'help' => __( 'The project is listed on the pages of these services.', 'blockmason-core' ), ), ), 'bm_service' => array( 'bm_icon' => array( 'type' => 'icon', 'label' => __( 'Icon', 'blockmason-core' ), ), ), 'bm_team_member' => array( 'bm_role' => array( 'type' => 'string', 'label' => __( 'Role', 'blockmason-core' ), ), 'bm_email' => array( 'type' => 'email', 'label' => __( 'Email', 'blockmason-core' ), ), 'bm_phone' => array( 'type' => 'string', 'label' => __( 'Phone', 'blockmason-core' ), ), 'bm_linkedin' => array( 'type' => 'url', 'label' => __( 'LinkedIn profile URL', 'blockmason-core' ), ), ), 'bm_testimonial' => array( 'bm_company' => array( 'type' => 'string', 'label' => __( 'Company', 'blockmason-core' ), ), 'bm_rating' => array( 'type' => 'rating', 'label' => __( 'Rating (1–5)', 'blockmason-core' ), ), 'bm_project' => array( 'type' => 'posts', 'posts' => 'bm_project', 'label' => __( 'Related project', 'blockmason-core' ), 'single' => true, ), ), ); /** * Filters the custom fields of the Blockmason content types. * * @param array $fields Field definitions grouped by post type. */ return apply_filters( 'blockmason_core_fields', $fields ); } /** * Registers all fields as post meta. */ function register_meta_fields() { foreach ( get_fields() as $post_type => $fields ) { foreach ( $fields as $key => $field ) { register_post_meta( $post_type, $key, meta_args( $field ) ); } } } /** * Builds register_post_meta() arguments for one field. * * @param array $field Field definition. * @return array */ function meta_args( array $field ) { $args = array( 'single' => true, 'show_in_rest' => true, 'label' => $field['label'], 'auth_callback' => __NAMESPACE__ . '\can_edit_meta', ); switch ( $field['type'] ) { case 'integer': case 'image': $args['type'] = 'integer'; $args['default'] = 0; $args['sanitize_callback'] = 'absint'; break; case 'rating': $args['type'] = 'integer'; $args['default'] = 5; $args['sanitize_callback'] = __NAMESPACE__ . '\sanitize_rating'; break; case 'number': $args['type'] = 'number'; $args['default'] = 0; $args['sanitize_callback'] = __NAMESPACE__ . '\sanitize_number'; break; case 'url': $args['type'] = 'string'; $args['default'] = ''; $args['sanitize_callback'] = 'esc_url_raw'; break; case 'email': $args['type'] = 'string'; $args['default'] = ''; $args['sanitize_callback'] = 'sanitize_email'; break; case 'icon': $args['type'] = 'string'; $args['default'] = ''; $args['sanitize_callback'] = 'sanitize_key'; break; case 'posts': $args['type'] = 'integer'; $args['sanitize_callback'] = 'absint'; if ( empty( $field['single'] ) ) { // One meta row per related post, so it can be queried with meta_query. $args['single'] = false; } else { $args['default'] = 0; } break; default: $args['type'] = 'string'; $args['default'] = ''; $args['sanitize_callback'] = 'sanitize_text_field'; } return $args; } /** * Only users who can edit the post can change its fields. * * @param bool $allowed Whether the user can edit the meta key. * @param string $meta_key Meta key. * @param int $post_id Post ID. * @return bool */ function can_edit_meta( $allowed, $meta_key, $post_id ) { return current_user_can( 'edit_post', $post_id ); } /** * Keeps a rating between 1 and 5. * * @param mixed $value Raw value. * @return int */ function sanitize_rating( $value ) { return max( 1, min( 5, absint( $value ) ) ); } /** * Keeps a non-negative number. * * @param mixed $value Raw value. * @return float */ function sanitize_number( $value ) { return max( 0, (float) $value ); } /** * Returns a field value for a post, with the right type. * * @param int $post_id Post ID. * @param string $key Meta key. * @return mixed */ function get_field( $post_id, $key ) { $post_type = get_post_type( $post_id ); $fields = get_fields(); $field = $fields[ $post_type ][ $key ] ?? null; if ( ! $field ) { return null; } if ( 'posts' === $field['type'] && empty( $field['single'] ) ) { return array_values( array_filter( array_map( 'absint', get_post_meta( $post_id, $key, false ) ) ) ); } return get_post_meta( $post_id, $key, true ); }