Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/Renderer/TangibleFieldsRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ protected function render_simple_field( array $field, string $type, mixed $value
'value' => $this->format_value_for_field( $value, $type ),
'description' => $field['help'] ?? $config['description'] ?? '',
'placeholder' => $field['placeholder'] ?? $config['placeholder'] ?? '',
'condition' => $config['condition'] ?? [],
];

// Add type-specific options.
Expand Down Expand Up @@ -403,6 +404,7 @@ protected function render_repeater_field( array $field, mixed $value, array $con
'value' => $value,
'sub_fields' => $sub_fields,
'layout' => $config['layout'] ?? 'table',
'condition' => $config['condition'] ?? [],
];

// Optional repeater settings.
Expand Down Expand Up @@ -439,9 +441,10 @@ protected function map_sub_fields( array $sub_fields ): array {
$tf_type = $this->sub_field_type_map[ $type ] ?? 'text';

$mapped_field = [
'type' => $tf_type,
'name' => $sub_field['name'],
'label' => $sub_field['label'] ?? ucfirst( str_replace( '_', ' ', $sub_field['name'] ) ),
'type' => $tf_type,
'name' => $sub_field['name'],
'label' => $sub_field['label'] ?? ucfirst( str_replace( '_', ' ', $sub_field['name'] ) ),
'condition' => $sub_field['condition'] ?? [],
];

// Add optional properties.
Expand Down Expand Up @@ -504,6 +507,7 @@ protected function build_field_config( array $field ): array {
'value' => $value,
'sub_fields' => $sub_fields,
'layout' => $config['layout'] ?? 'table',
'condition' => $config['condition'] ?? [],
];

if ( isset( $config['max_rows'] ) ) {
Expand All @@ -522,6 +526,7 @@ protected function build_field_config( array $field ): array {
'value' => $this->format_value_for_field( $value, $type ),
'description' => $field['help'] ?? $config['description'] ?? '',
'placeholder' => $field['placeholder'] ?? $config['placeholder'] ?? '',
'condition' => $config['condition'] ?? [],
];

// Add type-specific options.
Expand Down
236 changes: 236 additions & 0 deletions tests/phpunit/data-view.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
*/
class DataView_TestCase extends \WP_UnitTestCase {

public function setUp(): void {
parent::setUp();

if ( function_exists( 'tangible_fields' ) ) {
tangible_fields()->registered_fields = [];
}
}

/**
* ==========================================================================
* FieldTypeRegistry Tests
Expand Down Expand Up @@ -1843,6 +1851,234 @@ public function test_renderer_action_buttons_output_html(): void {
$this->assertStringContainsString( '>Archive</button>', $custom_html );
}

/**
* ==========================================================================
* TangibleFieldsRenderer Conditional Visibility Tests
* ==========================================================================
*/

/**
* @dataProvider condition_provider
*/
public function test_renderer_forwards_condition(
array $field_configs,
callable $build_layout,
string $lookup,
array $expected
): void {
if ( ! function_exists( 'tangible_fields' ) ) {
$this->markTestSkipped( 'Tangible Fields framework is not loaded.' );
}

$dataset = new DataSet();
foreach ( array_keys( $field_configs ) as $slug ) {
$dataset->add_string( $slug );
}

$layout = new Layout( $dataset );
$build_layout( $layout );

$renderer = new \Tangible\Renderer\TangibleFieldsRenderer();
$renderer->set_field_configs( $field_configs );

$renderer->render_editor( $layout, [] );

$config = $this->find_registered_field( $lookup );
$this->assertNotNull( $config, "Field '{$lookup}' should be registered with Tangible Fields" );
$this->assertEquals( $expected, $config['condition'] );
}

public function condition_provider(): array {
$condition = [
'action' => 'show',
'condition' => [ 'condition_flag' => [ '_eq' => 'true' ] ],
];

// Use same subfield for every repeater case
$sub_fields = [
[ 'name' => 'enabled', 'type' => 'boolean' ],
[ 'name' => 'amount', 'type' => 'integer', 'condition' => $condition ],
];

$in_section = fn( $layout, $slug ) => (
$layout->section(
'General',
fn( $section ) => $section->field( $slug )
)
);
$in_sidebar = fn( $layout, $slug ) => (
$layout->sidebar(
fn( $sidebar ) => $sidebar->field( $slug )
)
);

/**
* Each case is:
* - field_configs => configs registered on the renderer
* - build_layout => places the field(s) in the layout
* - lookup => field name to find in the registered tree
* - expected => condition expected on that field (empty array when none set)
*/
return [

'field forwards condition' => [
[
'condition_field' => [
'type' => 'string',
'condition' => $condition
]
],
fn( $layout ) => $in_section( $layout, 'condition_field' ),
'condition_field',
$condition,
],

'field absent defaults to empty' => [
[
'condition_field' => [
'type' => 'string'
]
],
fn( $layout ) => $in_section( $layout, 'condition_field' ),
'condition_field',
[],
],

'field in tab' => [
[
'condition_field' => [
'type' => 'string',
'condition' => $condition
]
],
fn( $layout ) => $layout->tabs(
fn( $tabs ) => $tabs->tab(
'Main',
fn( $tab ) => $tab->field( 'condition_field' )
)
),
'condition_field',
$condition,
],

'field in nested section' => [
[
'condition_field' => [
'type' => 'string',
'condition' => $condition
]
],
fn( $layout ) => $layout->section(
'Outer',
fn( $section ) => $section->section(
'Inner',
fn( $inner ) => $inner->field( 'condition_field' )
)
),
'condition_field',
$condition,
],

'field in sidebar' => [
[
'condition_field' => [
'type' => 'string',
'condition' => $condition
]
],
fn( $layout ) => $in_sidebar( $layout, 'condition_field' ),
'condition_field',
$condition,
],

'repeater forwards condition' => [
[
'condition_rows' => [
'type' => 'repeater',
'sub_fields' => $sub_fields,
'condition' => $condition
]
],
fn( $layout ) => $in_section( $layout, 'condition_rows' ),
'condition_rows',
$condition,
],

'repeater in sidebar forwards condition' => [
[
'condition_rows' => [
'type' => 'repeater',
'sub_fields' => $sub_fields,
'condition' => $condition
]
],
fn( $layout ) => $in_sidebar( $layout, 'condition_rows' ),
'condition_rows',
$condition,
],

'repeater sub-field forwards condition' => [
[
'condition_rows' => [
'type' => 'repeater',
'sub_fields' => $sub_fields
]
],
fn( $layout ) => $in_section( $layout, 'condition_rows' ),
'amount',
$condition,
],

'repeater sub-field absent defaults to empty' => [
[
'condition_rows' => [
'type' => 'repeater',
'sub_fields' => $sub_fields
]
],
fn( $layout ) => $in_section( $layout, 'condition_rows' ),
'enabled',
[],
],
];
}

/**
* Find a field config by name anywhere in the registered fields tree
* (top-level fields, section/tab children, repeater sub-fields).
*
* The root call omits $configs; recursion passes the subtree to search.
*/
private function find_registered_field( string $name, ?array $configs = null ): ?array {
foreach ( $configs ?? tangible_fields()->registered_fields as $config ) {
if ( ! is_array( $config ) ) {
continue;
}

if ( ( $config['name'] ?? null ) === $name ) {
return $config;
}

foreach ( [ 'fields', 'sub_fields' ] as $children ) {
if ( ! empty( $config[ $children ] ) && is_array( $config[ $children ] )
&& $found = $this->find_registered_field( $name, $config[ $children ] )
) {
return $found;
}
}

foreach ( $config['tabs'] ?? [] as $tab ) {
if ( ! empty( $tab['fields'] )
&& $found = $this->find_registered_field( $name, $tab['fields'] )
) {
return $found;
}
}
}

return null;
}

/**
* ==========================================================================
* DataView with TangibleFieldsRenderer Tests
Expand Down