Changeset 3446504
- Timestamp:
- 01/25/2026 11:30:49 AM (6 weeks ago)
- Location:
- griffinforms-form-builder/trunk
- Files:
-
- 8 edited
-
admin/css/griffinforms-settings.css (modified) (1 diff)
-
admin/html/pages/settings/format.php (modified) (3 diffs)
-
admin/js/griffinforms-settings.js (modified) (1 diff)
-
config.php (modified) (1 diff)
-
frontend/html/forms/form.php (modified) (1 diff)
-
griffinforms.php (modified) (1 diff)
-
readme.txt (modified) (2 diffs)
-
settings.php (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
griffinforms-form-builder/trunk/admin/css/griffinforms-settings.css
r3357957 r3446504 114 114 } 115 115 116 .griffinforms-settings-option-history .gf-settings-history-toggle { 117 margin-left: 6px; 118 font-size: 12px; 119 } 120 121 .griffinforms-settings-option-history .gf-settings-history-list { 122 margin-top: 6px; 123 } 124 125 .griffinforms-settings-option-history .gf-settings-history-items { 126 margin: 0; 127 padding-left: 18px; 128 font-size: 12px; 129 } 130 131 .griffinforms-settings-option-history .gf-settings-history-item { 132 margin: 2px 0; 133 } 134 116 135 .form-table td fieldset label, .form-table td fieldset li, .form-table td fieldset p { 117 136 font-size: 13px; -
griffinforms-form-builder/trunk/admin/html/pages/settings/format.php
r3425584 r3446504 185 185 } 186 186 187 $last_value = $this->formatOptionHistoryValue($this->option['last_value']); 188 $last_editor_id = $this->option['last_editor']; 189 $last_edited_on = $this->option['last_edited_on']; 187 $history = $this->option['history'] ?? []; 188 $history_count = is_array($history) ? count($history) : 0; 190 189 $max_len = 160; 191 $last_value_full = (string) $last_value; 192 $last_value_trimmed = $last_value_full; 193 if (strlen($last_value_full) > $max_len) { 194 $last_value_trimmed = substr($last_value_full, 0, $max_len) . '...'; 195 } 190 191 $latest_entry = $history_count > 0 ? $history[0] : null; 192 $latest_value = $latest_entry['value'] ?? $this->option['last_value']; 193 $last_editor_id = $latest_entry['editor'] ?? $this->option['last_editor']; 194 $last_edited_on = $latest_entry['edited_on'] ?? $this->option['last_edited_on']; 195 196 [$last_value_trimmed, $last_value_full, $last_value_truncated] = $this->getHistoryValueDisplay($latest_value, $max_len); 196 197 197 198 // Fetch editor details based on user ID … … 210 211 echo '<span>' . esc_html(__('on', 'griffinforms-form-builder')) . ' ' . esc_html($formatted_time) . '</span>. '; 211 212 echo '<span>' . esc_html(__('Its previous value was', 'griffinforms-form-builder')) . ' <code>' . esc_html($last_value_trimmed) . '</code>'; 212 if ( strlen($last_value_full) > $max_len) {213 if ($last_value_truncated) { 213 214 echo ' <a href="#" class="gf-settings-history-view-full" data-gf-full-value="' . esc_attr($last_value_full) . '">' . esc_html__('View full', 'griffinforms-form-builder') . '</a>'; 214 215 } 215 216 echo '</span>'; 217 218 if ($history_count > 1) { 219 $toggle_text = sprintf(__('View history (%d)', 'griffinforms-form-builder'), $history_count - 1); 220 echo ' <a href="#" class="gf-settings-history-toggle" data-gf-collapsed-text="' . esc_attr($toggle_text) . '" data-gf-expanded-text="' . esc_attr(__('Hide history', 'griffinforms-form-builder')) . '" aria-expanded="false">' . esc_html($toggle_text) . '</a>'; 221 222 echo '<div class="gf-settings-history-list" style="display: none;">'; 223 echo '<ul class="gf-settings-history-items">'; 224 for ($i = 1; $i < $history_count; $i++) { 225 $entry = $history[$i]; 226 $entry_editor_id = $entry['editor'] ?? null; 227 $entry_editor = $entry_editor_id ? get_user_by('id', $entry_editor_id) : null; 228 $entry_editor_name = $entry_editor ? $entry_editor->display_name : __('Unknown User', 'griffinforms-form-builder'); 229 $entry_time = $entry['edited_on'] ?? ''; 230 $entry_time_formatted = $entry_time ? wp_date(get_option('date_format') . ' ' . get_option('time_format'), strtotime($entry_time)) : ''; 231 232 $previous_value = $entry['value'] ?? ''; 233 $new_value = $history[$i - 1]['value'] ?? ''; 234 235 [$prev_trimmed, $prev_full, $prev_truncated] = $this->getHistoryValueDisplay($previous_value, $max_len); 236 [$new_trimmed, $new_full, $new_truncated] = $this->getHistoryValueDisplay($new_value, $max_len); 237 238 echo '<li class="gf-settings-history-item">'; 239 echo esc_html($entry_editor_name) . ' ' . esc_html(__('changed value from', 'griffinforms-form-builder')) . ' <code>' . esc_html($prev_trimmed) . '</code>'; 240 if ($prev_truncated) { 241 echo ' <a href="#" class="gf-settings-history-view-full" data-gf-full-value="' . esc_attr($prev_full) . '">' . esc_html__('View full', 'griffinforms-form-builder') . '</a>'; 242 } 243 echo ' ' . esc_html(__('to', 'griffinforms-form-builder')) . ' <code>' . esc_html($new_trimmed) . '</code>'; 244 if ($new_truncated) { 245 echo ' <a href="#" class="gf-settings-history-view-full" data-gf-full-value="' . esc_attr($new_full) . '">' . esc_html__('View full', 'griffinforms-form-builder') . '</a>'; 246 } 247 if (!empty($entry_time_formatted)) { 248 echo ' ' . esc_html(__('on', 'griffinforms-form-builder')) . ' ' . esc_html($entry_time_formatted) . '.'; 249 } 250 echo '</li>'; 251 } 252 echo '</ul>'; 253 echo '</div>'; 254 } 216 255 echo '</div>'; 217 256 } … … 236 275 return (string) $value; 237 276 } 277 278 protected function getHistoryValueDisplay($value, $max_len): array 279 { 280 $formatted = $this->formatOptionHistoryValue($value); 281 $full = (string) $formatted; 282 $trimmed = $full; 283 $truncated = false; 284 if (strlen($full) > $max_len) { 285 $trimmed = substr($full, 0, $max_len) . '...'; 286 $truncated = true; 287 } 288 return [$trimmed, $full, $truncated]; 289 } 238 290 } -
griffinforms-form-builder/trunk/admin/js/griffinforms-settings.js
r3425584 r3446504 11 11 } 12 12 }); 13 14 $(document).on('click', '.gf-settings-history-toggle', function(e) { 15 e.preventDefault(); 16 var toggle = $(this); 17 var list = toggle.closest('.griffinforms-settings-option-history').find('.gf-settings-history-list'); 18 if (!list.length) { 19 return; 20 } 21 list.slideToggle(150, function() { 22 var isOpen = list.is(':visible'); 23 toggle.attr('aria-expanded', isOpen ? 'true' : 'false'); 24 var text = isOpen ? toggle.attr('data-gf-expanded-text') : toggle.attr('data-gf-collapsed-text'); 25 if (text) { 26 toggle.text(text); 27 } 28 }); 29 }); 13 30 }); -
griffinforms-form-builder/trunk/config.php
r3439965 r3446504 5 5 class Config 6 6 { 7 public const VERSION = '2.1. 4.0';7 public const VERSION = '2.1.5.0'; 8 8 public const DB_VER = '1.0'; 9 9 public const PHP_REQUIRED = '8.2'; -
griffinforms-form-builder/trunk/frontend/html/forms/form.php
r3421663 r3446504 106 106 $html = '<div class="griffinforms-form' . absint($this->id) . '-container row' . $theme_class . $theme_slug_class . (!$is_theme_set && !empty($this->bs_form_main_container_classes) ? ' ' . esc_attr($this->bs_form_main_container_classes) : '') . '" data-gf-form-id="' . absint($this->id) . '"' . $theme_identifier_attr . '>'; 107 107 $html .= $theme_assets_markup . $theme_css; 108 $html .= '<noscript><div class="alert alert-warning small" role="alert">'; 109 $html .= '<strong class="fw-medium">' . esc_html__('JavaScript required', 'griffinforms-form-builder') . '</strong>. '; 110 $html .= esc_html__('This form needs JavaScript to function correctly. Please enable JavaScript in your browser and reload the page.', 'griffinforms-form-builder'); 111 $html .= '</div></noscript>'; 108 112 109 113 if ($this->resume_attempted && !empty($this->resume_payment_error)) { -
griffinforms-form-builder/trunk/griffinforms.php
r3439965 r3446504 4 4 * Plugin URI: https://griffinforms.com/ 5 5 * Description: A powerful and flexible form builder for WordPress. Create multi-page forms with drag-and-drop ease, custom validations, and full submission management. 6 * Version: 2.1. 4.06 * Version: 2.1.5.0 7 7 * Requires at least: 6.6 8 8 * Requires PHP: 8.2 -
griffinforms-form-builder/trunk/readme.txt
r3441920 r3446504 172 172 == Changelog == 173 173 174 = 2.1.5.0 – 2026-01-25 = 175 * Improvement: Settings history now retains the last 5 changes with an expandable history list. 176 * Improvement: Frontend forms now show a “JavaScript required” notice when scripts are disabled. 177 174 178 = 2.1.4.0 – 2026-01-15 = 175 179 * Feature: New Gutenberg block for embedding GriffinForms with a lightweight editor preview. … … 466 470 == Upgrade Notice == 467 471 472 = 2.1.5.0 = 473 Adds a settings history trail with expandable entries and shows a JavaScript-required notice when scripts are disabled on the frontend. Recommended update. 474 468 475 = 2.1.4.0 = 469 476 Adds a native Gutenberg block with a lightweight, theme-aware editor preview and quick links to edit forms. Recommended update for block editor users. -
griffinforms-form-builder/trunk/settings.php
r3421663 r3446504 163 163 $current_value = $this->maybeDecode($this->getOption($option_name)); 164 164 if ($current_value != $option_value) { 165 $now = current_time('mysql', 1); 166 $current_editor = get_current_user_id(); 167 $last_option_value = null; 168 $last_editor = null; 169 $last_edited_on = null; 170 171 $history_row = $wpdb->get_row( 172 $wpdb->prepare( 173 "SELECT last_option_value, editor, edited_on FROM %i WHERE option_name = %s", 174 $this->table, 175 $option_name 176 ) 177 ); 178 if ($history_row) { 179 $last_option_value = $history_row->last_option_value ?? null; 180 $last_editor = $history_row->editor ?? null; 181 $last_edited_on = $history_row->edited_on ?? null; 182 } 183 165 184 // Determine whether the option should be encrypted 166 185 if (in_array($option_name, $this->encrypted_options)) { … … 175 194 $encrypted_value = openssl_encrypt(maybe_serialize($option_value), $method, $secure_key, 0, $iv); 176 195 177 // Encrypt the past (current) value using the same key and IV 178 $encrypted_last_value = openssl_encrypt(maybe_serialize($current_value), $method, $secure_key, 0, $iv); 196 // Build and encrypt history array using the same key and IV 197 $history_entries = $this->normalizeHistoryEntries( 198 $option_name, 199 $this->maybeDecode($this->decryptValue($option_name, $last_option_value)), 200 $last_editor, 201 $last_edited_on 202 ); 203 array_unshift($history_entries, [ 204 'value' => $current_value, 205 'editor' => $current_editor, 206 'edited_on' => $now, 207 ]); 208 $history_entries = array_slice($history_entries, 0, 5); 209 $encrypted_last_value = openssl_encrypt(maybe_serialize($history_entries), $method, $secure_key, 0, $iv); 179 210 } else { 180 211 // Handle missing keys error … … 186 217 // If the option is not in encrypted options, keep values as plain text 187 218 $encrypted_value = maybe_serialize($option_value); 188 $encrypted_last_value = maybe_serialize($current_value); 219 $history_entries = $this->normalizeHistoryEntries( 220 $option_name, 221 $this->maybeDecode($last_option_value), 222 $last_editor, 223 $last_edited_on 224 ); 225 array_unshift($history_entries, [ 226 'value' => $current_value, 227 'editor' => $current_editor, 228 'edited_on' => $now, 229 ]); 230 $history_entries = array_slice($history_entries, 0, 5); 231 $encrypted_last_value = maybe_serialize($history_entries); 189 232 } 190 233 … … 195 238 'last_option_value' => $encrypted_last_value, // Encrypted or plain text last value 196 239 'option_group' => sanitize_text_field($option_group), 197 'editor' => get_current_user_id(),198 'edited_on' => current_time('mysql', 1),240 'editor' => $current_editor, 241 'edited_on' => $now, 199 242 ), 200 243 array('option_name' => $option_name), // Where clause … … 330 373 $current_value = $this->maybeDecode($this->decryptValue($option_name, $result->option_value)); 331 374 $last_value = $this->maybeDecode($this->decryptValue($option_name, $result->last_option_value)); 375 $history = $this->normalizeHistoryEntries($option_name, $last_value, $result->editor, $result->edited_on); 376 $history = array_slice($history, 0, 5); 377 $first_entry = !empty($history) ? $history[0] : null; 332 378 333 379 return [ 334 380 'current_value' => $current_value, 335 'last_value' => $last_value, 336 'last_editor' => $result->editor, 337 'last_edited_on' => $result->edited_on, 381 'last_value' => $first_entry['value'] ?? $last_value, 382 'last_editor' => $first_entry['editor'] ?? $result->editor, 383 'last_edited_on' => $first_entry['edited_on'] ?? $result->edited_on, 384 'history' => $history, 338 385 ]; 339 386 } … … 345 392 'last_editor' => null, 346 393 'last_edited_on' => null, 394 'history' => [], 347 395 ]; 396 } 397 398 protected function normalizeHistoryEntries($option_name, $last_value, $last_editor, $last_edited_on): array 399 { 400 if ($last_value === 'none' || $last_value === null || $last_value === '') { 401 return []; 402 } 403 404 if (is_array($last_value)) { 405 $is_history = true; 406 foreach ($last_value as $entry) { 407 if (!is_array($entry) || !array_key_exists('value', $entry)) { 408 $is_history = false; 409 break; 410 } 411 } 412 if ($is_history) { 413 return $last_value; 414 } 415 } 416 417 return [[ 418 'value' => $last_value, 419 'editor' => $last_editor, 420 'edited_on' => $last_edited_on, 421 ]]; 348 422 } 349 423
Note: See TracChangeset
for help on using the changeset viewer.