Skip to content
This repository has been archived by the owner on Nov 6, 2022. It is now read-only.

Repeater row count and row index function. #429

Merged
merged 14 commits into from
Sep 17, 2019
Merged
Show file tree
Hide file tree
Changes from 10 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: 11 additions & 0 deletions php/blocks/class-field.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,17 @@ public function cast_value( $value ) {
* @return string $value The value to echo.
*/
public function cast_value_to_string( $value ) {
/**
* Filters the value of a field when being output as a string.
*
* The result of this filter should be a string. Even if it isn't, it will be run
* through strval() anyway.
*
* @param mixed $value The value to cast as a string.
* @param Field $field This field.
*/
$value = apply_filters( 'block_lab_cast_field_value_to_string', $value, $this );
kienstra marked this conversation as resolved.
Show resolved Hide resolved

if ( is_array( $value ) ) {
return implode( ', ', $value );
}
Expand Down
9 changes: 8 additions & 1 deletion php/blocks/class-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,10 @@ public function render_block_template( $block, $attributes ) {
foreach ( $block->fields as $field ) {
if ( isset( $field->settings['sub_fields'] ) ) {
$sub_field_settings = $field->settings['sub_fields'];
$rows = $attributes[ $field->name ]['rows'];
}

if ( isset( $attributes[ $field->name ]['rows'] ) ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this conditional could be moved above to line 309, instead of creating a new if block:

if ( isset( $field->settings['sub_fields'] ) && isset( $attributes[ $field->name ]['rows'] ) ) {

Right now, it's possible (though unlikely) for $sub_field_settings to be unset at line 318.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 39fade9.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks 😄

$rows = $attributes[ $field->name ]['rows'];

// In each row, apply a field's default value if a value doesn't exist in the attributes.
foreach ( $rows as $row_index => $row ) {
Expand Down Expand Up @@ -463,6 +466,10 @@ public function block_template( $name, $type = 'block' ) {
if ( ! current_user_can( 'edit_posts' ) || ! isset( $templates[0] ) ) {
return;
}
// Hide the template not found notice on the frontend, unless WP_DEBUG is enabled.
lukecarbis marked this conversation as resolved.
Show resolved Hide resolved
if ( ! is_admin() && ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) {
return;
}
printf(
'<div class="notice notice-warning">%s</div>',
wp_kses_post(
Expand Down
57 changes: 54 additions & 3 deletions php/blocks/controls/class-repeater.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,28 @@ class Repeater extends Control_Abstract {
/**
* Field variable type.
*
* The Repeater control is an array of objects, with each row being an object.
* For example, a repeater with one row might be [ { 'example-text': 'Foo', 'example-image': 4232 } ].
* The Repeater control is an array of arrays, with each row being its own array.
* For example, a repeater with two rows might be:
* [ 'rows': [ 0: [ 'example-text': 'Foo', 'example-image': 42 ], 1: [ 'example-text': 'Bar', 'example-image': 32 ] ] ].
*
* @var string
*/
public $type = 'object';
public $type = 'array';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good thing to bring up. In PHP, this would be an array(), and in JS it'd be an object. I don't see many examples of array or object attributes in Core blocks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah – makes much more sense for $type to represent the Javascript type, rather than the PHP type. Addressed in 2b61b64.


/**
* Repeater constructor.
*/
public function __construct() {
parent::__construct();
$this->label = __( 'Repeater', 'block-lab' );
$this->register_hooks();
}

/**
* Register all the hooks.
*/
public function register_hooks() {
add_filter( 'block_lab_cast_field_value_to_string', array( $this, 'cast_as_string' ), 10, 2 );
}

/**
Expand All @@ -63,4 +72,46 @@ public function register_settings() {
)
);
}

/**
* Remove empty placeholder rows.
*
* @param mixed $value The value to either make available as a variable or echoed on the front-end template.
* @param bool $echo Whether this will be echoed.
* @return mixed $value The value to be made available or echoed on the front-end template.
*/
public function validate( $value, $echo ) {
unset( $echo );

if ( isset( $value['rows'] ) ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about something like:

array_filter( $value['rows'] );

It looks like that removes empty array values, like '' => ''

Copy link
Member Author

@lukecarbis lukecarbis Sep 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be nice, except that array_filter filters empty values (not empty keys) – so if there were a repeater with an empty value, that item in the array would be removed.

We could supply a custom callback to array_filter which targets empty keys, or alternatively use something like this:

array_diff_key( $value['rows'][ $key ], array_flip( array( '', 0 ) ) );

but ultimately, I think just unsetting the two is a better, simpler, solution.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it removes empty values. That's not good.

foreach ( $value['rows'] as $key => $row ) {
unset( $value['rows'][ $key ][''] );
unset( $value['rows'][ $key ][0] );
}
}

return $value;
}

/**
* Show a warning if someone tries to use block_field() with a repeater.
*
* @param mixed $value The value to cast as a string.
* @param Field $field The field that is being cast.
* @return string
*/
public function cast_as_string( $value, $field ) {
if ( 'repeater' === $field->control ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
return sprintf(
// translators: Placeholders are the opening and closing anchor tags of a link.
__( '⚠️ Please use Block Lab\'s %1$srepeater functions%2$s to display repeater fields in your template.', 'block-lab' ),
'<a href="https://getblocklab.com/docs/fields/repeater/">',
'</a>'
);
}
}

return $value;
}
}
37 changes: 37 additions & 0 deletions php/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,43 @@ function reset_block_rows( $name ) {
block_lab()->loop()->reset( $name );
}

/**
* Return the total amount of rows in a repeater.
*
* @param string $name The name of the repeater field.
* @return int|bool The total amount of rows. False if the repeater isn't found.
*/
function block_row_count( $name ) {
global $block_lab_attributes;

if ( ! isset( $block_lab_attributes[ $name ]['rows'] ) ) {
return false;
}

return count( $block_lab_attributes[ $name ]['rows'] );
}

/**
* Return the index of the current repeater row.
*
* Note: The index is zero-based, which means that the first row in a repeater has
* an index of 0, the second row has an index of 1, and so on.
*
* @param string $name (Optional) The name of the repeater field.
* @return int|bool The index of the row. False if the repeater isn't found.
*/
function block_row_index( $name = '' ) {
if ( '' === $name ) {
$name = block_lab()->loop()->active;
}

if ( ! isset( block_lab()->loop()->loops[ $name ] ) ) {
return false;
}

return block_lab()->loop()->loops[ $name ];
}

/**
* Return the value of a sub-field.
*
Expand Down
2 changes: 1 addition & 1 deletion tests/php/unit/blocks/controls/test-class-repeater.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function setUp() {
public function test_construct() {
$this->assertEquals( 'Repeater', $this->instance->label );
$this->assertEquals( 'repeater', $this->instance->name );
$this->assertEquals( 'object', $this->instance->type );
$this->assertEquals( 'array', $this->instance->type );
}

/**
Expand Down