Advanced Custom Fields - Version 5.9.7

Version Description

Release Date - 22 June 2021

  • Fix - Fixed PHP warnings logged due to incorrect parameter type for add_menu_page()/add_submenu_page()
  • Fix - Fixed bug causing WYSIWYG field to not keep line breaks
  • Fix - Fixed bug causing Email field to incorrectly invalidate emails with unicode characters
  • Fix - Fixed bug causing file type validation to fail in some cases
  • Fix - Fixed bug where newly uploaded or selected images do not contain custom preview size data
Download this release

Release Info

Developer deliciousbrains
Plugin Icon 128x128 Advanced Custom Fields
Version 5.9.7
Comparing to
See all releases

Code changes from version 5.9.6 to 5.9.7

acf.php CHANGED
@@ -3,8 +3,8 @@
3
  Plugin Name: Advanced Custom Fields
4
  Plugin URI: https://www.advancedcustomfields.com
5
  Description: Customize WordPress with powerful, professional and intuitive fields.
6
- Version: 5.9.6
7
- Author: Elliot Condon
8
  Author URI: https://www.advancedcustomfields.com
9
  Text Domain: acf
10
  Domain Path: /lang
@@ -17,7 +17,7 @@ if( ! class_exists('ACF') ) :
17
  class ACF {
18
 
19
  /** @var string The plugin version number. */
20
- var $version = '5.9.6';
21
 
22
  /** @var array The plugin settings array. */
23
  var $settings = array();
@@ -137,7 +137,6 @@ class ACF {
137
  acf_include('includes/loop.php');
138
  acf_include('includes/media.php');
139
  acf_include('includes/revisions.php');
140
- acf_include('includes/updates.php');
141
  acf_include('includes/upgrades.php');
142
  acf_include('includes/validation.php');
143
 
3
  Plugin Name: Advanced Custom Fields
4
  Plugin URI: https://www.advancedcustomfields.com
5
  Description: Customize WordPress with powerful, professional and intuitive fields.
6
+ Version: 5.9.7
7
+ Author: Delicious Brains
8
  Author URI: https://www.advancedcustomfields.com
9
  Text Domain: acf
10
  Domain Path: /lang
17
  class ACF {
18
 
19
  /** @var string The plugin version number. */
20
+ var $version = '5.9.7';
21
 
22
  /** @var array The plugin settings array. */
23
  var $settings = array();
137
  acf_include('includes/loop.php');
138
  acf_include('includes/media.php');
139
  acf_include('includes/revisions.php');
 
140
  acf_include('includes/upgrades.php');
141
  acf_include('includes/validation.php');
142
 
includes/admin/admin.php CHANGED
@@ -45,7 +45,7 @@ class ACF_Admin {
45
  $cap = acf_get_setting('capability');
46
 
47
  // Add menu items.
48
- add_menu_page( __("Custom Fields",'acf'), __("Custom Fields",'acf'), $cap, $slug, false, 'dashicons-welcome-widgets-menus', '80.025' );
49
  add_submenu_page( $slug, __('Field Groups','acf'), __('Field Groups','acf'), $cap, $slug );
50
  add_submenu_page( $slug, __('Add New','acf'), __('Add New','acf'), $cap, 'post-new.php?post_type=acf-field-group' );
51
  }
45
  $cap = acf_get_setting('capability');
46
 
47
  // Add menu items.
48
+ add_menu_page( __("Custom Fields",'acf'), __("Custom Fields",'acf'), $cap, $slug, false, 'dashicons-welcome-widgets-menus', 80 );
49
  add_submenu_page( $slug, __('Field Groups','acf'), __('Field Groups','acf'), $cap, $slug );
50
  add_submenu_page( $slug, __('Add New','acf'), __('Add New','acf'), $cap, 'post-new.php?post_type=acf-field-group' );
51
  }
includes/api/api-helpers.php CHANGED
@@ -3436,13 +3436,13 @@ function acf_get_valid_terms( $terms = false, $taxonomy = 'category' ) {
3436
  /*
3437
  * acf_validate_attachment
3438
  *
3439
- * This function will validate an attachment based on a field's resrictions and return an array of errors
3440
  *
3441
  * @type function
3442
  * @date 3/07/2015
3443
  * @since 5.2.3
3444
  *
3445
- * @param $attachment (array) attachment data. Cahnges based on context
3446
  * @param $field (array) field settings containing restrictions
3447
  * @param $context (string) $file is different when uploading / preparing
3448
  * @return $errors (array)
@@ -3478,7 +3478,7 @@ function acf_validate_attachment( $attachment, $field, $context = 'prepare' ) {
3478
  // prepare
3479
  } elseif( $context == 'prepare' ) {
3480
 
3481
- $file['type'] = pathinfo($attachment['url'], PATHINFO_EXTENSION);
3482
  $file['size'] = acf_maybe_get($attachment, 'filesizeInBytes', 0);
3483
  $file['width'] = acf_maybe_get($attachment, 'width', 0);
3484
  $file['height'] = acf_maybe_get($attachment, 'height', 0);
@@ -3487,7 +3487,7 @@ function acf_validate_attachment( $attachment, $field, $context = 'prepare' ) {
3487
  } else {
3488
 
3489
  $file = array_merge($file, $attachment);
3490
- $file['type'] = pathinfo($attachment['url'], PATHINFO_EXTENSION);
3491
 
3492
  }
3493
 
3436
  /*
3437
  * acf_validate_attachment
3438
  *
3439
+ * This function will validate an attachment based on a field's restrictions and return an array of errors
3440
  *
3441
  * @type function
3442
  * @date 3/07/2015
3443
  * @since 5.2.3
3444
  *
3445
+ * @param $attachment (array) attachment data. Changes based on context
3446
  * @param $field (array) field settings containing restrictions
3447
  * @param $context (string) $file is different when uploading / preparing
3448
  * @return $errors (array)
3478
  // prepare
3479
  } elseif( $context == 'prepare' ) {
3480
 
3481
+ $file['type'] = pathinfo($attachment['filename'], PATHINFO_EXTENSION);
3482
  $file['size'] = acf_maybe_get($attachment, 'filesizeInBytes', 0);
3483
  $file['width'] = acf_maybe_get($attachment, 'width', 0);
3484
  $file['height'] = acf_maybe_get($attachment, 'height', 0);
3487
  } else {
3488
 
3489
  $file = array_merge($file, $attachment);
3490
+ $file['type'] = pathinfo($attachment['filename'], PATHINFO_EXTENSION);
3491
 
3492
  }
3493
 
includes/fields/class-acf-field-email.php CHANGED
@@ -163,7 +163,9 @@ class acf_field_email extends acf_field {
163
  * @return bool|string
164
  */
165
  public function validate_value( $valid, $value, $field, $input ) {
166
- if ( $value && filter_var( wp_unslash($value), FILTER_VALIDATE_EMAIL ) === false ) {
 
 
167
  return sprintf( __( "'%s' is not a valid email address", 'acf' ), esc_html( $value ) );
168
  }
169
 
163
  * @return bool|string
164
  */
165
  public function validate_value( $valid, $value, $field, $input ) {
166
+ $flags = defined( 'FILTER_FLAG_EMAIL_UNICODE' ) ? FILTER_FLAG_EMAIL_UNICODE : 0;
167
+
168
+ if ( $value && filter_var( wp_unslash($value), FILTER_VALIDATE_EMAIL, $flags ) === false ) {
169
  return sprintf( __( "'%s' is not a valid email address", 'acf' ), esc_html( $value ) );
170
  }
171
 
includes/fields/class-acf-field-wysiwyg.php CHANGED
@@ -237,7 +237,7 @@ class acf_field_wysiwyg extends acf_field {
237
  }
238
 
239
 
240
- // must be logged in tp upload
241
  if( !current_user_can('upload_files') ) {
242
 
243
  $field['media_upload'] = 0;
@@ -250,6 +250,7 @@ class acf_field_wysiwyg extends acf_field {
250
 
251
 
252
  // filter
 
253
  $field['value'] = apply_filters( 'acf_the_editor_content', $field['value'], $default_editor );
254
 
255
 
237
  }
238
 
239
 
240
+ // must be logged in to upload
241
  if( !current_user_can('upload_files') ) {
242
 
243
  $field['media_upload'] = 0;
250
 
251
 
252
  // filter
253
+ add_filter( 'acf_the_editor_content', 'format_for_editor', 10, 2 );
254
  $field['value'] = apply_filters( 'acf_the_editor_content', $field['value'], $default_editor );
255
 
256
 
includes/media.php CHANGED
@@ -6,49 +6,40 @@ if( ! class_exists('ACF_Media') ) :
6
 
7
  class ACF_Media {
8
 
9
-
10
- /*
11
- * __construct
12
- *
13
- * Initialize filters, action, variables and includes
14
- *
15
- * @type function
16
- * @date 23/06/12
17
- * @since 5.0.0
18
- *
19
- * @param N/A
20
- * @return N/A
21
- */
22
-
23
- function __construct() {
24
-
25
- // actions
26
- add_action('acf/enqueue_scripts', array($this, 'enqueue_scripts'));
27
- add_action('acf/save_post', array($this, 'save_files'), 5, 1);
28
-
29
-
30
- // filters
31
- add_filter('wp_handle_upload_prefilter', array($this, 'handle_upload_prefilter'), 10, 1);
32
-
33
-
34
- // ajax
35
- add_action('wp_ajax_query-attachments', array($this, 'wp_ajax_query_attachments'), -1);
36
  }
37
 
38
-
39
  /**
40
- * enqueue_scripts
41
- *
42
- * Localizes data
43
- *
44
- * @date 27/4/18
45
- * @since 5.6.9
46
- *
47
- * @param void
48
- * @return void
49
- */
50
-
51
- function enqueue_scripts(){
52
  if( wp_script_is('acf-input') ) {
53
  acf_localize_text(array(
54
  'Select.verb' => _x('Select', 'verb', 'acf'),
@@ -66,149 +57,162 @@ class ACF_Media {
66
  ));
67
  }
68
  }
69
-
70
-
71
- /*
72
- * handle_upload_prefilter
73
- *
74
- * description
75
- *
76
- * @type function
77
- * @date 16/02/2015
78
- * @since 5.1.5
79
- *
80
- * @param $post_id (int)
81
- * @return $post_id (int)
82
- */
83
 
84
- function handle_upload_prefilter( $file ) {
85
-
86
- // bail early if no acf field
87
- if( empty($_POST['_acfuploader']) ) {
88
- return $file;
 
 
 
 
 
 
 
89
  }
90
-
91
-
92
- // load field
93
- $field = acf_get_field( $_POST['_acfuploader'] );
 
 
 
 
 
 
 
 
 
94
  if( !$field ) {
95
  return $file;
96
  }
97
 
98
-
99
- // get errors
100
  $errors = acf_validate_attachment( $file, $field, 'upload' );
101
 
102
-
103
  /**
104
- * Filters the errors for a file before it is uploaded to WordPress.
105
- *
106
- * @date 16/02/2015
107
- * @since 5.1.5
108
- *
109
- * @param array $errors An array of errors.
110
- * @param array $file An array of data for a single file.
111
- * @param array $field The field array.
112
- */
113
  $errors = apply_filters( "acf/upload_prefilter/type={$field['type']}", $errors, $file, $field );
114
  $errors = apply_filters( "acf/upload_prefilter/name={$field['_name']}", $errors, $file, $field );
115
  $errors = apply_filters( "acf/upload_prefilter/key={$field['key']}", $errors, $file, $field );
116
  $errors = apply_filters( "acf/upload_prefilter", $errors, $file, $field );
117
 
118
-
119
- // append error
120
  if( !empty($errors) ) {
121
  $file['error'] = implode("\n", $errors);
122
  }
123
 
 
 
124
 
125
- // return
126
  return $file;
127
  }
128
 
129
 
130
- /*
131
- * save_files
132
- *
133
- * This function will save the $_FILES data
134
- *
135
- * @type function
136
- * @date 24/10/2014
137
- * @since 5.0.9
138
- *
139
- * @param $post_id (int)
140
- * @return $post_id (int)
141
- */
142
 
143
- function save_files( $post_id = 0 ) {
144
-
145
- // bail early if no $_FILES data
146
- if( empty($_FILES['acf']['name']) ) {
147
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
149
 
150
-
151
- // upload files
152
- acf_upload_files();
 
 
 
153
  }
154
 
155
-
156
- /*
157
- * wp_ajax_query_attachments
158
- *
159
- * description
160
- *
161
- * @type function
162
- * @date 26/06/2015
163
- * @since 5.2.3
164
- *
165
- * @param $post_id (int)
166
- * @return $post_id (int)
167
- */
168
-
169
  function wp_ajax_query_attachments() {
170
-
171
- add_filter('wp_prepare_attachment_for_js', array($this, 'wp_prepare_attachment_for_js'), 10, 3);
172
-
 
173
  }
174
 
 
 
 
 
 
 
 
 
 
 
 
175
  function wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
 
176
 
177
- // append attribute
178
- $response['acf_errors'] = false;
179
-
180
-
181
- // bail early if no acf field
182
- if( empty($_POST['query']['_acfuploader']) ) {
183
- return $response;
184
- }
185
-
186
-
187
- // load field
188
- $field = acf_get_field( $_POST['query']['_acfuploader'] );
189
- if( !$field ) {
190
- return $response;
191
- }
192
-
193
-
194
- // get errors
195
  $errors = acf_validate_attachment( $response, $field, 'prepare' );
196
-
197
-
198
- // append errors
199
  if( !empty($errors) ) {
200
  $response['acf_errors'] = implode('<br />', $errors);
201
  }
202
 
203
-
204
- // return
205
  return $response;
206
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
 
209
- // instantiate
210
- acf_new_instance('ACF_Media');
211
-
212
- endif; // class_exists check
213
 
214
- ?>
6
 
7
  class ACF_Media {
8
 
9
+ /**
10
+ * Constructor.
11
+ *
12
+ * @date 23/06/12
13
+ * @since 5.0.0
14
+ *
15
+ * @param void
16
+ * @return void
17
+ */
18
+ public function __construct() {
19
+
20
+ // Localize media strings.
21
+ add_action( 'acf/enqueue_scripts', array( $this, 'enqueue_scripts' ) );
22
+
23
+ // Save files uploaded from basic `$_FILE` field.
24
+ add_action( 'acf/save_post', array( $this, 'save_files' ), 5, 1 );
25
+
26
+ // Hook into Media Upload to run additional logic.
27
+ add_filter( 'wp_handle_upload_prefilter', array( $this, 'handle_upload_prefilter' ), 10, 1 );
28
+
29
+ // Hook into Media Modal Query to run additional logic.
30
+ add_action( 'wp_ajax_query-attachments', array( $this, 'wp_ajax_query_attachments' ), -1 );
 
 
 
 
 
31
  }
32
 
 
33
  /**
34
+ * Fires when ACF scrtips are enqueued.
35
+ *
36
+ * @date 27/4/18
37
+ * @since 5.6.9
38
+ *
39
+ * @param void
40
+ * @return void
41
+ */
42
+ public function enqueue_scripts(){
 
 
 
43
  if( wp_script_is('acf-input') ) {
44
  acf_localize_text(array(
45
  'Select.verb' => _x('Select', 'verb', 'acf'),
57
  ));
58
  }
59
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
+ /**
62
+ * Uploads attachments found in the basic `$_FILES` array.
63
+ *
64
+ * @date 24/10/2014
65
+ * @since 5.0.9
66
+ *
67
+ * @param string|int $post_id The post ID being saved.
68
+ * @return void
69
+ */
70
+ public function save_files( $post_id = 0 ) {
71
+ if( isset( $_FILES['acf']['name'] ) ) {
72
+ acf_upload_files();
73
  }
74
+ }
75
+
76
+ /**
77
+ * Filters data for the current file being uploaded.
78
+ *
79
+ * @date 16/02/2015
80
+ * @since 5.1.5
81
+ *
82
+ * @param array $file An array of data for a single file.
83
+ * @return array
84
+ */
85
+ public function handle_upload_prefilter( $file ) {
86
+ $field = $this->get_source_field();
87
  if( !$field ) {
88
  return $file;
89
  }
90
 
91
+ // Validate the attachment and append any errors.
 
92
  $errors = acf_validate_attachment( $file, $field, 'upload' );
93
 
 
94
  /**
95
+ * Filters the errors for a file before it is uploaded to WordPress.
96
+ *
97
+ * @date 16/02/2015
98
+ * @since 5.1.5
99
+ *
100
+ * @param array $errors An array of errors.
101
+ * @param array $file An array of data for a single file.
102
+ * @param array $field The field array.
103
+ */
104
  $errors = apply_filters( "acf/upload_prefilter/type={$field['type']}", $errors, $file, $field );
105
  $errors = apply_filters( "acf/upload_prefilter/name={$field['_name']}", $errors, $file, $field );
106
  $errors = apply_filters( "acf/upload_prefilter/key={$field['key']}", $errors, $file, $field );
107
  $errors = apply_filters( "acf/upload_prefilter", $errors, $file, $field );
108
 
109
+ // Append errors.
 
110
  if( !empty($errors) ) {
111
  $file['error'] = implode("\n", $errors);
112
  }
113
 
114
+ // Ensure newly uploaded image contains "preview_size" within the "size" data.
115
+ add_filter( 'image_size_names_choose', array( $this, 'image_size_names_choose' ), 10, 1 );
116
 
117
+ // Return.
118
  return $file;
119
  }
120
 
121
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+
124
+ /**
125
+ * Returns the field responsible for the current Media query or upload context.
126
+ *
127
+ * @date 21/5/21
128
+ * @since 5.9.7
129
+ *
130
+ * @param void
131
+ * @return array| false.
132
+ */
133
+ private function get_source_field() {
134
+ $field = false;
135
+
136
+ // Search for field key within available data.
137
+ // Case 1) Media modal query.
138
+ if( isset( $_POST['query']['_acfuploader'] ) ) {
139
+ $field_key = (string) $_POST['query']['_acfuploader'];
140
+
141
+ // Case 2) Media modal upload.
142
+ } elseif( isset( $_POST['_acfuploader'] ) ) {
143
+ $field_key = (string) $_POST['_acfuploader'];
144
  }
145
 
146
+ // Attempt to load field.
147
+ // Note the `acf_get_field()` function will return false if not found.
148
+ if( isset( $field_key ) ) {
149
+ $field = acf_get_field( $field_key );
150
+ }
151
+ return $field;
152
  }
153
 
154
+ /**
155
+ * Fires during the WP Modal Query AJAX call.
156
+ *
157
+ * @date 26/06/2015
158
+ * @since 5.2.3
159
+ *
160
+ * @param void
161
+ * @return void
162
+ */
 
 
 
 
 
163
  function wp_ajax_query_attachments() {
164
+ if( $this->get_source_field() ) {
165
+ add_filter( 'wp_prepare_attachment_for_js', array( $this, 'wp_prepare_attachment_for_js' ), 10, 3 );
166
+ add_filter( 'image_size_names_choose', array( $this, 'image_size_names_choose' ), 10, 1 );
167
+ }
168
  }
169
 
170
+ /**
171
+ * Filters attachment data as it is being prepared for JS.
172
+ *
173
+ * @date 21/5/21
174
+ * @since 5.9.7
175
+ *
176
+ * @param array $response Array of prepared attachment data.
177
+ * @param WP_Post $attachment Attachment object.
178
+ * @param array|false $meta Array of attachment meta data, or false if there is none.
179
+ * @return array
180
+ */
181
  function wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
182
+ $field = $this->get_source_field();
183
 
184
+ // Validate the attachment and append any errors.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  $errors = acf_validate_attachment( $response, $field, 'prepare' );
 
 
 
186
  if( !empty($errors) ) {
187
  $response['acf_errors'] = implode('<br />', $errors);
188
  }
189
 
190
+ // Return.
 
191
  return $response;
192
  }
193
+
194
+ /**
195
+ * Filters the names and labels of the default image sizes.
196
+ *
197
+ * @date 21/5/21
198
+ * @since 5.9.7
199
+ *
200
+ * @param array $size_names Array of image size labels keyed by their name.
201
+ * @return array
202
+ */
203
+ function image_size_names_choose( $size_names ) {
204
+ $field = $this->get_source_field();
205
+
206
+ // Append "preview_size" setting to array of image sizes so WP will include in prepared JS data.
207
+ if( isset( $field['preview_size'] ) ) {
208
+ $name = (string) $field['preview_size'];
209
+ $size_names[ $name ] = $name; // Don't worry about size label, it is never used.
210
+ }
211
+ return $size_names;
212
+ }
213
  }
214
 
215
+ // Instantiate.
216
+ acf_new_instance( 'ACF_Media' );
 
 
217
 
218
+ endif; // class_exists check
includes/updates.php DELETED
@@ -1,490 +0,0 @@
1
- <?php
2
-
3
- if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
4
-
5
- if( ! class_exists('ACF_Updates') ) :
6
-
7
- class ACF_Updates {
8
-
9
- /** @var string The ACF_Updates version */
10
- var $version = '2.4';
11
-
12
- /** @var array The array of registered plugins */
13
- var $plugins = array();
14
-
15
- /** @var int Counts the number of plugin update checks */
16
- var $checked = 0;
17
-
18
- /*
19
- * __construct
20
- *
21
- * Sets up the class functionality.
22
- *
23
- * @date 5/03/2014
24
- * @since 5.0.0
25
- *
26
- * @param void
27
- * @return void
28
- */
29
-
30
- function __construct() {
31
-
32
- // append update information to transient
33
- add_filter('pre_set_site_transient_update_plugins', array($this, 'modify_plugins_transient'), 10, 1);
34
-
35
- // modify plugin data visible in the 'View details' popup
36
- add_filter('plugins_api', array($this, 'modify_plugin_details'), 10, 3);
37
- }
38
-
39
- /*
40
- * add_plugin
41
- *
42
- * Registeres a plugin for updates.
43
- *
44
- * @date 8/4/17
45
- * @since 5.5.10
46
- *
47
- * @param array $plugin The plugin array.
48
- * @return void
49
- */
50
-
51
- function add_plugin( $plugin ) {
52
-
53
- // validate
54
- $plugin = wp_parse_args($plugin, array(
55
- 'id' => '',
56
- 'key' => '',
57
- 'slug' => '',
58
- 'basename' => '',
59
- 'version' => '',
60
- ));
61
-
62
- // Check if is_plugin_active() function exists. This is required on the front end of the
63
- // site, since it is in a file that is normally only loaded in the admin.
64
- if( !function_exists( 'is_plugin_active' ) ) {
65
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
66
- }
67
-
68
- // add if is active plugin (not included in theme)
69
- if( is_plugin_active($plugin['basename']) ) {
70
- $this->plugins[ $plugin['basename'] ] = $plugin;
71
- }
72
- }
73
-
74
- /**
75
- * get_plugin_by
76
- *
77
- * Returns a registered plugin for the give key and value.
78
- *
79
- * @date 3/8/18
80
- * @since 5.7.2
81
- *
82
- * @param string $key The array key to compare
83
- * @param string $value The value to compare against
84
- * @return array|false
85
- */
86
-
87
- function get_plugin_by( $key = '', $value = null ) {
88
- foreach( $this->plugins as $plugin ) {
89
- if( $plugin[$key] === $value ) {
90
- return $plugin;
91
- }
92
- }
93
- return false;
94
- }
95
-
96
- /*
97
- * request
98
- *
99
- * Makes a request to the ACF connect server.
100
- *
101
- * @date 8/4/17
102
- * @since 5.5.10
103
- *
104
- * @param string $endpoint The API endpoint.
105
- * @param array $body The body to post.
106
- * @return (array|string|WP_Error)
107
- */
108
- function request( $endpoint = '', $body = null ) {
109
-
110
- // Determine URL.
111
- $url = "https://connect.advancedcustomfields.com/$endpoint";
112
-
113
- // Staging environment.
114
- if( defined('ACF_DEV_API') && ACF_DEV_API === 'STAGE' ) {
115
- $url = "https://staging.connect.advancedcustomfields.com/$endpoint";
116
- acf_log( $url, $body );
117
-
118
- // Dev environment.
119
- } elseif( defined('ACF_DEV_API') && ACF_DEV_API ) {
120
- $url = "http://connect/$endpoint";
121
- acf_log( $url, $body );
122
- }
123
-
124
- // Make request.
125
- $raw_response = wp_remote_post( $url, array(
126
- 'timeout' => 10,
127
- 'body' => $body
128
- ));
129
-
130
- // Handle response error.
131
- if( is_wp_error($raw_response) ) {
132
- return $raw_response;
133
-
134
- // Handle http error.
135
- } elseif( wp_remote_retrieve_response_code($raw_response) != 200 ) {
136
- return new WP_Error( 'server_error', wp_remote_retrieve_response_message($raw_response) );
137
- }
138
-
139
- // Decode JSON response.
140
- $json = json_decode( wp_remote_retrieve_body($raw_response), true );
141
-
142
- // Allow non json value.
143
- if( $json === null ) {
144
- return wp_remote_retrieve_body($raw_response);
145
- }
146
-
147
- // return
148
- return $json;
149
- }
150
-
151
- /*
152
- * get_plugin_info
153
- *
154
- * Returns update information for the given plugin id.
155
- *
156
- * @date 9/4/17
157
- * @since 5.5.10
158
- *
159
- * @param string $id The plugin id such as 'pro'.
160
- * @param boolean $force_check Bypasses cached result. Defaults to false.
161
- * @return array|WP_Error
162
- */
163
-
164
- function get_plugin_info( $id = '', $force_check = false ) {
165
-
166
- // var
167
- $transient_name = 'acf_plugin_info_' . $id;
168
-
169
- // check cache but allow for $force_check override
170
- if( !$force_check ) {
171
- $transient = get_transient( $transient_name );
172
- if( $transient !== false ) {
173
- return $transient;
174
- }
175
- }
176
-
177
- // connect
178
- $response = $this->request('v2/plugins/get-info?p='.$id);
179
-
180
- // convert string (misc error) to WP_Error object
181
- if( is_string($response) ) {
182
- $response = new WP_Error( 'server_error', esc_html($response) );
183
- }
184
-
185
- // allow json to include expiration but force minimum and max for safety
186
- $expiration = $this->get_expiration($response, DAY_IN_SECONDS, MONTH_IN_SECONDS);
187
-
188
- // update transient
189
- set_transient( $transient_name, $response, $expiration );
190
-
191
- // return
192
- return $response;
193
- }
194
-
195
- /**
196
- * get_plugin_update
197
- *
198
- * Returns specific data from the 'update-check' response.
199
- *
200
- * @date 3/8/18
201
- * @since 5.7.2
202
- *
203
- * @param string $basename The plugin basename.
204
- * @param boolean $force_check Bypasses cached result. Defaults to false
205
- * @return array
206
- */
207
-
208
- function get_plugin_update( $basename = '', $force_check = false ) {
209
-
210
- // get updates
211
- $updates = $this->get_plugin_updates( $force_check );
212
-
213
- // check for and return update
214
- if( is_array($updates) && isset($updates['plugins'][ $basename ]) ) {
215
- return $updates['plugins'][ $basename ];
216
- }
217
- return false;
218
- }
219
-
220
-
221
- /**
222
- * get_plugin_updates
223
- *
224
- * Checks for plugin updates.
225
- *
226
- * @date 8/7/18
227
- * @since 5.6.9
228
- * @since 5.7.2 Added 'checked' comparison
229
- *
230
- * @param boolean $force_check Bypasses cached result. Defaults to false.
231
- * @return array|WP_Error.
232
- */
233
-
234
- function get_plugin_updates( $force_check = false ) {
235
-
236
- // var
237
- $transient_name = 'acf_plugin_updates';
238
-
239
- // construct array of 'checked' plugins
240
- // sort by key to avoid detecting change due to "include order"
241
- $checked = array();
242
- foreach( $this->plugins as $basename => $plugin ) {
243
- $checked[ $basename ] = $plugin['version'];
244
- }
245
- ksort($checked);
246
-
247
- // $force_check prevents transient lookup
248
- if( !$force_check ) {
249
- $transient = get_transient($transient_name);
250
-
251
- // if cached response was found, compare $transient['checked'] against $checked and ignore if they don't match (plugins/versions have changed)
252
- if( is_array($transient) ) {
253
- $transient_checked = isset($transient['checked']) ? $transient['checked'] : array();
254
- if( wp_json_encode($checked) !== wp_json_encode($transient_checked) ) {
255
- $transient = false;
256
- }
257
- }
258
- if( $transient !== false ) {
259
- return $transient;
260
- }
261
- }
262
-
263
- // vars
264
- $post = array(
265
- 'plugins' => wp_json_encode($this->plugins),
266
- 'wp' => wp_json_encode(array(
267
- 'wp_name' => get_bloginfo('name'),
268
- 'wp_url' => home_url(),
269
- 'wp_version' => get_bloginfo('version'),
270
- 'wp_language' => get_bloginfo('language'),
271
- 'wp_timezone' => get_option('timezone_string'),
272
- )),
273
- 'acf' => wp_json_encode(array(
274
- 'acf_version' => get_option('acf_version'),
275
- 'acf_pro' => (defined('ACF_PRO') && ACF_PRO),
276
- )),
277
- );
278
-
279
- // request
280
- $response = $this->request('v2/plugins/update-check', $post);
281
-
282
- // append checked reference
283
- if( is_array($response) ) {
284
- $response['checked'] = $checked;
285
- }
286
-
287
- // allow json to include expiration but force minimum and max for safety
288
- $expiration = $this->get_expiration($response, DAY_IN_SECONDS, MONTH_IN_SECONDS);
289
-
290
- // update transient
291
- set_transient($transient_name, $response, $expiration );
292
-
293
- // return
294
- return $response;
295
- }
296
-
297
- /**
298
- * get_expiration
299
- *
300
- * This function safely gets the expiration value from a response.
301
- *
302
- * @date 8/7/18
303
- * @since 5.6.9
304
- *
305
- * @param mixed $response The response from the server. Default false.
306
- * @param int $min The minimum expiration limit. Default 0.
307
- * @param int $max The maximum expiration limit. Default 0.
308
- * @return int
309
- */
310
-
311
- function get_expiration( $response = false, $min = 0, $max = 0 ) {
312
-
313
- // vars
314
- $expiration = 0;
315
-
316
- // check
317
- if( is_array($response) && isset($response['expiration']) ) {
318
- $expiration = (int) $response['expiration'];
319
- }
320
-
321
- // min
322
- if( $expiration < $min ) {
323
- return $min;
324
- }
325
-
326
- // max
327
- if( $expiration > $max ) {
328
- return $max;
329
- }
330
-
331
- // return
332
- return $expiration;
333
- }
334
-
335
- /*
336
- * refresh_plugins_transient
337
- *
338
- * Deletes transients and allows a fresh lookup.
339
- *
340
- * @date 11/4/17
341
- * @since 5.5.10
342
- *
343
- * @param void
344
- * @return void
345
- */
346
-
347
- function refresh_plugins_transient() {
348
- delete_site_transient('update_plugins');
349
- delete_transient('acf_plugin_updates');
350
- }
351
-
352
- /*
353
- * modify_plugins_transient
354
- *
355
- * Called when WP updates the 'update_plugins' site transient. Used to inject ACF plugin update info.
356
- *
357
- * @date 16/01/2014
358
- * @since 5.0.0
359
- *
360
- * @param object $transient
361
- * @return $transient
362
- */
363
-
364
- function modify_plugins_transient( $transient ) {
365
-
366
- // bail early if no response (error)
367
- if( !isset($transient->response) ) {
368
- return $transient;
369
- }
370
-
371
- // force-check (only once)
372
- $force_check = ($this->checked == 0) ? !empty($_GET['force-check']) : false;
373
-
374
- // fetch updates (this filter is called multiple times during a single page load)
375
- $updates = $this->get_plugin_updates( $force_check );
376
-
377
- // append
378
- if( is_array($updates) ) {
379
- foreach( $updates['plugins'] as $basename => $update ) {
380
- $transient->response[ $basename ] = (object) $update;
381
- }
382
- }
383
-
384
- // increase
385
- $this->checked++;
386
-
387
- // return
388
- return $transient;
389
- }
390
-
391
- /*
392
- * modify_plugin_details
393
- *
394
- * Returns the plugin data visible in the 'View details' popup
395
- *
396
- * @date 17/01/2014
397
- * @since 5.0.0
398
- *
399
- * @param object $result
400
- * @param string $action
401
- * @param object $args
402
- * @return $result
403
- */
404
-
405
- function modify_plugin_details( $result, $action = null, $args = null ) {
406
-
407
- // vars
408
- $plugin = false;
409
-
410
- // only for 'plugin_information' action
411
- if( $action !== 'plugin_information' ) return $result;
412
-
413
- // find plugin via slug
414
- $plugin = $this->get_plugin_by('slug', $args->slug);
415
- if( !$plugin ) return $result;
416
-
417
- // connect
418
- $response = $this->get_plugin_info($plugin['id']);
419
-
420
- // bail early if no response
421
- if( !is_array($response) ) return $result;
422
-
423
- // remove tags (different context)
424
- unset($response['tags']);
425
-
426
- // convert to object
427
- $response = (object) $response;
428
-
429
- // sections
430
- $sections = array(
431
- 'description' => '',
432
- 'installation' => '',
433
- 'changelog' => '',
434
- 'upgrade_notice' => ''
435
- );
436
- foreach( $sections as $k => $v ) {
437
- $sections[ $k ] = $response->$k;
438
- }
439
- $response->sections = $sections;
440
-
441
- // return
442
- return $response;
443
- }
444
- }
445
-
446
-
447
- /*
448
- * acf_updates
449
- *
450
- * The main function responsible for returning the one true acf_updates instance to functions everywhere.
451
- * Use this function like you would a global variable, except without needing to declare the global.
452
- *
453
- * Example: <?php $acf_updates = acf_updates(); ?>
454
- *
455
- * @date 9/4/17
456
- * @since 5.5.12
457
- *
458
- * @param void
459
- * @return object
460
- */
461
-
462
- function acf_updates() {
463
- global $acf_updates;
464
- if( !isset($acf_updates) ) {
465
- $acf_updates = new ACF_Updates();
466
- }
467
- return $acf_updates;
468
- }
469
-
470
-
471
- /*
472
- * acf_register_plugin_update
473
- *
474
- * Alias of acf_updates()->add_plugin().
475
- *
476
- * @type function
477
- * @date 12/4/17
478
- * @since 5.5.10
479
- *
480
- * @param array $plugin
481
- * @return void
482
- */
483
-
484
- function acf_register_plugin_update( $plugin ) {
485
- acf_updates()->add_plugin( $plugin );
486
- }
487
-
488
- endif; // class_exists check
489
-
490
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -1,7 +1,7 @@
1
  === Advanced Custom Fields ===
2
- Contributors: elliotcondon, bradt
3
  Tags: acf, fields, custom fields, meta, repeater
4
- Stable tag: 5.9.6
5
  Requires at least: 4.7
6
  Tested up to: 5.7
7
  Requires PHP: 5.6
@@ -52,8 +52,6 @@ From your WordPress dashboard
52
 
53
  = What kind of support do you provide? =
54
 
55
- **Help Desk.** Support is currently provided via our email help desk. Questions are generally answered within 24 hours, with the exception of weekends and holidays. We answer questions related to ACF, its usage and provide minor customization guidance. We cannot guarantee support for questions which include custom theme code, or 3rd party plugin conflicts & compatibility. [Open a Support Ticket](https://www.advancedcustomfields.com/support/)
56
-
57
  **Support Forums.** Our Community Forums provide a great resource for searching and finding previously answered and asked support questions. You may create a new thread on these forums, however, it is not guaranteed that you will receive an answer from our support team. This is more of an area for developers to talk to one another, post ideas, plugins and provide basic help. [View the Support Forum](https://support.advancedcustomfields.com/)
58
 
59
 
@@ -68,6 +66,15 @@ From your WordPress dashboard
68
 
69
  == Changelog ==
70
 
 
 
 
 
 
 
 
 
 
71
  = 5.9.6 =
72
  *Release Date - 20 May 2021*
73
 
1
  === Advanced Custom Fields ===
2
+ Contributors: deliciousbrains, bradt, elliotcondon
3
  Tags: acf, fields, custom fields, meta, repeater
4
+ Stable tag: 5.9.7
5
  Requires at least: 4.7
6
  Tested up to: 5.7
7
  Requires PHP: 5.6
52
 
53
  = What kind of support do you provide? =
54
 
 
 
55
  **Support Forums.** Our Community Forums provide a great resource for searching and finding previously answered and asked support questions. You may create a new thread on these forums, however, it is not guaranteed that you will receive an answer from our support team. This is more of an area for developers to talk to one another, post ideas, plugins and provide basic help. [View the Support Forum](https://support.advancedcustomfields.com/)
56
 
57
 
66
 
67
  == Changelog ==
68
 
69
+ = 5.9.7 =
70
+ *Release Date - 22 June 2021*
71
+
72
+ * Fix - Fixed PHP warnings logged due to incorrect parameter type for `add_menu_page()`/`add_submenu_page()`
73
+ * Fix - Fixed bug causing WYSIWYG field to not keep line breaks
74
+ * Fix - Fixed bug causing Email field to incorrectly invalidate emails with unicode characters
75
+ * Fix - Fixed bug causing file type validation to fail in some cases
76
+ * Fix - Fixed bug where newly uploaded or selected images do not contain custom preview size data
77
+
78
  = 5.9.6 =
79
  *Release Date - 20 May 2021*
80