PHP expression of the post ID passed to get_field() ('' for the current post). * * @return array */ public function covered(): array { $defaults = array_fill_keys( self::POST_RULES, '' ); /** * Location rules the generated code covers, with the post ID argument of get_field() for each * (a PHP expression, such as "'option'"; '' reads the current post). * * @param array $locations Rule name => PHP expression. */ $filtered = apply_filters( 'awfc_locations', $defaults ); if ( ! is_array( $filtered ) ) { return $defaults; } $covered = array(); foreach ( $filtered as $param => $post_id ) { if ( is_string( $param ) && is_string( $post_id ) ) { $covered[ $param ] = $post_id; } } return $covered; } /** * What the code of a field group reads, from its location rules. * * @param array $group Field group. * @return array{post_id:string,uncovered:string[]} The post ID argument of the code (from the first covered rule), * and the names of the rules that this code does not cover. */ public function resolve( array $group ): array { $read = $this->read( $group ); unset( $read['uncovered_rules'] ); return $read; } /** * What the code of a field group reads, with the uncovered rules as ACF and SCF store them as well. * * @param array $group Field group. * @return array{post_id:string,uncovered:string[],uncovered_rules:string[]} See resolve(); uncovered_rules: the same * rules by their name (param), such as "options_page". */ public function read( array $group ): array { $analysis = $this->analyse( $group ); return array( 'post_id' => $analysis['post_id'], 'uncovered' => array_values( array_unique( array_map( array( $this, 'label' ), $analysis['uncovered'] ) ) ), 'uncovered_rules' => array_values( array_unique( $analysis['uncovered'] ) ), ); } /** * Reads the location rules of a field group. * * @param array $group Field group. * @return array{post_id:string,uncovered:string[]} The post ID argument of the code, and the first rule (param) * of each "or" group that this code does not cover. */ private function analyse( array $group ): array { $covered = $this->covered(); $post_id = null; $uncovered = array(); $location = isset( $group['location'] ) && is_array( $group['location'] ) ? $group['location'] : array(); foreach ( $location as $rules ) { if ( ! is_array( $rules ) ) { continue; } $found = null; $params = array(); foreach ( $rules as $rule ) { $param = is_array( $rule ) && isset( $rule['param'] ) && is_string( $rule['param'] ) ? $rule['param'] : ''; if ( '' === $param ) { continue; } if ( null === $found && array_key_exists( $param, $covered ) ) { $found = $this->post_id( $covered[ $param ], $rule, $group ); } $params[] = $param; } if ( null !== $found && ( null === $post_id || $found === $post_id ) ) { $post_id = $found; } elseif ( $params ) { // Not covered, or covered with another post ID than the one the code reads. $uncovered[] = $params[0]; } } return array( 'post_id' => null === $post_id ? '' : $post_id, 'uncovered' => $uncovered, ); } /** * The post ID argument of a covered rule, once other plugins have seen the whole rule. * * @param string $post_id PHP expression of the post ID, from awfc_locations. * @param array $rule Location rule (param, operator, value). * @param array $group Field group. * @return string */ private function post_id( string $post_id, array $rule, array $group ): string { $rule = array_merge( $rule, array( 'param' => (string) $rule['param'], 'operator' => isset( $rule['operator'] ) && is_string( $rule['operator'] ) ? $rule['operator'] : '', 'value' => isset( $rule['value'] ) && is_scalar( $rule['value'] ) ? (string) $rule['value'] : '', ) ); /** * The post ID argument of get_field() for a covered location rule, with the whole rule: an options page * stored under its own post ID, for example. * * @param string $post_id PHP expression of the post ID ('' reads the current post). * @param array $rule Location rule: param, operator, value. * @param array $group Field group. */ $filtered = apply_filters( 'awfc_location_post_id', $post_id, $rule, $group ); return is_string( $filtered ) ? $filtered : $post_id; } /** * Name of a location rule, as ACF or SCF shows it. * * @param string $param Rule name. * @return string */ public function label( string $param ): string { if ( function_exists( 'acf_get_location_type' ) ) { $type = acf_get_location_type( $param ); if ( is_object( $type ) && isset( $type->label ) && is_string( $type->label ) && '' !== $type->label ) { return $type->label; } } return $param; } }