diff --git a/includes/extensions/edit-entry/class-edit-entry-locking.php b/includes/extensions/edit-entry/class-edit-entry-locking.php index 8382df6797..3aee253764 100644 --- a/includes/extensions/edit-entry/class-edit-entry-locking.php +++ b/includes/extensions/edit-entry/class-edit-entry-locking.php @@ -1,6 +1,10 @@ request_lock( $object_id ); - echo json_encode( $response ); - die(); + + $response = $this->request_lock( $object_id ); + + wp_send_json( $response ); } // TODO: Convert to extending Gravity Forms public function ajax_reject_lock_request() { $object_id = rgget( 'object_id' ); - $response = $this->delete_lock_request_meta( $object_id ); - echo json_encode( $response ); - die(); + + $response = $this->delete_lock_request_meta( $object_id ); + + wp_send_json( $response ); } // TODO: Convert to extending Gravity Forms @@ -65,28 +90,42 @@ protected function request_lock( $object_id ) { $lock_holder_user_id = $this->check_lock( $object_id ); - $result = array(); + $result = []; + if ( ! $lock_holder_user_id ) { $this->set_lock( $object_id ); + $result['html'] = __( 'You now have control', 'gk-gravityview' ); $result['status'] = 'lock_obtained'; - } else { - if ( GVCommon::has_cap( 'gravityforms_edit_entries' ) ) { - $user = get_userdata( $lock_holder_user_id ); - $result['html'] = sprintf( __( 'Your request has been sent to %s.', 'gk-gravityview' ), $user->display_name ); - } else { - $result['html'] = __( 'Your request has been sent.', 'gk-gravityview' ); - } + return $result; + } - $this->update_lock_request_meta( $object_id, $user_id ); + if ( GVCommon::has_cap( 'gravityforms_edit_entries' ) ) { + $user = get_userdata( $lock_holder_user_id ); - $result['status'] = 'lock_requested'; + $result['html'] = sprintf( __( 'Your request has been sent to %s.', 'gk-gravityview' ), $user->display_name ); + } else { + $result['html'] = __( 'Your request has been sent.', 'gk-gravityview' ); } + $this->update_lock_request_meta( $object_id, $user_id ); + + $result['status'] = 'lock_requested'; + return $result; } + /** + * Updates the lock request meta for an object. + * + * @since 2.34 + * + * @param string $object_id + * @param string $lock_request_value + * + * @return void + */ protected function update_lock_request_meta( $object_id, $lock_request_value ) { GFCache::set( 'lock_request_entry_' . $object_id, $lock_request_value, true, 120 ); } @@ -97,6 +136,8 @@ protected function update_lock_request_meta( $object_id, $lock_request_value ) { * - Is it Edit Entry? * - Is the entry connected to a View that has `edit_locking` enabled? * - Is the entry connected to a form connected to a currently-loaded View? + * - Does the user have the capability to edit the entry? + * - Is the nonce valid? * * @internal * @since 2.7 @@ -112,47 +153,59 @@ public function maybe_enqueue_scripts() { return; } + $entry = $entry->as_entry(); + + /** + * Overrides whether to load the entry lock UI assets. + * This filter runs before checking whether if the edit entry link is valid, user has the capability to edit the entry, etc. + * + * Filter: `gk/gravityview/edit-entry/renderer/enqueue-entry-lock-assets` + * + * @since TBD + * + * @param bool $load Whether to load the entry lock UI assets. Default: false. + * @param array $entry The entry. + */ + if ( apply_filters( 'gk/gravityview/edit-entry/renderer/enqueue-entry-lock-assets', false, $entry ) ) { + $this->enqueue_scripts( $entry ); + } + if ( ! $post || ! is_a( $post, 'WP_Post' ) ) { return; } - $views = \GV\View_Collection::from_post( $post ); - - $entry_array = $entry->as_entry(); + $views = View_Collection::from_post( $post ); - $continue_enqueuing = false; - - // If any Views being loaded have entry locking, enqueue the scripts + // If any Views being loaded have entry locking, enqueue the scripts. foreach ( $views->all() as $view ) { - // Make sure the View has edit locking enabled if ( ! $view->settings->get( 'edit_locking' ) ) { continue; } - // Make sure that the entry belongs to one of the forms connected to one of the Views in this request - $joined_forms = $view::get_joined_forms( $view->ID ); + // Make sure that the entry belongs to the View form. + if ( $view->form->ID !== (int) $entry['form_id'] ) { + continue; + } - $entry_form_id = $entry_array['form_id']; + // Check user capabilities. + if ( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $entry, $view ) ) { + continue; + } - if ( ! isset( $joined_forms[ $entry_form_id ] ) ) { + // Check the nonce. + if ( ! ( new GravityView_Edit_Entry_Render( GravityView_Edit_Entry::getInstance() ) )->verify_nonce() ) { continue; } - $continue_enqueuing = true; + $this->enqueue_scripts( $entry ); break; } - - if ( ! $continue_enqueuing ) { - return; - } - - $this->enqueue_scripts( $entry_array ); } /** - * Enqueue the required scripts and styles from Gravity Forms. + * Enqueues the required scripts and styles from Gravity Forms. * * Called via load() and `wp_enqueue_scripts` * @@ -163,33 +216,52 @@ public function maybe_enqueue_scripts() { * @return void */ protected function enqueue_scripts( $entry ) { + $lock_user_id = $this->check_lock( $entry['id'] ); + + // Gravity forms locking checks if #wpwrap exist in the admin dashboard, + // So we have to add the lock UI to the body before the gforms locking script is loaded. + wp_add_inline_script( 'heartbeat', ' + jQuery(document).ready(function($) { + if ($("#wpwrap").length === 0) { + var lockUI = ' . json_encode( $this->get_lock_ui( $lock_user_id, $entry ) ) . '; + $("body").prepend(lockUI); + } + }); + ' ); $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min'; $locking_path = GFCommon::get_base_url() . '/includes/locking/'; - wp_enqueue_script( 'gforms_locking', $locking_path . "js/locking{$min}.js", array( 'jquery', 'heartbeat' ), GFCommon::$version ); - wp_enqueue_style( 'gforms_locking_css', $locking_path . "css/locking{$min}.css", array( 'edit' ), GFCommon::$version ); + wp_enqueue_script( 'gforms_locking', $locking_path . "js/locking{$min}.js", [ 'jquery', 'heartbeat' ], GFCommon::$version ); + wp_enqueue_style( 'gforms_locking_css', $locking_path . "css/locking{$min}.css", [ 'edit' ], GFCommon::$version ); + + // add inline css to hide notification-dialog-wrap if it has the hidden class + wp_add_inline_style( 'gforms_locking_css', ' + .notification-dialog-wrap.hidden { + display: none; + } + ' ); $translations = array_map( 'wp_strip_all_tags', $this->get_strings() ); - $strings = array( + $strings = [ 'noResponse' => $translations['no_response'], 'requestAgain' => $translations['request_again'], 'requestError' => $translations['request_error'], 'gainedControl' => $translations['gained_control'], 'rejected' => $translations['request_rejected'], 'pending' => $translations['request_pending'], - ); + ]; $lock_user_id = $this->check_lock( $entry['id'] ); - $vars = array( + $vars = [ 'hasLock' => ! $lock_user_id ? 1 : 0, - 'lockUI' => $this->get_lock_ui( $lock_user_id ), + 'lockUI' => $this->get_lock_ui( $lock_user_id, $entry ), 'objectID' => $entry['id'], 'objectType' => 'entry', 'strings' => $strings, - ); + ]; wp_localize_script( 'gforms_locking', 'gflockingVars', $vars ); } @@ -197,26 +269,27 @@ protected function enqueue_scripts( $entry ) { /** * Returns a string with the Lock UI HTML markup. * - * Called script enqueuing, added to JavaScript gforms_locking global variable. + * Called script enqueuing, added to JavaScript `gforms_locking` global variable. * * @since 2.5.2 * - * @see GravityView_Edit_Entry_Locking::check_lock + * @see GravityView_Edit_Entry_Locking::check_lock * - * @param int $user_id The User ID that has the current lock. Will be empty if entry is not locked - * or is locked to the current user. + * @param int $user_id The User ID that has the current lock. Will be empty if entry is not locked + * or is locked to the current user. + * @param array $entry The entry array. * * @return string The Lock UI dialog box, etc. */ - public function get_lock_ui( $user_id ) { + public function get_lock_ui( $user_id, $entry ) { $user = get_userdata( $user_id ); $locked = $user_id && $user; $hidden = $locked ? '' : ' hidden'; - if ( $locked ) { - if ( GVCommon::has_cap( 'gravityforms_edit_entries' ) ) { + if ( $locked ) { + if ( GVCommon::has_cap( 'gravityforms_edit_entries' ) || $entry['created_by'] == get_current_user_id() ) { $avatar = get_avatar( $user->ID, 64 ); $person_editing_text = $user->display_name; } else { @@ -229,7 +302,6 @@ public function get_lock_ui( $user_id ) {
' . $avatar . '

' . esc_html( sprintf( $this->get_string( 'currently_locked' ), $person_editing_text ) ) . '

- ' . esc_html( $this->get_string( 'cancel' ) ) . ' @@ -238,9 +310,7 @@ public function get_lock_ui( $user_id ) { '; - } else { - $message = '

@@ -253,28 +323,33 @@ public function get_lock_ui( $user_id ) {

'; } - $html = '
-
-
'; - $html .= $message; - - $html .= '
-
'; - return $html; + $html = '
+
+
' . $message . '
'; + $html .= '
'; + + /** + * Modifies the edit entry lock UI markup. + * + * @filter `gk/gravityview/edit-entry/renderer/entry-lock-dialog-markup` + * + * @since TBD + * + * @param string $html The HTML markup. + */ + return apply_filters( 'gk/gravityview/edit-entry/renderer/entry-lock-dialog-markup', $html ); } /** - * Localized string for the UI. - * - * Uses gravityforms textdomain unchanged. + * Returns localized text strings used in the UI. * * @since 2.5.2 * * @return array An array of translations. */ public function get_strings() { - $translations = array( + $translations = [ 'currently_locked' => __( 'This entry is currently locked. Click on the "Request Control" button to let %s know you\'d like to take over.', 'gk-gravityview' ), 'currently_editing' => __( '%s is currently editing this entry', 'gk-gravityview' ), 'taken_over' => __( '%s has taken over and is currently editing this entry.', 'gk-gravityview' ), @@ -287,7 +362,7 @@ public function get_strings() { 'request_again' => __( 'Request again', 'gk-gravityview' ), 'request_error' => __( 'Error', 'gk-gravityview' ), 'request_rejected' => __( 'Your request was rejected', 'gk-gravityview' ), - ); + ]; $translations = array_map( 'wp_strip_all_tags', $translations ); @@ -295,105 +370,145 @@ public function get_strings() { } /** - * Get a localized string. + * Returns a localized string. * * @param string $string The string to get. * * @return string A localized string. See self::get_strings() */ public function get_string( $string ) { - return \GV\Utils::get( $this->get_strings(), $string, '' ); + return Utils::get( $this->get_strings(), $string, '' ); } /** - * Lock the entry... maybe. + * Locks the entry... maybe. * * Has 3 modes of locking: - * * - acquire (get), which reloads the page after locking the entry * - release, which reloads the page after unlocking the entry * - default action to lock on load if not locked * + * @since 2.34 + * * @param int $entry_id The entry ID. * * @return void */ public function maybe_lock_object( $entry_id ) { - global $wp; - - $current_url = add_query_arg( $wp->query_string, '', home_url( $wp->request ) ); + $current_url = home_url( add_query_arg( null, null ) ); if ( isset( $_GET['get-edit-lock'] ) ) { $this->set_lock( $entry_id ); + echo ''; + exit(); } elseif ( isset( $_GET['release-edit-lock'] ) ) { $this->delete_lock_meta( $entry_id ); + $current_url = remove_query_arg( 'edit', $current_url ); + echo ''; + exit(); - } elseif ( ! $user_id = $this->check_lock( $entry_id ) ) { - $this->set_lock( $entry_id ); + } elseif ( ! $this->check_lock( $entry_id ) ) { + $this->set_lock( $entry_id ); } } /** - * Is this entry locked to some other user? + * Checks if this entry is locked to some other user. + * + * @since TBD * * @param int $entry_id The entry ID. * * @return boolean Yes or no. */ public function check_lock( $entry_id ) { - if ( ! $user_id = $this->get_lock_meta( $entry_id ) ) { + $user_id = $this->get_lock_meta( $entry_id ); + + if ( ! $user_id || $user_id == get_current_user_id() ) { return false; } - if ( $user_id != get_current_user_id() ) { - return $user_id; + return $user_id; + } + + /** + * Check if the current user has a lock request for an object. + * + * @since TBD + * + * @param int $object_id The object ID. + * + * @return int|false The User ID or false. + */ + protected function check_lock_request( $object_id ) { + $user_id = (int) $this->get_lock_request_meta( $object_id ); + + if ( ! $user_id || $user_id === get_current_user_id() ) { + return false; } - return false; + return $user_id; } /** - * The lock for an entry. + * Returns the lock status by leveraging GF's persistent caching mechanism. * - * Leverages Gravity Forms' persistent caching mechanisms. + * @since TBD * * @param int $entry_id The entry ID. * * @return int|null The User ID or null. */ public function get_lock_meta( $entry_id ) { - return GFCache::get( 'lock_entry_' . $entry_id ); + return GFCache::get( $this->get_lock_cache_key_for_entry( $entry_id ) ); } /** - * Set the lock for an entry. + * Sets the lock for an entry. + * + * @since TBD * * @param int $entry_id The entry ID. - * @param int $user_id The user ID to lock the entry to. + * @param int $user_id The user ID to lock the entry to. * * @return void */ public function update_lock_meta( $entry_id, $user_id ) { - GFCache::set( 'lock_entry_' . $entry_id, $user_id, true, 1500 ); + GFCache::set( $this->get_lock_cache_key_for_entry( $entry_id ), $user_id, true, 1500 ); } /** - * Release the lock for an entry. + * Returns the cache key used to retrieve/save the lock status for an entry. + * + * @since TBD + * + * @param int $entry_id + * + * @return string + */ + public function get_lock_cache_key_for_entry( $entry_id ) { + return self::LOCK_CACHE_KEY_PREFIX . $entry_id; + } + + /** + * Releases the lock for an entry. + * + * @since TBD * * @param int $entry_id The entry ID. * * @return void */ public function delete_lock_meta( $entry_id ) { - GFCache::delete( 'lock_entry_' . $entry_id ); + GFCache::delete( $this->get_lock_cache_key_for_entry( $entry_id ) ); } /** - * Lock the entry to the current user. + * Locks the entry to the current user. * * @since 2.5.2 * @@ -402,7 +517,6 @@ public function delete_lock_meta( $entry_id ) { * @return int|false Locked or not. */ public function set_lock( $entry_id ) { - $entry = GFAPI::get_entry( $entry_id ); if ( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $entry ) ) { @@ -417,4 +531,182 @@ public function set_lock( $entry_id ) { return $user_id; } + + /** + * Checks if the objects are locked. + * + * @since TBD + * + * @param array $response The response array. + * @param array $data The data array. + * + * @return array The response array. + */ + public function heartbeat_check_locked_objects( $response, $data ) { + $checked = []; + + $heartbeat_key = 'gform-check-locked-objects-entry'; + + if ( array_key_exists( $heartbeat_key, $data ) && is_array( $data[ $heartbeat_key ] ) ) { + foreach ( $data[ $heartbeat_key ] as $object_id ) { + if ( ( $user_id = $this->check_lock( $object_id ) ) && ( $user = get_userdata( $user_id ) ) ) { + $send = [ 'text' => sprintf( __( $this->get_string( 'currently_editing' ) ), $user->display_name ) ]; + + if ( ( $avatar = get_avatar( $user->ID, 18 ) ) && preg_match( "|src='([^']+)'|", $avatar, $matches ) ) { + $send['avatar_src'] = $matches[1]; + } + + $checked[ $object_id ] = $send; + } + } + } + + if ( ! empty( $checked ) ) { + $response[ $heartbeat_key ] = $checked; + } + + return $response; + } + + /** + * Refreshes the lock for an entry. + * + * @since TBD + * + * @param array $response The response array. + * @param array $data The data array. + * + * @return array The response array. + */ + public function heartbeat_refresh_lock( $response, $data ) { + $heartbeat_key = 'gform-refresh-lock-entry'; + + if ( array_key_exists( $heartbeat_key, $data ) ) { + $received = $data[ $heartbeat_key ]; + + $send = []; + + if ( ! isset( $received['objectID'] ) ) { + return $response; + } + + $object_id = $received['objectID']; + + if ( ( $user_id = $this->check_lock( $object_id ) ) && ( $user = get_userdata( $user_id ) ) ) { + $error = [ + 'text' => sprintf( __( $this->get_string( 'taken_over' ) ), $user->display_name ), + ]; + + $avatar = get_avatar( $user->ID, 64 ); + + if ( $avatar && preg_match( "|src='([^']+)'|", $avatar, $matches ) ) { + $error['avatar_src'] = $matches[1]; + } + + $send['lock_error'] = $error; + } elseif ( $new_lock = $this->set_lock( $object_id ) ) { + $send['new_lock'] = $new_lock; + + if ( ( $lock_requester = $this->check_lock_request( $object_id ) ) && ( $user = get_userdata( $lock_requester ) ) ) { + $lock_request = [ + 'text' => sprintf( __( $this->get_string( 'lock_requested' ) ), $user->display_name ), + ]; + + $avatar = get_avatar( $user->ID, 64 ); + + if ( $avatar && preg_match( "|src='([^']+)'|", $avatar, $matches ) ) { + $lock_request['avatar_src'] = $matches[1]; + } + + $send['lock_request'] = $lock_request; + } + } + + $response[ $heartbeat_key ] = $send; + } + + return $response; + } + + /** + * Requests the lock for an entry. + * + * @since TBD + * + * @param array $response The response array. + * @param array $data The data array. + * @param string $screen_id The screen ID. + * + * @return array The response array. + */ + public function heartbeat_request_lock( $response, $data ) { + $heartbeat_key = 'gform-request-lock-entry'; + + if ( ! array_key_exists( $heartbeat_key, $data ) ) { + return $response; + } + + $received = $data[ $heartbeat_key ]; + + $send = []; + + if ( ! isset( $received['objectID'] ) ) { + return $response; + } + + $object_id = $received['objectID']; + + $user_id = $this->check_lock( $object_id ); + + if ( $user_id && get_userdata( $user_id ) ) { + $send['status'] = $this->get_lock_request_meta( $object_id ) ? 'pending' : 'deleted'; + } elseif ( $this->set_lock( $object_id ) ) { + $send['status'] = 'granted'; + } + + $response[ $heartbeat_key ] = $send; + + return $response; + } + + /** + * Refreshes nonces for an entry. + * + * @since TBD + * + * @param array $response The response array. + * @param array $data The data array. + * + * @return array The response array. + */ + public function heartbeat_refresh_nonces( $response, $data ) { + if ( ! array_key_exists( 'gform-refresh-nonces', $data ) ) { + return $response; + } + + $received = $data['gform-refresh-nonces']; + + $response['gform-refresh-nonces'] = [ 'check' => 1 ]; + + if ( ! isset( $received['objectID'] ) ) { + return $response; + } + + $object_id = $received['objectID']; + + if ( ! GVCommon::has_cap( 'gravityforms_edit_entries' ) || empty( $received['post_nonce'] ) ) { + return $response; + } + + if ( 2 === wp_verify_nonce( $received['object_nonce'], 'update-contact_' . $object_id ) ) { + $response['gform-refresh-nonces'] = [ + 'replace' => [ + '_wpnonce' => wp_create_nonce( 'update-object_' . $object_id ), + ], + 'heartbeatNonce' => wp_create_nonce( 'heartbeat-nonce' ), + ]; + } + + return $response; + } } diff --git a/includes/extensions/edit-entry/class-edit-entry.php b/includes/extensions/edit-entry/class-edit-entry.php index 7c531a4f76..5a8dba7210 100644 --- a/includes/extensions/edit-entry/class-edit-entry.php +++ b/includes/extensions/edit-entry/class-edit-entry.php @@ -352,7 +352,7 @@ function get_field_blocklist( $entry = array() ) { /** * checks if user has permissions to edit a specific entry * - * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_entry for maximum security!! + * Needs to be used combined with GravityView_Edit_Entry_Render::user_can_edit_entry for maximum security!! * * @param array|\WP_Error $entry Gravity Forms entry array or WP_Error if the entry wasn't found. * @param \GV\View|int $view ID of the view you want to check visibility against {@since 1.9.2}. Required since 2.0. @@ -403,7 +403,7 @@ public static function check_user_cap_edit_entry( $entry, $view = 0 ) { $current_user = wp_get_current_user(); // User edit is disabled - if ( empty( $user_edit ) ) { + if ( $view_id && empty( $user_edit ) ) { gravityview()->log->debug( 'User Edit is disabled. Returning false.' ); diff --git a/includes/extensions/lightbox-entry/class-gravityview-lightbox-entry.php b/includes/extensions/lightbox-entry/class-gravityview-lightbox-entry.php index 2f752cda2e..172c9f5ca2 100644 --- a/includes/extensions/lightbox-entry/class-gravityview-lightbox-entry.php +++ b/includes/extensions/lightbox-entry/class-gravityview-lightbox-entry.php @@ -51,7 +51,7 @@ public function __construct() { * * @used-by `gravityview/template/before` filter. * - * @since 2.29.0 + * @since 2.29.0 * * @param Template_Context $context * @@ -151,7 +151,7 @@ public function process_rest_request( $request ) { * * @used-by `gravityview/view/links/directory` filter. * - * @since 2.29.0 + * @since 2.29.0 * * @param string $link The directory link. * @@ -323,6 +323,8 @@ private function process_edit_entry( $nonce, $view, $entry, $form ) { return; } + add_filter( 'gk/gravityview/edit-entry/renderer/enqueue-entry-lock-assets', '__return_true' ); + add_filter( 'gravityview/edit_entry/verify_nonce', '__return_true' ); add_filter( 'gravityview/edit_entry/cancel_onclick', function () use ( $view ) { @@ -333,6 +335,25 @@ private function process_edit_entry( $nonce, $view, $entry, $form ) { } } ); + // Updates the GF entry lock UI markup to properly handle requests for accepting the release or taking over the edit lock. + add_filter( 'gk/gravityview/edit-entry/renderer/entry-lock-dialog-markup', function ( $markup ) { + // To accept the release, we do an Ajax GET request by passing "release-edit-lock=1" and then close the lightbox. + $markup = str_replace( + 'id="gform-release-lock-button"', + 'id="gform-release-lock-button" onclick="event.preventDefault(); jQuery.ajax({ url: window.location.href, data: { \'release-edit-lock\': 1 }, method: \'GET\', dataType: \'html\' }).done(function() { window.parent.postMessage({ closeFancybox: true }); });"', + $markup + ); + + // To take over once the release has been accepted, we do an Ajax GET request by passing "get-edit-lock=1" and then close the GF lock dialog window. + $markup = str_replace( + 'id="gform-take-over-button"', + 'id="gform-take-over-button" onclick="event.preventDefault(); jQuery.ajax({ url: window.location.href, data: { \'get-edit-lock\': 1 }, method: \'GET\', dataType: \'html\' }).done(function() { jQuery( \'#gform-lock-dialog\' ).hide(); });"', + $markup + ); + + return $markup; + } ); + // Prevent redirection inside the lightbox by sending event to the parent window and hiding the success message. if ( ! in_array( $view->settings->get( 'edit_redirect' ), [ '1', '2' ] ) ) { return; @@ -488,14 +509,15 @@ private function render_entry( $type, $view, $entry, $form ) { * * @action `gk/gravityview/lightbox/entry/before-output` * - * @since 2.31.0 + * @since 2.31.0 * - * @param array $args { - * @type View $view The View object being rendered. - * @type GF_Entry $entry The Gravity Forms entry data. - * @type array $form The Gravity Forms form array. - * @type Entry_Render $entry_renderer The renderer object responsible for rendering the entry. - * } + * @param array $args { + * + * @type View $view The View object being rendered. + * @type GF_Entry $entry The Gravity Forms entry data. + * @type array $form The Gravity Forms form array. + * @type Entry_Render $entry_renderer The renderer object responsible for rendering the entry. + * } */ do_action_ref_array( 'gk/gravityview/lightbox/entry/before-output', [ &$view, &$entry, &$form, &$entry_renderer ] ); @@ -519,19 +541,19 @@ private function render_entry( $type, $view, $entry, $form ) { tag. - * - * @action `gk/gravityview/lightbox/entry/output/head-before` - * - * @since 2.31.0 - * - * @param string $type The type of the entry view (single or edit). - * @param View $view The View object being rendered. - * @param GF_Entry $entry The Gravity Forms entry data. - * @param array $form The Gravity Forms form array. - */ - do_action( 'gk/gravityview/lightbox/entry/output/head-before', $type, $view, $entry, $form ); + /** + * Fires after tag. + * + * @action `gk/gravityview/lightbox/entry/output/head-before` + * + * @since 2.31.0 + * + * @param string $type The type of the entry view (single or edit). + * @param View $view The View object being rendered. + * @param GF_Entry $entry The Gravity Forms entry data. + * @param array $form The Gravity Forms form array. + */ + do_action( 'gk/gravityview/lightbox/entry/output/head-before', $type, $view, $entry, $form ); ?> <?php echo $title; ?> @@ -547,73 +569,73 @@ private function render_entry( $type, $view, $entry, $form ) { tag. - * - * @action `gk/gravityview/lightbox/entry/output/head-after` - * - * @since 2.31.0 - * - * @param string $type The type of the entry view (single or edit). - * @param View $view The View object being rendered. - * @param GF_Entry $entry The Gravity Forms entry data. - * @param array $form The Gravity Forms form array. - */ - do_action( 'gk/gravityview/lightbox/entry/output/head-after', $type, $view, $entry, $form ); + /** + * Fires before tag. + * + * @action `gk/gravityview/lightbox/entry/output/head-after` + * + * @since 2.31.0 + * + * @param string $type The type of the entry view (single or edit). + * @param View $view The View object being rendered. + * @param GF_Entry $entry The Gravity Forms entry data. + * @param array $form The Gravity Forms form array. + */ + do_action( 'gk/gravityview/lightbox/entry/output/head-after', $type, $view, $entry, $form ); ?> tag before the content is rendered. - * - * @action `gk/gravityview/lightbox/entry/output/content-before` - * - * @since 2.31.0 - * - * @param string $type The type of the entry view (single or edit). - * @param View $view The View object being rendered. - * @param GF_Entry $entry The Gravity Forms entry data. - * @param array $form The Gravity Forms form array. - */ - do_action( 'gk/gravityview/lightbox/entry/output/content-before', $type, $view, $entry, $form ); + /** + * Fires after tag before the content is rendered. + * + * @action `gk/gravityview/lightbox/entry/output/content-before` + * + * @since 2.31.0 + * + * @param string $type The type of the entry view (single or edit). + * @param View $view The View object being rendered. + * @param GF_Entry $entry The Gravity Forms entry data. + * @param array $form The Gravity Forms form array. + */ + do_action( 'gk/gravityview/lightbox/entry/output/content-before', $type, $view, $entry, $form ); ?> tag after the content is rendered and before the footer. - * - * @action `gk/gravityview/lightbox/entry/output/content-after` - * - * @since 2.31.0 - * - * @param string $type The type of the entry view (single or edit). - * @param View $view The View object being rendered. - * @param GF_Entry $entry The Gravity Forms entry data. - * @param array $form The Gravity Forms form array. - */ - do_action( 'gk/gravityview/lightbox/entry/output/content-after', $type, $view, $entry, $form ); + /** + * Fires inside the tag after the content is rendered and before the footer. + * + * @action `gk/gravityview/lightbox/entry/output/content-after` + * + * @since 2.31.0 + * + * @param string $type The type of the entry view (single or edit). + * @param View $view The View object being rendered. + * @param GF_Entry $entry The Gravity Forms entry data. + * @param array $form The Gravity Forms form array. + */ + do_action( 'gk/gravityview/lightbox/entry/output/content-after', $type, $view, $entry, $form ); ?> tag. - * - * @action `gk/gravityview/lightbox/entry/output/footer-after` - * - * @since 2.31.0 - * - * @param string $type The type of the entry view (single or edit). - * @param View $view The View object being rendered. - * @param GF_Entry $entry The Gravity Forms entry data. - * @param array $form The Gravity Forms form array. - */ - do_action( 'gk/gravityview/lightbox/entry/output/footer-after', $type, $view, $entry, $form ); + /** + * Fires after the footer and before the closing tag. + * + * @action `gk/gravityview/lightbox/entry/output/footer-after` + * + * @since 2.31.0 + * + * @param string $type The type of the entry view (single or edit). + * @param View $view The View object being rendered. + * @param GF_Entry $entry The Gravity Forms entry data. + * @param array $form The Gravity Forms form array. + */ + do_action( 'gk/gravityview/lightbox/entry/output/footer-after', $type, $view, $entry, $form ); ?> @@ -631,7 +653,7 @@ private function render_entry( $type, $view, $entry, $form ) { * * @used-by `gk/foundation/inline-scripts` filter. * - * @since 2.29.0 + * @since 2.29.0 * * @param array $scripts The registered scripts. * @@ -725,7 +747,7 @@ function handleChange( changedInput, otherInput ) { * @since 2.31.0 * * @param string $type The type of the entry view (single or edit). - * @param View $view The View object being rendered. + * @param View $view The View object being rendered. * * @return void */ diff --git a/readme.txt b/readme.txt index e92a4ca8e6..bc0c64c9c1 100644 --- a/readme.txt +++ b/readme.txt @@ -26,6 +26,11 @@ Beautifully display your Gravity Forms entries. Learn more on [gravitykit.com](h #### 🐛 Fixed * The Search Bar would not always be visible in Views using the Layout Builder. * Users belonging to the main network site in a multisite environment couldn’t delete their own entries on subsites. +* Entry locking not working. + +#### 💻 Developer Updates +* Added `gk/gravityview/edit-entry/renderer/enqueue-entry-lock-assets` filter to override whether to load the entry lock UI assets. +* Added `gk/gravityview/edit-entry/renderer/entry-lock-dialog-markup` filter to modify the entry locking UI dialog window markup. = 2.34 on January 9, 2025 =