diff --git a/README.md b/README.md index 7129efc..1e0bfe4 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ ACF JSON Field is a Wordpress plugin adding a new ACF field to edit, save and ou - Extract the archive and copy the folder (`acf-json-field`) to the Wordpress plugins folder (`/wp-content/plugins/`). -- Go to the Wordpress plugins manager on your website (`/wp-admin/plugins.php`) and enable the plugin **ACF JSON Field**. Note that you can enable auto-updates. +- Go to the Wordpress plugins manager on your website (`https://.../wp-admin/plugins.php`) and enable the plugin **ACF JSON Field**. Note that you can enable auto-updates. ## Usage -Go to the ACF administration page (`/wp-admin/edit.php?post_type=acf-field-group`), add a new field group and choose the field **JSON**. Change the field settings as needed. +Go to the ACF administration page (`https://.../wp-admin/edit.php?post_type=acf-field-group`), add a new field group and choose the field **JSON**. Change the field settings as needed. -![JSON Field in the list of ACF fields](/assets/screenshots/json-field.png) +![JSON Field in the list of ACF fields](assets/screenshots/json-field.png) When editing a page containing a JSON field, an editor will allow the user to edit the JSON data: @@ -22,7 +22,7 @@ When editing a page containing a JSON field, an editor will allow the user to ed ### Utilities and shortcode -The plugin provides a utility method to retrieve and format JSON data from a specified ACF field, as well as a shortcode to display this data on the front end. +The plugin provides utility methods to retrieve, format, and set JSON data from a specified ACF field, as well as a shortcode to display this data on the front end. The `get_json_field` method can be called as follows: @@ -31,14 +31,11 @@ use \AcfJsonField\JsonUtils; // Retrieve the JSON data as a PHP type (array, boolean, etc.) for the current post $json_data = JsonUtils::get_json_field('field_name_or_key'); -$json_data = JsonUtils::get_json_field('field_name_or_key', null); -$json_data = JsonUtils::get_json_field('field_name_or_key', 'null'); $json_data = JsonUtils::get_json_field('field_name_or_key', false); -$json_data = JsonUtils::get_json_field('field_name_or_key', 'false'); +$json_data = JsonUtils::get_json_field('field_name_or_key', null); // For a specific post ID $json_data = JsonUtils::get_json_field('field_name_or_key', 125); -$json_data = JsonUtils::get_json_field('field_name_or_key', '125'); // For the current user $json_data = JsonUtils::get_json_field('field_name_or_key', 'user'); @@ -56,7 +53,23 @@ Or as follows: $json_data = \AcfJsonField\JsonUtils::get_json_field('field_name_or_key'); ``` -To display the field value on the front end, the shortcode `acf_json_field` can be used. This shortcode internally calls the `get_json_field` method with the `html` format. By default, it'll look at the current post where the shortcode is added: +To set the JSON data for a specific ACF field, use the `set_json_field` method: + +```php +$php_data = ['lorem1' => 'ipsum2', 'lorem2' => 'ipsum2']; +$success = JsonUtils::set_json_field('field_name_or_key', $php_data, 125); + +$json_encoded = json_encode($php_data); +$success = JsonUtils::set_json_field('field_name_or_key', $json_encoded, 125, true); +``` + +To encode PHP data to a JSON string with pretty print formatting, use the `encode` method: + +```php +$json_encoded = JsonUtils::encode($php_data); +``` + +To display the field value on the front end, the shortcode `acf_json_field` can be used. By default, it'll look at the current post where the shortcode is added: [acf_json_field field="field_name_or_key"] diff --git a/acf-json-field.php b/acf-json-field.php index 6b27124..c5ba878 100644 --- a/acf-json-field.php +++ b/acf-json-field.php @@ -5,7 +5,7 @@ * Description: A custom ACF field type for manipulating JSON data * Text Domain: acf-json-field * Author: Misaki F. - * Version: 1.0.1 + * Version: 1.0.2 */ namespace AcfJsonField; @@ -18,7 +18,7 @@ # @title Constants ################################################################################ -define('ACF_JSON_FIELD_VERSION', '1.0.1'); +define('ACF_JSON_FIELD_VERSION', '1.0.2'); ################################################################################ # @title Inclusions diff --git a/includes/class-json-utils.php b/includes/class-json-utils.php index 05ae30b..73fc195 100644 --- a/includes/class-json-utils.php +++ b/includes/class-json-utils.php @@ -10,6 +10,64 @@ * Utility class for ACF JSON Field plugin. */ class JsonUtils { + /** + * Adds HTML tokens to a JSON-encoded string for syntax highlighting. + * + * @param string $json_encoded The JSON-encoded string. + * @return string The JSON string with HTML tokens for syntax highlighting. + */ + private static function add_html_tokens($json_encoded) { + $token_pattern = '/("(?:\\\\u[a-fA-F0-9]{4}|\\\\[^u]|[^\\\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(\.\d*)?([eE][+-]?\d+)?)/'; + + return preg_replace_callback($token_pattern, function ($matches) { + $match = $matches[0]; + $token_type = 'number'; + + if (preg_match('/^"/', $match)) { + if (preg_match('/:$/', $match)) { + $token_type = 'key'; + } else { + $token_type = 'string'; + } + } elseif (preg_match('/true|false/', $match)) { + $token_type = 'boolean'; + } elseif (preg_match('/null/', $match)) { + $token_type = 'null'; + } + + return '' . esc_html($match) . ''; + }, $json_encoded); + } + + /** + * Retrieves the appropriate ID based on the input. + * @return int|string The determined ID. + */ + private static function get_id($id) { + if ($id === 'user') { + $id = 'user_' . get_current_user_id(); + } else if (empty($id) || $id === 'null' || $id === 'false') { + $id = get_the_ID(); + } + + return $id; + } + + /** + * Encodes PHP data to a JSON string with formatting options. + * + * @param mixed $php_data The PHP data to be encoded. + * @return string The JSON-encoded string. + */ + public static function encode($php_data) { + $json_encoded = json_encode($php_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + $json_encoded = preg_replace_callback('/^( {4,})/m', function ($matches) { + return str_replace(' ', ' ', $matches[1]); + }, $json_encoded); + + return $json_encoded; + } + /** * Retrieves and formats JSON data from a specified ACF field. * @@ -21,12 +79,9 @@ class JsonUtils { * - `user_\d+`: Uses the specified user ID. * Examples: * - get_json_field('field_name_or_key') - * - get_json_field('field_name_or_key', null) - * - get_json_field('field_name_or_key', 'null') * - get_json_field('field_name_or_key', false) - * - get_json_field('field_name_or_key', 'false') + * - get_json_field('field_name_or_key', null) * - get_json_field('field_name_or_key', 125) - * - get_json_field('field_name_or_key', '125') * - get_json_field('field_name_or_key', 'user') * - get_json_field('field_name_or_key', 'user_24') * @param string $format The format in which to return the data. @@ -36,47 +91,48 @@ class JsonUtils { * Returns the appropriate PHP type if `$format` is 'php', or an HTML string if `$format` is 'html'. */ public static function get_json_field($field, $id = null, $format = 'php') { - if ($id === 'user') { - $id = 'user_' . get_current_user_id(); - } else if ($id === '' || $id === null || $id === 'null' || $id === false || $id === 'false') { - $id = get_the_ID(); - } - + $id = self::get_id($id); $data = ''; $raw_data = get_field($field, $id); $json_decoded = json_decode($raw_data, true); if ($format === 'html') { - $json_encoded = json_encode($json_decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - $json_encoded = preg_replace_callback('/^( {4,})/m', function ($matches) { - return str_replace(' ', ' ', $matches[1]); - }, $json_encoded); - - $token_pattern = '/("(?:\\\\u[a-fA-F0-9]{4}|\\\\[^u]|[^\\\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(\.\d*)?([eE][+-]?\d+)?)/'; - $json_encoded = preg_replace_callback($token_pattern, function ($matches) { - $match = $matches[0]; - $token_type = 'number'; - - if (preg_match('/^"/', $match)) { - if (preg_match('/:$/', $match)) { - $token_type = 'key'; - } else { - $token_type = 'string'; - } - } elseif (preg_match('/true|false/', $match)) { - $token_type = 'boolean'; - } elseif (preg_match('/null/', $match)) { - $token_type = 'null'; - } - - return '' . esc_html($match) . ''; - }, $json_encoded); - + $json_encoded = self::encode($json_decoded); + $json_encoded = self::add_html_tokens($json_encoded); $data = '
' . $json_encoded . '
'; } else if ($format === 'php') { $data = $json_decoded; } - + return $data; } + + /** + * Sets the JSON data to a specified ACF field. + * + * @param string $field The key or name of the ACF field where the JSON data will be stored. + * @param mixed $data The data to be stored. + * @param int|string|false|null $id The ID of the post or user (see `get_json_field` for details). + * @param bool $is_json_encoded True if the data passed is already JSON encoded, false otherwise. + * @param bool $add_slashes True if slashes should be added to the data to escape it properly, false otherwise. + * @return bool True if the data was successfully updated, false otherwise. + */ + public static function set_json_field($field, $data, $id = null, $is_json_encoded = false, $add_slashes = false) { + $id = self::get_id($id); + $json_encoded = $is_json_encoded ? $data : self::encode($data); + + if ($add_slashes) { + $json_encoded = wp_slash($json_encoded); + } + + if (str_starts_with($id, 'user_')) { + $ret = update_user_meta(substr($id, 5), $field, $json_encoded); + } else { + $ret = update_post_meta($id, $field, $json_encoded); + } + + $success = !empty($ret); + + return $success; + } }