Plugin Directory

Changeset 3667390


Ignore:
Timestamp:
08/26/2026 03:36:10 PM (2 months ago)
Author:
shanemuir
Message:

Update to 1.1.0

Location:
fieldlock-sync-guard-for-acf
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • fieldlock-sync-guard-for-acf/tags/1.1.0/assets/js/admin-field-group-lock.js

    r3594467 r3667390  
    1010
    1111                buttons.forEach( function ( button ) {
     12                        var panel;
     13                        var heading;
     14                        var message;
     15                        var list;
     16                        var action;
     17
    1218                        button.disabled = true;
    1319                        button.setAttribute( 'aria-disabled', 'true' );
    1420                        button.setAttribute( 'title', fieldLockSyncGuardForAcf.message );
    1521                        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 );
    1662                } );
    1763        }
  • fieldlock-sync-guard-for-acf/tags/1.1.0/fieldlock-sync-guard-for-acf.php

    r3656886 r3667390  
    33 * Plugin Name:       FieldLock Sync Guard for ACF
    44 * Description:       Prevents ACF field groups from being edited while Local JSON changes are waiting to be synced.
    5  * Version:           1.0.1
     5 * Version:           1.1.0
    66 * Requires at least: 7.0
    77 * Requires PHP:      8.2
    … …  
    1616defined( 'ABSPATH' ) || exit;
    1717
    18 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1.0.1' );
     18define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1.1.0' );
    1919define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_FILE', __FILE__ );
    2020define( '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  
    7979                }
    8080
    81                 $url = $this->get_sync_url();
     81                $url            = $this->get_sync_url();
     82                $pending_groups = $this->get_pending_groups();
    8283                ?>
    8384                <div class="notice notice-warning">
    8485                        <p>
    8586                                <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                                ?>
    8794                                <a href="<?php echo esc_url( $url ); ?>"><?php esc_html_e( 'Review field group sync', 'fieldlock-sync-guard-for-acf' ); ?></a>
    8895                        </p>
     96                        <?php $this->render_pending_group_list( $pending_groups ); ?>
    8997                </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                                        &mdash; <?php echo esc_html( $this->get_pending_reason_label( $group['reason'] ) ); ?>
     116                                </li>
     117                        <?php endforeach; ?>
     118                </ul>
    90119                <?php
    91120        }
    … …  
    117146                        'fieldLockSyncGuardForAcf',
    118147                        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                                ),
    120161                        )
    121162                );
    … …  
    182223         */
    183224        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() {
    184234                $cached = get_transient( self::TRANSIENT_KEY );
    185235
    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                        }
    188242                }
    189243
    … …  
    191245                $lifetime = (int) apply_filters( 'fieldlock_sync_guard_for_acf_cache_lifetime', MINUTE_IN_SECONDS );
    192246
    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 ) );
    194248
    195249                return $pending;
    … …  
    199253         * Performs the uncached Local JSON scan.
    200254         *
    201          * @return bool
     255         * @return array<int,array{key:string,title:string,reason:string}>
    202256         */
    203257        private function scan_for_pending_sync() {
    204258                if ( ! $this->acf_ready || ! function_exists( 'acf_get_local_json_files' ) ) {
    205                         return false;
     259                        return array();
    206260                }
    207261
    … …  
    209263
    210264                if ( ! is_array( $files ) || empty( $files ) ) {
    211                         return false;
     265                        return array();
    212266                }
    213267
    … …  
    218272                $database_groups = $this->get_database_field_groups();
    219273
     274                $pending = array();
     275
    220276                foreach ( $files as $file ) {
    221277                        $item = $this->read_json_item( $file );
    … …  
    228284                        $modified = isset( $item['modified'] ) ? (int) $item['modified'] : 0;
    229285
    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;
    236294        }
    237295
    … …  
    241299         * This follows the same comparisons used by ACF's Sync Available screen.
    242300         *
    243          * @return bool
     301         * @return array<int,array{key:string,title:string,reason:string}>
    244302         */
    245303        private function scan_acf_field_groups() {
    … …  
    247305
    248306                if ( ! is_array( $groups ) ) {
    249                         return false;
    250                 }
     307                        return array();
     308                }
     309
     310                $pending = array();
    251311
    252312                foreach ( $groups as $group ) {
    … …  
    259319
    260320                        if ( ! $post_id ) {
    261                                 return true;
     321                                $pending[] = $this->format_pending_group( $group, 'missing' );
     322                                continue;
    262323                        }
    263324
    … …  
    265326
    266327                        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' );
    272369        }
    273370
  • fieldlock-sync-guard-for-acf/tags/1.1.0/readme.txt

    r3656886 r3667390  
    55Tested up to: 7.1
    66Requires PHP: 8.2
    7 Stable tag: 1.0.1
     7Stable tag: 1.1.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    1616
    1717* Shows an administrator notice with a link to ACF's sync screen.
     18* Lists each pending field group and explains why it needs syncing.
    1819* Disables the Update button on ACF field-group edit screens.
     20* Shows an inline explanation and sync link on locked edit screens.
    1921* Blocks normal field-group saves on the server.
    2022
    … …  
    5355== Changelog ==
    5456
     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
    5561= 1.0.1 =
    5662* Confirmed compatibility with WordPress 7.1.
  • fieldlock-sync-guard-for-acf/trunk/assets/js/admin-field-group-lock.js

    r3594467 r3667390  
    1010
    1111                buttons.forEach( function ( button ) {
     12                        var panel;
     13                        var heading;
     14                        var message;
     15                        var list;
     16                        var action;
     17
    1218                        button.disabled = true;
    1319                        button.setAttribute( 'aria-disabled', 'true' );
    1420                        button.setAttribute( 'title', fieldLockSyncGuardForAcf.message );
    1521                        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 );
    1662                } );
    1763        }
  • fieldlock-sync-guard-for-acf/trunk/fieldlock-sync-guard-for-acf.php

    r3656886 r3667390  
    33 * Plugin Name:       FieldLock Sync Guard for ACF
    44 * Description:       Prevents ACF field groups from being edited while Local JSON changes are waiting to be synced.
    5  * Version:           1.0.1
     5 * Version:           1.1.0
    66 * Requires at least: 7.0
    77 * Requires PHP:      8.2
    … …  
    1616defined( 'ABSPATH' ) || exit;
    1717
    18 define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1.0.1' );
     18define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_VERSION', '1.1.0' );
    1919define( 'FIELDLOCK_SYNC_GUARD_FOR_ACF_FILE', __FILE__ );
    2020define( '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  
    7979                }
    8080
    81                 $url = $this->get_sync_url();
     81                $url            = $this->get_sync_url();
     82                $pending_groups = $this->get_pending_groups();
    8283                ?>
    8384                <div class="notice notice-warning">
    8485                        <p>
    8586                                <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                                ?>
    8794                                <a href="<?php echo esc_url( $url ); ?>"><?php esc_html_e( 'Review field group sync', 'fieldlock-sync-guard-for-acf' ); ?></a>
    8895                        </p>
     96                        <?php $this->render_pending_group_list( $pending_groups ); ?>
    8997                </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                                        &mdash; <?php echo esc_html( $this->get_pending_reason_label( $group['reason'] ) ); ?>
     116                                </li>
     117                        <?php endforeach; ?>
     118                </ul>
    90119                <?php
    91120        }
    … …  
    117146                        'fieldLockSyncGuardForAcf',
    118147                        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                                ),
    120161                        )
    121162                );
    … …  
    182223         */
    183224        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() {
    184234                $cached = get_transient( self::TRANSIENT_KEY );
    185235
    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                        }
    188242                }
    189243
    … …  
    191245                $lifetime = (int) apply_filters( 'fieldlock_sync_guard_for_acf_cache_lifetime', MINUTE_IN_SECONDS );
    192246
    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 ) );
    194248
    195249                return $pending;
    … …  
    199253         * Performs the uncached Local JSON scan.
    200254         *
    201          * @return bool
     255         * @return array<int,array{key:string,title:string,reason:string}>
    202256         */
    203257        private function scan_for_pending_sync() {
    204258                if ( ! $this->acf_ready || ! function_exists( 'acf_get_local_json_files' ) ) {
    205                         return false;
     259                        return array();
    206260                }
    207261
    … …  
    209263
    210264                if ( ! is_array( $files ) || empty( $files ) ) {
    211                         return false;
     265                        return array();
    212266                }
    213267
    … …  
    218272                $database_groups = $this->get_database_field_groups();
    219273
     274                $pending = array();
     275
    220276                foreach ( $files as $file ) {
    221277                        $item = $this->read_json_item( $file );
    … …  
    228284                        $modified = isset( $item['modified'] ) ? (int) $item['modified'] : 0;
    229285
    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;
    236294        }
    237295
    … …  
    241299         * This follows the same comparisons used by ACF's Sync Available screen.
    242300         *
    243          * @return bool
     301         * @return array<int,array{key:string,title:string,reason:string}>
    244302         */
    245303        private function scan_acf_field_groups() {
    … …  
    247305
    248306                if ( ! is_array( $groups ) ) {
    249                         return false;
    250                 }
     307                        return array();
     308                }
     309
     310                $pending = array();
    251311
    252312                foreach ( $groups as $group ) {
    … …  
    259319
    260320                        if ( ! $post_id ) {
    261                                 return true;
     321                                $pending[] = $this->format_pending_group( $group, 'missing' );
     322                                continue;
    262323                        }
    263324
    … …  
    265326
    266327                        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' );
    272369        }
    273370
  • fieldlock-sync-guard-for-acf/trunk/readme.txt

    r3656886 r3667390  
    55Tested up to: 7.1
    66Requires PHP: 8.2
    7 Stable tag: 1.0.1
     7Stable tag: 1.1.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    1616
    1717* Shows an administrator notice with a link to ACF's sync screen.
     18* Lists each pending field group and explains why it needs syncing.
    1819* Disables the Update button on ACF field-group edit screens.
     20* Shows an inline explanation and sync link on locked edit screens.
    1921* Blocks normal field-group saves on the server.
    2022
    … …  
    5355== Changelog ==
    5456
     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
    5561= 1.0.1 =
    5662* Confirmed compatibility with WordPress 7.1.
Note: See TracChangeset for help on using the changeset viewer.