| @@ -126,10 +126,10 @@ | ||
| 126 | 126 | public function get_auto_update_context_fields(): array { |
| 127 | 127 | return array( |
| 128 | 128 | array( |
| 129 | 129 | 'single' => true, |
| 130 | - 'description' => __( 'The Trigger Field value overrides the static "Filter by Roles" setting above. If the Trigger Field is empty, the static roles are used.', 'jet-form-builder' ), | |
| 131 | - 'example' => __( 'Select the field that returns one or more user role slugs, for example: administrator, editor, subscriber.', 'jet-form-builder' ), | |
| 130 | + 'description' => __( 'The Trigger Field value can narrow the configured "Filter by Roles" setting when it matches a saved Trigger Field choice or an allowed server-side role. If validation fails, the static roles are used.', 'jet-form-builder' ), | |
| 131 | + 'example' => __( 'Select the field whose saved option values should be allowed as dynamic user roles, for example: editor or subscriber.', 'jet-form-builder' ), | |
| 132 | 132 | ), |
| 133 | 133 | ); |
| 134 | 134 | } |
| 135 | 135 | |
| @@ -152,9 +152,9 @@ | ||
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | /** |
| 155 | 155 | * Generates options with context from a dependent field. |
| 156 | - * Overrides the roles setting with the value from the listened field. | |
| 156 | + * Narrows the saved roles setting with the value from the listened field. | |
| 157 | 157 | * |
| 158 | 158 | * @param array $settings Parsed settings from block attributes. |
| 159 | 159 | * @param array $context Associative array ['field_name' => 'value'] from dependent fields. |
| 160 | 160 | * |
| @@ -162,32 +162,125 @@ | ||
| 162 | 162 | */ |
| 163 | 163 | public function generate_with_context( array $settings, array $context = array() ): array { |
| 164 | 164 | if ( ! empty( $context ) ) { |
| 165 | 165 | $context_value = reset( $context ); |
| 166 | + $context_roles = array(); | |
| 166 | 167 | |
| 167 | 168 | // Support both single role (scalar) and multi-role (checkbox/multi-select array). |
| 168 | 169 | if ( is_array( $context_value ) ) { |
| 169 | - $roles = array_filter( | |
| 170 | - array_map( | |
| 171 | - static function ( $role ) { | |
| 172 | - return sanitize_key( (string) $role ); | |
| 173 | - }, | |
| 174 | - $context_value | |
| 175 | - ) | |
| 170 | + $context_roles = $this->sanitize_roles_list( $context_value ); | |
| 171 | + } else { | |
| 172 | + $role = sanitize_key( (string) $context_value ); | |
| 173 | + if ( $role ) { | |
| 174 | + $context_roles = array( $role ); | |
| 175 | + } | |
| 176 | + } | |
| 177 | + | |
| 178 | + if ( ! empty( $context_roles ) ) { | |
| 179 | + $runtime = $settings['_jfb_runtime'] ?? array(); | |
| 180 | + $block_attrs = $settings['_jfb_block_attrs'] ?? array(); | |
| 181 | + $validate_dynamic = apply_filters( | |
| 182 | + 'jet-form-builder/generators/get-from-users/validate_dynamic_roles', | |
| 183 | + true, | |
| 184 | + $context_roles, | |
| 185 | + $settings, | |
| 186 | + $context, | |
| 187 | + $runtime, | |
| 188 | + $block_attrs | |
| 176 | 189 | ); |
| 177 | 190 | |
| 191 | + if ( ! $validate_dynamic ) { | |
| 192 | + $settings['roles'] = array_values( $context_roles ); | |
| 193 | + | |
| 194 | + return $this->generate( $settings ); | |
| 195 | + } | |
| 196 | + | |
| 197 | + $registered_roles = $this->get_registered_roles(); | |
| 198 | + $allowed_roles = $runtime['allowed_roles'] ?? array(); | |
| 199 | + $allowed_roles = apply_filters( | |
| 200 | + 'jet-form-builder/generators/get-from-users/allowed-roles', | |
| 201 | + $allowed_roles, | |
| 202 | + $context_roles, | |
| 203 | + $settings, | |
| 204 | + $context, | |
| 205 | + $runtime, | |
| 206 | + $block_attrs | |
| 207 | + ); | |
| 208 | + $allowed_roles = $this->sanitize_roles_list( $allowed_roles ); | |
| 209 | + $context_roles = array_intersect( $context_roles, $registered_roles ); | |
| 210 | + | |
| 211 | + if ( ! empty( $allowed_roles ) ) { | |
| 212 | + $context_roles = array_intersect( $context_roles, $allowed_roles ); | |
| 213 | + } else { | |
| 214 | + $context_roles = array(); | |
| 215 | + } | |
| 216 | + | |
| 217 | + $saved_roles = $this->normalize_saved_roles( $settings['roles'] ?? array() ); | |
| 218 | + $roles = empty( $saved_roles ) ? $context_roles : array_intersect( $context_roles, $saved_roles ); | |
| 219 | + | |
| 178 | 220 | if ( ! empty( $roles ) ) { |
| 179 | 221 | $settings['roles'] = array_values( $roles ); |
| 180 | 222 | } |
| 181 | - } else { | |
| 182 | - $role = sanitize_key( (string) $context_value ); | |
| 183 | - if ( $role ) { | |
| 184 | - $settings['roles'] = array( $role ); | |
| 185 | - } | |
| 186 | 223 | } |
| 187 | 224 | } |
| 188 | 225 | |
| 189 | 226 | return $this->generate( $settings ); |
| 227 | + } | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * Normalize configured roles into a sanitized list. | |
| 231 | + * | |
| 232 | + * @param mixed $saved_roles Configured roles. | |
| 233 | + * | |
| 234 | + * @return array | |
| 235 | + */ | |
| 236 | + private function normalize_saved_roles( $saved_roles ): array { | |
| 237 | + if ( is_array( $saved_roles ) ) { | |
| 238 | + return $this->sanitize_roles_list( $saved_roles ); | |
| 239 | + } | |
| 240 | + | |
| 241 | + return $this->sanitize_roles_list( | |
| 242 | + array_map( 'trim', explode( ',', (string) $saved_roles ) ) | |
| 243 | + ); | |
| 244 | + } | |
| 245 | + | |
| 246 | + /** | |
| 247 | + * Sanitize a list of role slugs. | |
| 248 | + * | |
| 249 | + * @param mixed $roles List of roles. | |
| 250 | + * | |
| 251 | + * @return array | |
| 252 | + */ | |
| 253 | + private function sanitize_roles_list( $roles ): array { | |
| 254 | + if ( ! is_array( $roles ) ) { | |
| 255 | + return array(); | |
| 256 | + } | |
| 257 | + | |
| 258 | + $roles = array_filter( | |
| 259 | + array_map( | |
| 260 | + static function ( $role ) { | |
| 261 | + return sanitize_key( (string) $role ); | |
| 262 | + }, | |
| 263 | + $roles | |
| 264 | + ) | |
| 265 | + ); | |
| 266 | + | |
| 267 | + return array_values( array_unique( $roles ) ); | |
| 268 | + } | |
| 269 | + | |
| 270 | + /** | |
| 271 | + * Return the registered WordPress role slugs. | |
| 272 | + * | |
| 273 | + * @return array | |
| 274 | + */ | |
| 275 | + private function get_registered_roles(): array { | |
| 276 | + $roles = wp_roles(); | |
| 277 | + | |
| 278 | + if ( ! $roles || empty( $roles->roles ) || ! is_array( $roles->roles ) ) { | |
| 279 | + return array(); | |
| 280 | + } | |
| 281 | + | |
| 282 | + return $this->sanitize_roles_list( array_keys( $roles->roles ) ); | |
| 190 | 283 | } |
| 191 | 284 | |
| 192 | 285 | /** |
| 193 | 286 | * Returns WP roles as options array for multi-select. |