Skip to content

Commit

Permalink
Fix text_datetime_timestamp_timezone repeatable group saving error, a…
Browse files Browse the repository at this point in the history
…nd supporting tests. Fixes #330
  • Loading branch information
jtsternberg committed Nov 24, 2015
1 parent af75132 commit fcb112c
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 66 deletions.
22 changes: 17 additions & 5 deletions includes/CMB2.php
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ public function save_group( $args ) {
$group_vals = $field_group->sanitization_cb( $this->data_to_save[ $base_id ] );
$saved = array();
$field_group->index = 0;
$field_group->data_to_save = $this->data_to_save;

foreach ( array_values( $field_group->fields() ) as $field_args ) {
$field = new CMB2_Field( array(
Expand All @@ -623,11 +624,22 @@ public function save_group( $args ) {
// Sanitize
$new_val = $field->sanitization_cb( $new_val );

if ( 'file' == $field->type() && is_array( $new_val ) ) {
// Add image ID to the array stack
$saved[ $field_group->index ][ $new_val['field_id'] ] = $new_val['attach_id'];
// Reset var to url string
$new_val = $new_val['url'];
if ( is_array( $new_val ) && $field->args( 'has_supporting_data' ) ) {
if ( $field->args( 'repeatable' ) ) {
$_new_val = array();
foreach ( $new_val as $group_index => $grouped_data ) {
// Add the supporting data to the $saved array stack
$saved[ $field_group->index ][ $grouped_data['supporting_field_id'] ][] = $grouped_data['supporting_field_value'];
// Reset var to the actual value
$_new_val[ $group_index ] = $grouped_data['value'];
}
$new_val = $_new_val;
} else {
// Add the supporting data to the $saved array stack
$saved[ $field_group->index ][ $new_val['supporting_field_id'] ] = $new_val['supporting_field_value'];
// Reset var to the actual value
$new_val = $new_val['value'];
}
}

// Get old value
Expand Down
11 changes: 11 additions & 0 deletions includes/CMB2_Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,17 @@ public function _set_field_defaults( $args ) {

}

$args['has_supporting_data'] = in_array(
$args['type'],
array(
// See CMB2_Sanitize::_save_utc_value()
'file',
// CMB2_Sanitize::_save_file_id_value()/CMB2_Sanitize::_get_group_file_value_array()
'text_datetime_timestamp_timezone',
),
true
);

return $args;
}

Expand Down
174 changes: 121 additions & 53 deletions includes/CMB2_Sanitize.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ public function text_datetime_timestamp( $repeat = false ) {
return '';
}

if ( $repeat_value = $this->_check_repeat( __FUNCTION__, $repeat ) ) {
$repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
if ( false !== $repeat_value ) {
return $repeat_value;
}

Expand All @@ -231,13 +232,22 @@ public function text_datetime_timestamp( $repeat = false ) {
* @return string Timestring
*/
public function text_datetime_timestamp_timezone( $repeat = false ) {
static $utc_values = array();

$test = is_array( $this->value ) ? array_filter( $this->value ) : '';
if ( empty( $test ) ) {
return '';
}

if ( $repeat_value = $this->_check_repeat( __FUNCTION__, $repeat ) ) {
$utc_key = $this->field->_id() . '_utc';

$repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
if ( false !== $repeat_value ) {
if ( ! empty( $utc_values[ $utc_key ] ) ) {
$this->_save_utc_value( $utc_key, $utc_values[ $utc_key ] );
unset( $utc_values[ $utc_key ] );
}

return $repeat_value;
}

Expand Down Expand Up @@ -268,10 +278,34 @@ public function text_datetime_timestamp_timezone( $repeat = false ) {
$full_date = $this->value['date'] . ' ' . $this->value['time'];

try {

$datetime = date_create_from_format( $full_format, $full_date );
$datetime->setTimezone( new DateTimeZone( $tzstring ) );
$this->value = serialize( $datetime );

if ( ! is_object( $datetime ) ) {
$this->value = $utc_stamp = '';
} else {
$timestamp = $datetime->setTimezone( new DateTimeZone( $tzstring ) )->getTimestamp();
$utc_stamp = $timestamp - $offset;
$this->value = serialize( $datetime );
}

if ( $this->field->group ) {
$this->value = array(
'supporting_field_value' => $utc_stamp,
'supporting_field_id' => $utc_key,
'value' => $this->value,
);
} else {
// Save the utc timestamp supporting field
if ( $repeat ) {
$utc_values[ $utc_key ][] = $utc_stamp;
} else {
$this->_save_utc_value( $utc_key, $utc_stamp );
}
}

} catch ( Exception $e ) {
$this->value = '';
cmb2_utils()->log_if_debug( __METHOD__, __LINE__, $e->getMessage() );
}

Expand All @@ -293,77 +327,100 @@ public function textarea() {
* @return string Sanitized data
*/
public function textarea_code( $repeat = false ) {
if ( $repeat_value = $this->_check_repeat( __FUNCTION__, $repeat ) ) {
$repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
if ( false !== $repeat_value ) {
return $repeat_value;
}

return htmlspecialchars_decode( stripslashes( $this->value ) );
}

/**
* Peforms saving of `file` attachement's ID
* Handles saving of attachment post ID and sanitizing file url
* @since 1.1.0
* @return string Sanitized url
*/
public function _save_file_id() {
$group = $this->field->group;
$args = $this->field->args();
$args['id'] = $args['_id'] . '_id';
public function file() {
$file_id_key = $this->field->_id() . '_id';

unset( $args['_id'], $args['_name'] );
// And get new field object
$field = new CMB2_Field( array(
'field_args' => $args,
'group_field' => $group,
'object_id' => $this->field->object_id,
'object_type' => $this->field->object_type,
) );
$id_key = $field->_id();
$id_val_old = $field->escaped_value( 'absint' );
if ( $this->field->group ) {
// Return an array with url/id if saving a group field
$this->value = $this->_get_group_file_value_array( $file_id_key );
} else {
$this->_save_file_id_value( $file_id_key );
$this->text_url();
}

$alldata = $this->field->data_to_save;
return $this->value;
}

if ( $group ) {
// Check group $alldata data
$i = $group->index;
$base_id = $group->_id();
$id_val = isset( $alldata[ $base_id ][ $i ][ $id_key ] ) ? absint( $alldata[ $base_id ][ $i ][ $id_key ] ) : 0;
/**
* Gets the values for the `file` field type from the data being saved.
* @since 2.2.0
*/
public function _get_group_file_value_array( $id_key ) {
$alldata = $this->field->group->data_to_save;
$base_id = $this->field->group->_id();
$i = $this->field->group->index;

// Check group $alldata data
$id_val = isset( $alldata[ $base_id ][ $i ][ $id_key ] )
? absint( $alldata[ $base_id ][ $i ][ $id_key ] )
: 0;

return array(
'value' => $this->text_url(),
'supporting_field_value' => $id_val,
'supporting_field_id' => $id_key,
);
}

} else {
// Check standard $alldata data
$id_val = isset( $alldata[ $field->id() ] ) ? $alldata[ $field->id() ] : null;
/**
* Peforms saving of `file` attachement's ID
* @since 1.1.0
*/
public function _save_file_id_value( $file_id_key ) {
$id_field = $this->_new_supporting_field( $file_id_key );

}
// Check standard data_to_save data
$id_val = isset( $this->field->data_to_save[ $file_id_key ] )
? $this->field->data_to_save[ $file_id_key ]
: null;

// If there is no ID saved yet, try to get it from the url
if ( $this->value && ! $id_val ) {
$id_val = cmb2_utils()->image_id_from_url( $this->value );
}

if ( $group ) {
return array(
'attach_id' => $id_val,
'field_id' => $id_key,
);
}
return $id_field->save_field( $id_val );
}

if ( $id_val && $id_val != $id_val_old ) {
return $field->update_data( $id_val );
} elseif ( empty( $id_val ) && $id_val_old ) {
return $field->remove_data( $id_val_old );
}
/**
* Peforms saving of `text_datetime_timestamp_timezone` utc timestamp
* @since 2.2.0
*/
public function _save_utc_value( $utc_key, $utc_stamp ) {
return $this->_new_supporting_field( $utc_key )->save_field( $utc_stamp );
}

/**
* Handles saving of attachment post ID and sanitizing file url
* @since 1.1.0
* @return string Sanitized url
* Returns a new, supporting CMB2_Field object based on a new field id.
* @since 2.2.0
*/
public function file() {
$id_value = $this->_save_file_id();
$clean = $this->text_url();
public function _new_supporting_field( $new_field_id ) {
$args = $this->field->args();
unset( $args['_id'], $args['_name'] );

// Return an array with url/id if saving a group field
return $this->field->group ? array_merge( array( 'url' => $clean ), $id_value ) : $clean;
$args['id'] = $new_field_id;
$args['sanitization_cb'] = false;

// And get new field object
return new CMB2_Field( array(
'field_args' => $args,
'group_field' => $this->field->group,
'object_id' => $this->field->object_id,
'object_type' => $this->field->object_type,
) );
}

/**
Expand All @@ -375,13 +432,24 @@ public function file() {
*/
public function _check_repeat( $method, $repeat ) {
if ( $repeat || ! $this->field->args( 'repeatable' ) ) {
return;
return false;
}

$values_array = $this->value;

$new_value = array();
foreach ( $this->value as $iterator => $val ) {
$new_value[] = $this->$method( $val, true );
foreach ( $values_array as $iterator => $this->value ) {
if ( $this->value ) {
$val = $this->$method( true );
if ( ! empty( $val ) ) {
$new_value[] = $val;
}
}
}
return $new_value;

$this->value = $new_value;

return empty( $this->value ) ? null : $this->value;
}

/**
Expand Down
12 changes: 6 additions & 6 deletions includes/CMB2_Types.php
Original file line number Diff line number Diff line change
Expand Up @@ -594,18 +594,18 @@ public function text_datetime_timestamp_timezone( $args = array() ) {
$args['value'] = '';
}

$datetime = unserialize( $args['value'] );
$args['value'] = $tzstring = '';
$datetime = maybe_unserialize( $args['value'] );
$value = $tzstring = '';

if ( $datetime && $datetime instanceof DateTime ) {
$tz = $datetime->getTimezone();
$tzstring = $tz->getName();
$args['value'] = $datetime->getTimestamp() + $tz->getOffset( new DateTime( 'NOW' ) );
$tz = $datetime->getTimezone();
$tzstring = $tz->getName();
$value = $datetime->getTimestamp();
}

$timestamp_args = wp_parse_args( $args['text_datetime_timestamp'], array(
'desc' => '',
'value' => $args['value'],
'value' => $value,
) );

$timezone_args = wp_parse_args( $args['select_timezone'], array(
Expand Down
4 changes: 2 additions & 2 deletions tests/test-cmb-field.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ public function test_cmb2_label_cb_field_callback() {
public function test_cmb2_row_classes_field_callback_with_array() {
// Add row classes dynamically with a callback that returns an array
$classes = $this->field->row_classes();
$this->assertEquals( 'cmb-type-text cmb2-id-test-test table-layout type name desc before after options_cb options attributes protocols default select_all_button multiple repeatable inline on_front show_names date_format time_format description preview_size render_row_cb label_cb id before_field after_field row_classes _id _name', $classes );
$this->assertEquals( 'cmb-type-text cmb2-id-test-test table-layout type name desc before after options_cb options attributes protocols default select_all_button multiple repeatable inline on_front show_names date_format time_format description preview_size render_row_cb label_cb id before_field after_field row_classes _id _name has_supporting_data', $classes );
}

public function test_cmb2_default_field_callback_with_array() {
// Add row classes dynamically with a callback that returns an array
$default = $this->field->args( 'default' );
$this->assertEquals( 'type, name, desc, before, after, options_cb, options, attributes, protocols, default, select_all_button, multiple, repeatable, inline, on_front, show_names, date_format, time_format, description, preview_size, render_row_cb, label_cb, id, before_field, after_field, row_classes, _id, _name', $default );
$this->assertEquals( 'type, name, desc, before, after, options_cb, options, attributes, protocols, default, select_all_button, multiple, repeatable, inline, on_front, show_names, date_format, time_format, description, preview_size, render_row_cb, label_cb, id, before_field, after_field, row_classes, _id, _name, has_supporting_data', $default );
}

public function test_cmb2_row_classes_field_callback_with_string() {
Expand Down

0 comments on commit fcb112c

Please sign in to comment.