Skip to content

Commit 3a13dec

Browse files
authored
Merge pull request #1510 from CMB2/jt/fix-serialized-values
Jt/fix serialized values
2 parents a6ee0ed + 419646b commit 3a13dec

12 files changed

+1108
-840
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"source": "http://wordpress.org/support/plugin/cmb2"
2525
},
2626
"require": {
27-
"php": ">5.2.4"
27+
"php": ">7.4"
2828
},
2929
"suggest": {
3030
"composer/installers": "~1.0"

composer.lock

Lines changed: 752 additions & 783 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

includes/CMB2.php

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
*/
2121
class CMB2 extends CMB2_Base {
2222

23+
/**
24+
* Supported CMB2 object types
25+
*
26+
* @var array
27+
* @since 2.11.0
28+
*/
29+
protected $core_object_types = array( 'post', 'user', 'comment', 'term', 'options-page' );
30+
2331
/**
2432
* The object properties name.
2533
*
@@ -1098,8 +1106,7 @@ public function mb_object_type() {
10981106
}
10991107

11001108
// Get our object type.
1101-
$supported_types = array( 'post', 'user', 'comment', 'term', 'options-page' );
1102-
$mb_object_type = in_array( $found_type, $supported_types, true )
1109+
$mb_object_type = $this->is_supported_core_object_type( $found_type )
11031110
? $found_type
11041111
: 'post';
11051112

@@ -1565,30 +1572,7 @@ public function add_group_field( $parent_field_id, array $field, $position = 0 )
15651572
* @return void
15661573
*/
15671574
protected function field_actions( $field ) {
1568-
switch ( $field['type'] ) {
1569-
case 'file':
1570-
case 'file_list':
1571-
// Initiate attachment JS hooks.
1572-
add_filter( 'wp_prepare_attachment_for_js', array( 'CMB2_Type_File_Base', 'prepare_image_sizes_for_js' ), 10, 3 );
1573-
break;
1574-
1575-
case 'oembed':
1576-
// Initiate oembed Ajax hooks.
1577-
cmb2_ajax();
1578-
break;
1579-
1580-
case 'group':
1581-
if ( empty( $field['render_row_cb'] ) ) {
1582-
$field['render_row_cb'] = array( $this, 'render_group_callback' );
1583-
}
1584-
break;
1585-
case 'colorpicker':
1586-
// https://github.com/JayWood/CMB2_RGBa_Picker
1587-
// Dequeue the rgba_colorpicker custom field script if it is used,
1588-
// since we now enqueue our own more current version.
1589-
add_action( 'admin_enqueue_scripts', array( 'CMB2_Type_Colorpicker', 'dequeue_rgba_colorpicker_script' ), 99 );
1590-
break;
1591-
}
1575+
$field = CMB2_Hookup_Field::init( $field, $this );
15921576

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

1796+
/**
1797+
* Whether given object type is one of the core supported object types.
1798+
*
1799+
* @since 2.11.0
1800+
* @return bool
1801+
*/
1802+
public function is_supported_core_object_type( $object_type ) {
1803+
return in_array( $object_type, $this->core_object_types, true );
1804+
}
1805+
18121806
/**
18131807
* Magic getter for our object.
18141808
*
@@ -1821,6 +1815,7 @@ public function __get( $property ) {
18211815
case 'updated':
18221816
case 'has_columns':
18231817
case 'tax_metaboxes_to_remove':
1818+
case 'core_object_types':
18241819
return $this->{$property};
18251820
default:
18261821
return parent::__get( $property );

includes/CMB2_Field_Display.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -318,25 +318,26 @@ class CMB2_Display_Text_Date_Timezone extends CMB2_Field_Display {
318318
* @since 2.2.2
319319
*/
320320
protected function _display() {
321-
$field = $this->field;
322-
323321
if ( empty( $this->value ) ) {
324322
return;
325323
}
326324

327-
$datetime = maybe_unserialize( $this->value );
328-
$this->value = $tzstring = '';
329-
330-
if ( $datetime && $datetime instanceof DateTime ) {
331-
$tz = $datetime->getTimezone();
332-
$tzstring = $tz->getName();
333-
$this->value = $datetime->getTimestamp();
325+
$datetime = CMB2_Utils::get_datetime_from_value( $this->value );
326+
if ( ! $datetime || ! $datetime instanceof DateTime ) {
327+
return;
334328
}
335329

336-
$date = $this->field->get_timestamp_format( 'date_format', $this->value );
337-
$time = $this->field->get_timestamp_format( 'time_format', $this->value );
330+
$date = $datetime->format( stripslashes( $this->field->args( 'date_format' ) ) );
331+
$time = $datetime->format( stripslashes( $this->field->args( 'time_format' ) ) );
332+
$timezone = $datetime->getTimezone()->getName();
338333

339-
echo $date, ( $time ? ' ' . $time : '' ), ( $tzstring ? ', ' . $tzstring : '' );
334+
echo $date;
335+
if ( $time ) {
336+
echo ' ' . $time;
337+
}
338+
if ( $timezone ) {
339+
echo ', ' . $timezone;
340+
}
340341
}
341342
}
342343

includes/CMB2_Hookup_Field.php

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
<?php
2+
/**
3+
* CMB2 Hookup Field
4+
*
5+
* Adds necessary hooks for certain field types.
6+
*
7+
* @since 2.11.0
8+
*
9+
* @category WordPress_Plugin
10+
* @package CMB2
11+
* @author CMB2 team
12+
* @license GPL-2.0+
13+
* @link https://cmb2.io
14+
*/
15+
class CMB2_Hookup_Field {
16+
17+
/**
18+
* Field id.
19+
*
20+
* @var string
21+
* @since 2.11.0
22+
*/
23+
protected $field_id;
24+
25+
/**
26+
* CMB2 object id.
27+
*
28+
* @var string
29+
* @since 2.11.0
30+
*/
31+
protected $cmb_id;
32+
33+
/**
34+
* The object type we are performing the hookup for
35+
*
36+
* @var string
37+
* @since 2.11.0
38+
*/
39+
protected $object_type = 'post';
40+
41+
/**
42+
* Initialize all hooks for the given field.
43+
*
44+
* @since 2.11.0
45+
* @param array $field The field arguments array.
46+
* @param CMB2 $cmb The CMB2 object.
47+
* @return array The field arguments array.
48+
*/
49+
public static function init( $field, CMB2 $cmb ) {
50+
switch ( $field['type'] ) {
51+
case 'file':
52+
case 'file_list':
53+
// Initiate attachment JS hooks.
54+
add_filter( 'wp_prepare_attachment_for_js', array( 'CMB2_Type_File_Base', 'prepare_image_sizes_for_js' ), 10, 3 );
55+
break;
56+
57+
case 'oembed':
58+
// Initiate oembed Ajax hooks.
59+
cmb2_ajax();
60+
break;
61+
62+
case 'group':
63+
if ( empty( $field['render_row_cb'] ) ) {
64+
$field['render_row_cb'] = array( $cmb, 'render_group_callback' );
65+
}
66+
break;
67+
case 'colorpicker':
68+
// https://github.com/JayWood/CMB2_RGBa_Picker
69+
// Dequeue the rgba_colorpicker custom field script if it is used,
70+
// since we now enqueue our own more current version.
71+
add_action( 'admin_enqueue_scripts', array( 'CMB2_Type_Colorpicker', 'dequeue_rgba_colorpicker_script' ), 99 );
72+
break;
73+
74+
case 'text_datetime_timestamp_timezone':
75+
foreach ( $cmb->box_types() as $object_type ) {
76+
if ( ! $cmb->is_supported_core_object_type( $object_type ) ) {
77+
// Ignore post-types...
78+
continue;
79+
}
80+
81+
if ( empty( $field['field_hookup_instance'][ $object_type ] ) ) {
82+
$instance = new self( $field, $object_type, $cmb );
83+
$method = 'options-page' === $object_type
84+
? 'text_datetime_timestamp_timezone_option_back_compat'
85+
: 'text_datetime_timestamp_timezone_back_compat';
86+
87+
$field['field_hookup_instance'][ $object_type ] = array( $instance, $method );
88+
}
89+
90+
if ( false === $field['field_hookup_instance'][ $object_type ] ) {
91+
// If set to false, no need to filter.
92+
// This can be set if you have updated your use of the field type value to
93+
// assume the JSON value.
94+
continue;
95+
}
96+
97+
if ( 'options-page' === $object_type ) {
98+
$option_name = $cmb->object_id();
99+
add_filter( "pre_option_{$option_name}", $field['field_hookup_instance'][ $object_type ], 10, 3 );
100+
continue;
101+
}
102+
103+
add_filter( "get_{$object_type}_metadata", $field['field_hookup_instance'][ $object_type ], 10, 5 );
104+
}
105+
break;
106+
}
107+
108+
return $field;
109+
}
110+
111+
/**
112+
* Constructor
113+
*
114+
* @since 2.11.0
115+
* @param CMB2 $cmb The CMB2 object to hookup.
116+
*/
117+
public function __construct( $field, $object_type, CMB2 $cmb ) {
118+
$this->field_id = $field['id'];
119+
$this->object_type = $object_type;
120+
$this->cmb_id = $cmb->cmb_id;
121+
}
122+
123+
/**
124+
* Adds a back-compat shim for text_datetime_timestamp_timezone field type values.
125+
*
126+
* Handles old serialized DateTime values, as well as the new JSON formatted values.
127+
*
128+
* @since 2.11.0
129+
*
130+
* @param mixed $value The value of the metadata.
131+
* @param int $object_id ID of the object metadata is for.
132+
* @param string $meta_key Meta key.
133+
* @param bool $single Whether to return a single value.
134+
* @param string $meta_type Type of object metadata is for.
135+
* @return mixed Maybe reserialized value.
136+
*/
137+
public function text_datetime_timestamp_timezone_back_compat( $value, $object_id, $meta_key, $single, $meta_type ) {
138+
if ( $meta_key === $this->field_id ) {
139+
remove_filter( "get_{$meta_type}_metadata", [ $this, __FUNCTION__ ], 10, 5 );
140+
$value = get_metadata( $meta_type, $object_id, $meta_key, $single );
141+
add_filter( "get_{$meta_type}_metadata", [ $this, __FUNCTION__ ], 10, 5 );
142+
143+
$value = $this->reserialize_safe_value( $value );
144+
}
145+
146+
return $value;
147+
}
148+
149+
/**
150+
* Adds a back-compat shim for text_datetime_timestamp_timezone field type values on options pages.
151+
*
152+
* Handles old serialized DateTime values, as well as the new JSON formatted values.
153+
*
154+
* @since 2.11.0
155+
*
156+
* @param mixed $value The value of the option.
157+
* @param string $option Option name.
158+
* @param mixed $default_value Default value.
159+
* @return mixed The updated value.
160+
*/
161+
public function text_datetime_timestamp_timezone_option_back_compat( $value, $option, $default_value ) {
162+
remove_filter( "pre_option_{$option}", [ $this, __FUNCTION__ ], 10, 3 );
163+
$value = get_option( $option, $default_value );
164+
add_filter( "pre_option_{$option}", [ $this, __FUNCTION__ ], 10, 3 );
165+
166+
if ( ! empty( $value ) && is_array( $value ) ) {
167+
168+
// Loop fields and update values for all text_datetime_timestamp_timezone fields.
169+
foreach ( CMB2_Boxes::get( $this->cmb_id )->prop( 'fields' ) as $field ) {
170+
if (
171+
'text_datetime_timestamp_timezone' === $field['type']
172+
&& ! empty( $value[ $field['id'] ] )
173+
) {
174+
$value[ $field['id'] ] = $this->reserialize_safe_value( $value[ $field['id'] ] );
175+
}
176+
}
177+
}
178+
179+
return $value;
180+
}
181+
182+
/**
183+
* Reserialize a value to a safe serialized DateTime value.
184+
*
185+
* @since 2.11.0
186+
*
187+
* @param mixed $value The value to check.
188+
* @return mixed The value, possibly reserialized.
189+
*/
190+
protected function reserialize_safe_value( $value ) {
191+
if ( is_array( $value ) ) {
192+
return array_map( [ $this, 'reserialize_safe_value' ], $value );
193+
}
194+
195+
$updated_val = CMB2_Utils::get_datetime_from_value( $value );
196+
$value = $updated_val ? serialize( $updated_val ) : '';
197+
198+
return $value;
199+
}
200+
}

includes/CMB2_Sanitize.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ public function text_datetime_timestamp_timezone( $repeat = false ) {
399399
} else {
400400
$datetime->setTimezone( new DateTimeZone( $tzstring ) );
401401
$utc_stamp = date_timestamp_get( $datetime ) - $offset;
402-
$this->value = serialize( $datetime );
402+
$this->value = json_encode( $datetime );
403403
}
404404

405405
if ( $this->field->group ) {

0 commit comments

Comments
 (0)