Changeset 3667390
- Timestamp:
- 08/26/2026 03:36:10 PM (2 months ago)
- Location:
- fieldlock-sync-guard-for-acf
- Files:
-
- 8 edited
- 1 copied
-
tags/1.1.0 (copied) (copied from fieldlock-sync-guard-for-acf/trunk )
-
tags/1.1.0/assets/js/admin-field-group-lock.js (modified) (1 diff)
-
tags/1.1.0/fieldlock-sync-guard-for-acf.php (modified) (2 diffs)
-
tags/1.1.0/includes/class-fieldlock-sync-guard-for-acf.php (modified) (12 diffs)
-
tags/1.1.0/readme.txt (modified) (3 diffs)
-
trunk/assets/js/admin-field-group-lock.js (modified) (1 diff)
-
trunk/fieldlock-sync-guard-for-acf.php (modified) (2 diffs)
-
trunk/includes/class-fieldlock-sync-guard-for-acf.php (modified) (12 diffs)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
fieldlock-sync-guard-for-acf/tags/1.1.0/assets/js/admin-field-group-lock.js
r3594467 r3667390 10 10 11 11 buttons.forEach( function ( button ) { 12 var panel; 13 var heading; 14 var message; 15 var list; 16 var action; 17 12 18 button.disabled = true; 13 19 button.setAttribute( 'aria-disabled', 'true' ); 14 20 button.setAttribute( 'title', fieldLockSyncGuardForAcf.message ); 15 21 button.classList.add( 'disabled' ); 22 23 if ( document.querySelector( '.fieldlock-sync-guard-message' ) ) { 24 return; 25 } 26 27 panel = document.createElement( 'div' ); 28 panel.className = 'notice notice-warning inline fieldlock-sync-guard-message'; 29 30 heading = document.createElement( 'p' ); 31 heading.appendChild( document.createElement( 'strong' ) ); 32 heading.firstChild.textContent = fieldLockSyncGuardForAcf.title; 33 panel.appendChild( heading ); 34 35 message = document.createElement( 'p' ); 36 message.textContent = fieldLockSyncGuardForAcf.message; 37 panel.appendChild( message ); 38 39 if ( fieldLockSyncGuardForAcf.pendingGroups.length ) { 40 list = document.createElement( 'ul' ); 41 42 fieldLockSyncGuardForAcf.pendingGroups.forEach( function ( group ) { 43 var item = document.createElement( 'li' ); 44 var name = document.createElement( 'strong' ); 45 46 name.textContent = group.title; 47 item.appendChild( name ); 48 item.appendChild( document.createTextNode( ' - ' + group.reason ) ); 49 list.appendChild( item ); 50 } ); 51 52 panel.appendChild( list ); 53 } 54 55 action = document.createElement( 'a' ); 56 action.className = 'button button-secondary'; 57 action.href = fieldLockSyncGuardForAcf.syncUrl; 58 action.textContent = fieldLockSyncGuardForAcf.actionLabel; 59 panel.appendChild( action ); 60 61 button.parentNode.insertBefore( panel, button ); 16 62 } ); 17 63 } -
fieldlock-sync-guard-for-acf/tags/1.1.0/fieldlock-sync-guard-for-acf.php
r3656886 r3667390 3 3 * Plugin Name: FieldLock Sync Guard for ACF 4 4 * Description: Prevents ACF field groups from being edited while Local JSON changes are waiting to be synced. 5 * Version: 1. 0.15 * Version: 1.1.0 6 6 * Requires at least: 7.0 7 7 * Requires PHP: 8.2 … … 16 16 defined( 'ABSPATH' ) || exit; 17 17 18 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1. 0.1' );18 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1.1.0' ); 19 19 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_FILE', __FILE__ ); 20 20 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_DIR', plugin_dir_path( __FILE__ ) ); -
fieldlock-sync-guard-for-acf/tags/1.1.0/includes/class-fieldlock-sync-guard-for-acf.php
r3594467 r3667390 79 79 } 80 80 81 $url = $this->get_sync_url(); 81 $url = $this->get_sync_url(); 82 $pending_groups = $this->get_pending_groups(); 82 83 ?> 83 84 <div class="notice notice-warning"> 84 85 <p> 85 86 <strong><?php esc_html_e( 'ACF Local JSON sync is pending.', 'fieldlock-sync-guard-for-acf' ); ?></strong> 86 <?php esc_html_e( 'Field-group editing is locked until the pending JSON changes are synced.', 'fieldlock-sync-guard-for-acf' ); ?> 87 <?php 88 printf( 89 /* translators: %s: Number of pending ACF field groups. */ 90 esc_html( _n( '%s field group requires syncing. Editing is locked until it is synced.', '%s field groups require syncing. Editing is locked until they are synced.', count( $pending_groups ), 'fieldlock-sync-guard-for-acf' ) ), 91 esc_html( number_format_i18n( count( $pending_groups ) ) ) 92 ); 93 ?> 87 94 <a href="<?php echo esc_url( $url ); ?>"><?php esc_html_e( 'Review field group sync', 'fieldlock-sync-guard-for-acf' ); ?></a> 88 95 </p> 96 <?php $this->render_pending_group_list( $pending_groups ); ?> 89 97 </div> 98 <?php 99 } 100 101 /** 102 * Renders the pending field-group names and reasons. 103 * 104 * @param array $pending_groups Pending field-group details. 105 */ 106 private function render_pending_group_list( $pending_groups ) { 107 if ( empty( $pending_groups ) ) { 108 return; 109 } 110 ?> 111 <ul> 112 <?php foreach ( $pending_groups as $group ) : ?> 113 <li> 114 <strong><?php echo esc_html( $group['title'] ); ?></strong> 115 — <?php echo esc_html( $this->get_pending_reason_label( $group['reason'] ) ); ?> 116 </li> 117 <?php endforeach; ?> 118 </ul> 90 119 <?php 91 120 } … … 117 146 'fieldLockSyncGuardForAcf', 118 147 array( 119 'message' => __( 'Sync the pending ACF Local JSON changes before editing field groups.', 'fieldlock-sync-guard-for-acf' ), 148 'title' => __( 'Field-group editing is locked', 'fieldlock-sync-guard-for-acf' ), 149 'message' => __( 'Sync the pending ACF Local JSON changes before editing field groups.', 'fieldlock-sync-guard-for-acf' ), 150 'actionLabel' => __( 'Review field group sync', 'fieldlock-sync-guard-for-acf' ), 151 'syncUrl' => $this->get_sync_url(), 152 'pendingGroups' => array_map( 153 function ( $group ) { 154 return array( 155 'title' => $group['title'], 156 'reason' => $this->get_pending_reason_label( $group['reason'] ), 157 ); 158 }, 159 $this->get_pending_groups() 160 ), 120 161 ) 121 162 ); … … 182 223 */ 183 224 private function has_pending_sync() { 225 return ! empty( $this->get_pending_groups() ); 226 } 227 228 /** 229 * Returns details of Local JSON field groups waiting to be synced. 230 * 231 * @return array<int,array{key:string,title:string,reason:string}> 232 */ 233 private function get_pending_groups() { 184 234 $cached = get_transient( self::TRANSIENT_KEY ); 185 235 186 if ( false !== $cached ) { 187 return '1' === $cached; 236 if ( is_string( $cached ) ) { 237 $decoded = json_decode( $cached, true ); 238 239 if ( is_array( $decoded ) ) { 240 return $decoded; 241 } 188 242 } 189 243 … … 191 245 $lifetime = (int) apply_filters( 'fieldlock_sync_guard_for_acf_cache_lifetime', MINUTE_IN_SECONDS ); 192 246 193 set_transient( self::TRANSIENT_KEY, $pending ? '1' : '0', max( 1, $lifetime ) );247 set_transient( self::TRANSIENT_KEY, wp_json_encode( $pending ), max( 1, $lifetime ) ); 194 248 195 249 return $pending; … … 199 253 * Performs the uncached Local JSON scan. 200 254 * 201 * @return bool255 * @return array<int,array{key:string,title:string,reason:string}> 202 256 */ 203 257 private function scan_for_pending_sync() { 204 258 if ( ! $this->acf_ready || ! function_exists( 'acf_get_local_json_files' ) ) { 205 return false;259 return array(); 206 260 } 207 261 … … 209 263 210 264 if ( ! is_array( $files ) || empty( $files ) ) { 211 return false;265 return array(); 212 266 } 213 267 … … 218 272 $database_groups = $this->get_database_field_groups(); 219 273 274 $pending = array(); 275 220 276 foreach ( $files as $file ) { 221 277 $item = $this->read_json_item( $file ); … … 228 284 $modified = isset( $item['modified'] ) ? (int) $item['modified'] : 0; 229 285 230 if ( ! isset( $database_groups[ $key ] ) || $modified > $database_groups[ $key ] ) { 231 return true; 232 } 233 } 234 235 return false; 286 if ( ! isset( $database_groups[ $key ] ) ) { 287 $pending[] = $this->format_pending_group( $item, 'missing' ); 288 } elseif ( $modified > $database_groups[ $key ] ) { 289 $pending[] = $this->format_pending_group( $item, 'newer' ); 290 } 291 } 292 293 return $pending; 236 294 } 237 295 … … 241 299 * This follows the same comparisons used by ACF's Sync Available screen. 242 300 * 243 * @return bool301 * @return array<int,array{key:string,title:string,reason:string}> 244 302 */ 245 303 private function scan_acf_field_groups() { … … 247 305 248 306 if ( ! is_array( $groups ) ) { 249 return false; 250 } 307 return array(); 308 } 309 310 $pending = array(); 251 311 252 312 foreach ( $groups as $group ) { … … 259 319 260 320 if ( ! $post_id ) { 261 return true; 321 $pending[] = $this->format_pending_group( $group, 'missing' ); 322 continue; 262 323 } 263 324 … … 265 326 266 327 if ( $modified && $modified > (int) $database_modified ) { 267 return true; 268 } 269 } 270 271 return false; 328 $pending[] = $this->format_pending_group( $group, 'newer' ); 329 } 330 } 331 332 return $pending; 333 } 334 335 /** 336 * Normalizes pending field-group details for caching and display. 337 * 338 * @param array $group ACF field-group data. 339 * @param string $reason Pending reason. 340 * @return array{key:string,title:string,reason:string} 341 */ 342 private function format_pending_group( $group, $reason ) { 343 $key = isset( $group['key'] ) && is_string( $group['key'] ) ? $group['key'] : ''; 344 $title = isset( $group['title'] ) && is_string( $group['title'] ) ? $group['title'] : ''; 345 346 if ( '' === $title ) { 347 $title = $key; 348 } 349 350 return array( 351 'key' => $key, 352 'title' => $title, 353 'reason' => $reason, 354 ); 355 } 356 357 /** 358 * Returns a localized label for a pending reason. 359 * 360 * @param string $reason Pending reason. 361 * @return string 362 */ 363 private function get_pending_reason_label( $reason ) { 364 if ( 'missing' === $reason ) { 365 return __( 'not yet imported into the database', 'fieldlock-sync-guard-for-acf' ); 366 } 367 368 return __( 'Local JSON is newer than the database version', 'fieldlock-sync-guard-for-acf' ); 272 369 } 273 370 -
fieldlock-sync-guard-for-acf/tags/1.1.0/readme.txt
r3656886 r3667390 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.2 7 Stable tag: 1. 0.17 Stable tag: 1.1.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 16 16 17 17 * Shows an administrator notice with a link to ACF's sync screen. 18 * Lists each pending field group and explains why it needs syncing. 18 19 * Disables the Update button on ACF field-group edit screens. 20 * Shows an inline explanation and sync link on locked edit screens. 19 21 * Blocks normal field-group saves on the server. 20 22 … … 53 55 == Changelog == 54 56 57 = 1.1.0 = 58 * List pending field groups and explain whether each group is missing or has newer Local JSON. 59 * Add clearer lock messaging and a sync link to ACF field-group edit screens. 60 55 61 = 1.0.1 = 56 62 * Confirmed compatibility with WordPress 7.1. -
fieldlock-sync-guard-for-acf/trunk/assets/js/admin-field-group-lock.js
r3594467 r3667390 10 10 11 11 buttons.forEach( function ( button ) { 12 var panel; 13 var heading; 14 var message; 15 var list; 16 var action; 17 12 18 button.disabled = true; 13 19 button.setAttribute( 'aria-disabled', 'true' ); 14 20 button.setAttribute( 'title', fieldLockSyncGuardForAcf.message ); 15 21 button.classList.add( 'disabled' ); 22 23 if ( document.querySelector( '.fieldlock-sync-guard-message' ) ) { 24 return; 25 } 26 27 panel = document.createElement( 'div' ); 28 panel.className = 'notice notice-warning inline fieldlock-sync-guard-message'; 29 30 heading = document.createElement( 'p' ); 31 heading.appendChild( document.createElement( 'strong' ) ); 32 heading.firstChild.textContent = fieldLockSyncGuardForAcf.title; 33 panel.appendChild( heading ); 34 35 message = document.createElement( 'p' ); 36 message.textContent = fieldLockSyncGuardForAcf.message; 37 panel.appendChild( message ); 38 39 if ( fieldLockSyncGuardForAcf.pendingGroups.length ) { 40 list = document.createElement( 'ul' ); 41 42 fieldLockSyncGuardForAcf.pendingGroups.forEach( function ( group ) { 43 var item = document.createElement( 'li' ); 44 var name = document.createElement( 'strong' ); 45 46 name.textContent = group.title; 47 item.appendChild( name ); 48 item.appendChild( document.createTextNode( ' - ' + group.reason ) ); 49 list.appendChild( item ); 50 } ); 51 52 panel.appendChild( list ); 53 } 54 55 action = document.createElement( 'a' ); 56 action.className = 'button button-secondary'; 57 action.href = fieldLockSyncGuardForAcf.syncUrl; 58 action.textContent = fieldLockSyncGuardForAcf.actionLabel; 59 panel.appendChild( action ); 60 61 button.parentNode.insertBefore( panel, button ); 16 62 } ); 17 63 } -
fieldlock-sync-guard-for-acf/trunk/fieldlock-sync-guard-for-acf.php
r3656886 r3667390 3 3 * Plugin Name: FieldLock Sync Guard for ACF 4 4 * Description: Prevents ACF field groups from being edited while Local JSON changes are waiting to be synced. 5 * Version: 1. 0.15 * Version: 1.1.0 6 6 * Requires at least: 7.0 7 7 * Requires PHP: 8.2 … … 16 16 defined( 'ABSPATH' ) || exit; 17 17 18 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1. 0.1' );18 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1.1.0' ); 19 19 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_FILE', __FILE__ ); 20 20 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_DIR', plugin_dir_path( __FILE__ ) ); -
fieldlock-sync-guard-for-acf/trunk/includes/class-fieldlock-sync-guard-for-acf.php
r3594467 r3667390 79 79 } 80 80 81 $url = $this->get_sync_url(); 81 $url = $this->get_sync_url(); 82 $pending_groups = $this->get_pending_groups(); 82 83 ?> 83 84 <div class="notice notice-warning"> 84 85 <p> 85 86 <strong><?php esc_html_e( 'ACF Local JSON sync is pending.', 'fieldlock-sync-guard-for-acf' ); ?></strong> 86 <?php esc_html_e( 'Field-group editing is locked until the pending JSON changes are synced.', 'fieldlock-sync-guard-for-acf' ); ?> 87 <?php 88 printf( 89 /* translators: %s: Number of pending ACF field groups. */ 90 esc_html( _n( '%s field group requires syncing. Editing is locked until it is synced.', '%s field groups require syncing. Editing is locked until they are synced.', count( $pending_groups ), 'fieldlock-sync-guard-for-acf' ) ), 91 esc_html( number_format_i18n( count( $pending_groups ) ) ) 92 ); 93 ?> 87 94 <a href="<?php echo esc_url( $url ); ?>"><?php esc_html_e( 'Review field group sync', 'fieldlock-sync-guard-for-acf' ); ?></a> 88 95 </p> 96 <?php $this->render_pending_group_list( $pending_groups ); ?> 89 97 </div> 98 <?php 99 } 100 101 /** 102 * Renders the pending field-group names and reasons. 103 * 104 * @param array $pending_groups Pending field-group details. 105 */ 106 private function render_pending_group_list( $pending_groups ) { 107 if ( empty( $pending_groups ) ) { 108 return; 109 } 110 ?> 111 <ul> 112 <?php foreach ( $pending_groups as $group ) : ?> 113 <li> 114 <strong><?php echo esc_html( $group['title'] ); ?></strong> 115 — <?php echo esc_html( $this->get_pending_reason_label( $group['reason'] ) ); ?> 116 </li> 117 <?php endforeach; ?> 118 </ul> 90 119 <?php 91 120 } … … 117 146 'fieldLockSyncGuardForAcf', 118 147 array( 119 'message' => __( 'Sync the pending ACF Local JSON changes before editing field groups.', 'fieldlock-sync-guard-for-acf' ), 148 'title' => __( 'Field-group editing is locked', 'fieldlock-sync-guard-for-acf' ), 149 'message' => __( 'Sync the pending ACF Local JSON changes before editing field groups.', 'fieldlock-sync-guard-for-acf' ), 150 'actionLabel' => __( 'Review field group sync', 'fieldlock-sync-guard-for-acf' ), 151 'syncUrl' => $this->get_sync_url(), 152 'pendingGroups' => array_map( 153 function ( $group ) { 154 return array( 155 'title' => $group['title'], 156 'reason' => $this->get_pending_reason_label( $group['reason'] ), 157 ); 158 }, 159 $this->get_pending_groups() 160 ), 120 161 ) 121 162 ); … … 182 223 */ 183 224 private function has_pending_sync() { 225 return ! empty( $this->get_pending_groups() ); 226 } 227 228 /** 229 * Returns details of Local JSON field groups waiting to be synced. 230 * 231 * @return array<int,array{key:string,title:string,reason:string}> 232 */ 233 private function get_pending_groups() { 184 234 $cached = get_transient( self::TRANSIENT_KEY ); 185 235 186 if ( false !== $cached ) { 187 return '1' === $cached; 236 if ( is_string( $cached ) ) { 237 $decoded = json_decode( $cached, true ); 238 239 if ( is_array( $decoded ) ) { 240 return $decoded; 241 } 188 242 } 189 243 … … 191 245 $lifetime = (int) apply_filters( 'fieldlock_sync_guard_for_acf_cache_lifetime', MINUTE_IN_SECONDS ); 192 246 193 set_transient( self::TRANSIENT_KEY, $pending ? '1' : '0', max( 1, $lifetime ) );247 set_transient( self::TRANSIENT_KEY, wp_json_encode( $pending ), max( 1, $lifetime ) ); 194 248 195 249 return $pending; … … 199 253 * Performs the uncached Local JSON scan. 200 254 * 201 * @return bool255 * @return array<int,array{key:string,title:string,reason:string}> 202 256 */ 203 257 private function scan_for_pending_sync() { 204 258 if ( ! $this->acf_ready || ! function_exists( 'acf_get_local_json_files' ) ) { 205 return false;259 return array(); 206 260 } 207 261 … … 209 263 210 264 if ( ! is_array( $files ) || empty( $files ) ) { 211 return false;265 return array(); 212 266 } 213 267 … … 218 272 $database_groups = $this->get_database_field_groups(); 219 273 274 $pending = array(); 275 220 276 foreach ( $files as $file ) { 221 277 $item = $this->read_json_item( $file ); … … 228 284 $modified = isset( $item['modified'] ) ? (int) $item['modified'] : 0; 229 285 230 if ( ! isset( $database_groups[ $key ] ) || $modified > $database_groups[ $key ] ) { 231 return true; 232 } 233 } 234 235 return false; 286 if ( ! isset( $database_groups[ $key ] ) ) { 287 $pending[] = $this->format_pending_group( $item, 'missing' ); 288 } elseif ( $modified > $database_groups[ $key ] ) { 289 $pending[] = $this->format_pending_group( $item, 'newer' ); 290 } 291 } 292 293 return $pending; 236 294 } 237 295 … … 241 299 * This follows the same comparisons used by ACF's Sync Available screen. 242 300 * 243 * @return bool301 * @return array<int,array{key:string,title:string,reason:string}> 244 302 */ 245 303 private function scan_acf_field_groups() { … … 247 305 248 306 if ( ! is_array( $groups ) ) { 249 return false; 250 } 307 return array(); 308 } 309 310 $pending = array(); 251 311 252 312 foreach ( $groups as $group ) { … … 259 319 260 320 if ( ! $post_id ) { 261 return true; 321 $pending[] = $this->format_pending_group( $group, 'missing' ); 322 continue; 262 323 } 263 324 … … 265 326 266 327 if ( $modified && $modified > (int) $database_modified ) { 267 return true; 268 } 269 } 270 271 return false; 328 $pending[] = $this->format_pending_group( $group, 'newer' ); 329 } 330 } 331 332 return $pending; 333 } 334 335 /** 336 * Normalizes pending field-group details for caching and display. 337 * 338 * @param array $group ACF field-group data. 339 * @param string $reason Pending reason. 340 * @return array{key:string,title:string,reason:string} 341 */ 342 private function format_pending_group( $group, $reason ) { 343 $key = isset( $group['key'] ) && is_string( $group['key'] ) ? $group['key'] : ''; 344 $title = isset( $group['title'] ) && is_string( $group['title'] ) ? $group['title'] : ''; 345 346 if ( '' === $title ) { 347 $title = $key; 348 } 349 350 return array( 351 'key' => $key, 352 'title' => $title, 353 'reason' => $reason, 354 ); 355 } 356 357 /** 358 * Returns a localized label for a pending reason. 359 * 360 * @param string $reason Pending reason. 361 * @return string 362 */ 363 private function get_pending_reason_label( $reason ) { 364 if ( 'missing' === $reason ) { 365 return __( 'not yet imported into the database', 'fieldlock-sync-guard-for-acf' ); 366 } 367 368 return __( 'Local JSON is newer than the database version', 'fieldlock-sync-guard-for-acf' ); 272 369 } 273 370 -
fieldlock-sync-guard-for-acf/trunk/readme.txt
r3656886 r3667390 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.2 7 Stable tag: 1. 0.17 Stable tag: 1.1.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 16 16 17 17 * Shows an administrator notice with a link to ACF's sync screen. 18 * Lists each pending field group and explains why it needs syncing. 18 19 * Disables the Update button on ACF field-group edit screens. 20 * Shows an inline explanation and sync link on locked edit screens. 19 21 * Blocks normal field-group saves on the server. 20 22 … … 53 55 == Changelog == 54 56 57 = 1.1.0 = 58 * List pending field groups and explain whether each group is missing or has newer Local JSON. 59 * Add clearer lock messaging and a sync link to ACF field-group edit screens. 60 55 61 = 1.0.1 = 56 62 * Confirmed compatibility with WordPress 7.1.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)