Skip to content

Commit

Permalink
Merge pull request #1510 from CMB2/jt/fix-serialized-values
Browse files Browse the repository at this point in the history
Jt/fix serialized values
  • Loading branch information
jtsternberg committed Apr 2, 2024
2 parents a6ee0ed + 419646b commit 3a13dec
Show file tree
Hide file tree
Showing 12 changed files with 1,108 additions and 840 deletions.
2 changes: 1 addition & 1 deletion composer.json
Expand Up @@ -24,7 +24,7 @@
"source": "http://wordpress.org/support/plugin/cmb2"
},
"require": {
"php": ">5.2.4"
"php": ">7.4"
},
"suggest": {
"composer/installers": "~1.0"
Expand Down
1,535 changes: 752 additions & 783 deletions composer.lock

Large diffs are not rendered by default.

47 changes: 21 additions & 26 deletions includes/CMB2.php
Expand Up @@ -20,6 +20,14 @@
*/
class CMB2 extends CMB2_Base {

/**
* Supported CMB2 object types
*
* @var array
* @since 2.11.0
*/
protected $core_object_types = array( 'post', 'user', 'comment', 'term', 'options-page' );

/**
* The object properties name.
*
Expand Down Expand Up @@ -1098,8 +1106,7 @@ public function mb_object_type() {
}

// Get our object type.
$supported_types = array( 'post', 'user', 'comment', 'term', 'options-page' );
$mb_object_type = in_array( $found_type, $supported_types, true )
$mb_object_type = $this->is_supported_core_object_type( $found_type )
? $found_type
: 'post';

Expand Down Expand Up @@ -1565,30 +1572,7 @@ public function add_group_field( $parent_field_id, array $field, $position = 0 )
* @return void
*/
protected function field_actions( $field ) {
switch ( $field['type'] ) {
case 'file':
case 'file_list':
// Initiate attachment JS hooks.
add_filter( 'wp_prepare_attachment_for_js', array( 'CMB2_Type_File_Base', 'prepare_image_sizes_for_js' ), 10, 3 );
break;

case 'oembed':
// Initiate oembed Ajax hooks.
cmb2_ajax();
break;

case 'group':
if ( empty( $field['render_row_cb'] ) ) {
$field['render_row_cb'] = array( $this, 'render_group_callback' );
}
break;
case 'colorpicker':
// https://github.com/JayWood/CMB2_RGBa_Picker
// Dequeue the rgba_colorpicker custom field script if it is used,
// since we now enqueue our own more current version.
add_action( 'admin_enqueue_scripts', array( 'CMB2_Type_Colorpicker', 'dequeue_rgba_colorpicker_script' ), 99 );
break;
}
$field = CMB2_Hookup_Field::init( $field, $this );

if ( isset( $field['column'] ) && false !== $field['column'] ) {
$field = $this->define_field_column( $field );
Expand Down Expand Up @@ -1809,6 +1793,16 @@ public function is_alternate_context_box() {
return $this->prop( 'context' ) && in_array( $this->prop( 'context' ), array( 'form_top', 'before_permalink', 'after_title', 'after_editor' ), true );
}

/**
* Whether given object type is one of the core supported object types.
*
* @since 2.11.0
* @return bool
*/
public function is_supported_core_object_type( $object_type ) {
return in_array( $object_type, $this->core_object_types, true );
}

/**
* Magic getter for our object.
*
Expand All @@ -1821,6 +1815,7 @@ public function __get( $property ) {
case 'updated':
case 'has_columns':
case 'tax_metaboxes_to_remove':
case 'core_object_types':
return $this->{$property};
default:
return parent::__get( $property );
Expand Down
25 changes: 13 additions & 12 deletions includes/CMB2_Field_Display.php
Expand Up @@ -318,25 +318,26 @@ class CMB2_Display_Text_Date_Timezone extends CMB2_Field_Display {
* @since 2.2.2
*/
protected function _display() {
$field = $this->field;

if ( empty( $this->value ) ) {
return;
}

$datetime = maybe_unserialize( $this->value );
$this->value = $tzstring = '';

if ( $datetime && $datetime instanceof DateTime ) {
$tz = $datetime->getTimezone();
$tzstring = $tz->getName();
$this->value = $datetime->getTimestamp();
$datetime = CMB2_Utils::get_datetime_from_value( $this->value );
if ( ! $datetime || ! $datetime instanceof DateTime ) {
return;
}

$date = $this->field->get_timestamp_format( 'date_format', $this->value );
$time = $this->field->get_timestamp_format( 'time_format', $this->value );
$date = $datetime->format( stripslashes( $this->field->args( 'date_format' ) ) );
$time = $datetime->format( stripslashes( $this->field->args( 'time_format' ) ) );
$timezone = $datetime->getTimezone()->getName();

echo $date, ( $time ? ' ' . $time : '' ), ( $tzstring ? ', ' . $tzstring : '' );
echo $date;
if ( $time ) {
echo ' ' . $time;
}
if ( $timezone ) {
echo ', ' . $timezone;
}
}
}

Expand Down
200 changes: 200 additions & 0 deletions includes/CMB2_Hookup_Field.php
@@ -0,0 +1,200 @@
<?php
/**
* CMB2 Hookup Field
*
* Adds necessary hooks for certain field types.
*
* @since 2.11.0
*
* @category WordPress_Plugin
* @package CMB2
* @author CMB2 team
* @license GPL-2.0+
* @link https://cmb2.io
*/
class CMB2_Hookup_Field {

/**
* Field id.
*
* @var string
* @since 2.11.0
*/
protected $field_id;

/**
* CMB2 object id.
*
* @var string
* @since 2.11.0
*/
protected $cmb_id;

/**
* The object type we are performing the hookup for
*
* @var string
* @since 2.11.0
*/
protected $object_type = 'post';

/**
* Initialize all hooks for the given field.
*
* @since 2.11.0
* @param array $field The field arguments array.
* @param CMB2 $cmb The CMB2 object.
* @return array The field arguments array.
*/
public static function init( $field, CMB2 $cmb ) {
switch ( $field['type'] ) {
case 'file':
case 'file_list':
// Initiate attachment JS hooks.
add_filter( 'wp_prepare_attachment_for_js', array( 'CMB2_Type_File_Base', 'prepare_image_sizes_for_js' ), 10, 3 );
break;

case 'oembed':
// Initiate oembed Ajax hooks.
cmb2_ajax();
break;

case 'group':
if ( empty( $field['render_row_cb'] ) ) {
$field['render_row_cb'] = array( $cmb, 'render_group_callback' );
}
break;
case 'colorpicker':
// https://github.com/JayWood/CMB2_RGBa_Picker
// Dequeue the rgba_colorpicker custom field script if it is used,
// since we now enqueue our own more current version.
add_action( 'admin_enqueue_scripts', array( 'CMB2_Type_Colorpicker', 'dequeue_rgba_colorpicker_script' ), 99 );
break;

case 'text_datetime_timestamp_timezone':
foreach ( $cmb->box_types() as $object_type ) {
if ( ! $cmb->is_supported_core_object_type( $object_type ) ) {
// Ignore post-types...
continue;
}

if ( empty( $field['field_hookup_instance'][ $object_type ] ) ) {
$instance = new self( $field, $object_type, $cmb );
$method = 'options-page' === $object_type
? 'text_datetime_timestamp_timezone_option_back_compat'
: 'text_datetime_timestamp_timezone_back_compat';

$field['field_hookup_instance'][ $object_type ] = array( $instance, $method );
}

if ( false === $field['field_hookup_instance'][ $object_type ] ) {
// If set to false, no need to filter.
// This can be set if you have updated your use of the field type value to
// assume the JSON value.
continue;
}

if ( 'options-page' === $object_type ) {
$option_name = $cmb->object_id();
add_filter( "pre_option_{$option_name}", $field['field_hookup_instance'][ $object_type ], 10, 3 );
continue;
}

add_filter( "get_{$object_type}_metadata", $field['field_hookup_instance'][ $object_type ], 10, 5 );
}
break;
}

return $field;
}

/**
* Constructor
*
* @since 2.11.0
* @param CMB2 $cmb The CMB2 object to hookup.
*/
public function __construct( $field, $object_type, CMB2 $cmb ) {
$this->field_id = $field['id'];
$this->object_type = $object_type;
$this->cmb_id = $cmb->cmb_id;
}

/**
* Adds a back-compat shim for text_datetime_timestamp_timezone field type values.
*
* Handles old serialized DateTime values, as well as the new JSON formatted values.
*
* @since 2.11.0
*
* @param mixed $value The value of the metadata.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Meta key.
* @param bool $single Whether to return a single value.
* @param string $meta_type Type of object metadata is for.
* @return mixed Maybe reserialized value.
*/
public function text_datetime_timestamp_timezone_back_compat( $value, $object_id, $meta_key, $single, $meta_type ) {
if ( $meta_key === $this->field_id ) {
remove_filter( "get_{$meta_type}_metadata", [ $this, __FUNCTION__ ], 10, 5 );
$value = get_metadata( $meta_type, $object_id, $meta_key, $single );
add_filter( "get_{$meta_type}_metadata", [ $this, __FUNCTION__ ], 10, 5 );

$value = $this->reserialize_safe_value( $value );
}

return $value;
}

/**
* Adds a back-compat shim for text_datetime_timestamp_timezone field type values on options pages.
*
* Handles old serialized DateTime values, as well as the new JSON formatted values.
*
* @since 2.11.0
*
* @param mixed $value The value of the option.
* @param string $option Option name.
* @param mixed $default_value Default value.
* @return mixed The updated value.
*/
public function text_datetime_timestamp_timezone_option_back_compat( $value, $option, $default_value ) {
remove_filter( "pre_option_{$option}", [ $this, __FUNCTION__ ], 10, 3 );
$value = get_option( $option, $default_value );
add_filter( "pre_option_{$option}", [ $this, __FUNCTION__ ], 10, 3 );

if ( ! empty( $value ) && is_array( $value ) ) {

// Loop fields and update values for all text_datetime_timestamp_timezone fields.
foreach ( CMB2_Boxes::get( $this->cmb_id )->prop( 'fields' ) as $field ) {
if (
'text_datetime_timestamp_timezone' === $field['type']
&& ! empty( $value[ $field['id'] ] )
) {
$value[ $field['id'] ] = $this->reserialize_safe_value( $value[ $field['id'] ] );
}
}
}

return $value;
}

/**
* Reserialize a value to a safe serialized DateTime value.
*
* @since 2.11.0
*
* @param mixed $value The value to check.
* @return mixed The value, possibly reserialized.
*/
protected function reserialize_safe_value( $value ) {
if ( is_array( $value ) ) {
return array_map( [ $this, 'reserialize_safe_value' ], $value );
}

$updated_val = CMB2_Utils::get_datetime_from_value( $value );
$value = $updated_val ? serialize( $updated_val ) : '';

return $value;
}
}
2 changes: 1 addition & 1 deletion includes/CMB2_Sanitize.php
Expand Up @@ -399,7 +399,7 @@ public function text_datetime_timestamp_timezone( $repeat = false ) {
} else {
$datetime->setTimezone( new DateTimeZone( $tzstring ) );
$utc_stamp = date_timestamp_get( $datetime ) - $offset;
$this->value = serialize( $datetime );
$this->value = json_encode( $datetime );
}

if ( $this->field->group ) {
Expand Down

0 comments on commit 3a13dec

Please sign in to comment.