| 1 |
/* global document, jQuery, ef_week_first_day, wp */ |
| 2 |
|
| 3 |
jQuery( document ).ready( function( $ ) { |
| 4 |
/** |
| 5 |
* Check if we're in the Gutenberg editor. |
| 6 |
* |
| 7 |
* @return {boolean} True if Gutenberg is available. |
| 8 |
*/ |
| 9 |
function isGutenberg() { |
| 10 |
return typeof wp !== 'undefined' && wp.data && wp.data.dispatch && wp.data.select; |
| 11 |
} |
| 12 |
|
| 13 |
/** |
| 14 |
* Check if Gutenberg post entity is ready for meta updates. |
| 15 |
* |
| 16 |
* @return {boolean} True if ready. |
| 17 |
*/ |
| 18 |
function isGutenbergReady() { |
| 19 |
if ( ! isGutenberg() ) { |
| 20 |
return false; |
| 21 |
} |
| 22 |
try { |
| 23 |
const postType = wp.data.select( 'core/editor' ).getCurrentPostType(); |
| 24 |
return !! postType; |
| 25 |
} catch ( e ) { |
| 26 |
return false; |
| 27 |
} |
| 28 |
} |
| 29 |
|
| 30 |
/** |
| 31 |
* Update Gutenberg's data store with the meta value. |
| 32 |
* This ensures that when the user saves, the REST API includes our updated meta. |
| 33 |
* |
| 34 |
* @param {string} metaKey The post meta key. |
| 35 |
* @param {*} metaValue The value to save (will be converted to string). |
| 36 |
*/ |
| 37 |
function updateGutenbergMeta( metaKey, metaValue ) { |
| 38 |
if ( ! isGutenbergReady() ) { |
| 39 |
return; |
| 40 |
} |
| 41 |
|
| 42 |
const meta = {}; |
| 43 |
// Convert to string since REST API expects string type. |
| 44 |
meta[ metaKey ] = String( metaValue ); |
| 45 |
|
| 46 |
wp.data.dispatch( 'core/editor' ).editPost( { meta: meta } ); |
| 47 |
} |
| 48 |
|
| 49 |
/** |
| 50 |
* Update the hidden field with combined date and time values. |
| 51 |
* The hidden field stores the value in 'Y-m-d H:i' format for PHP processing. |
| 52 |
* Also updates Gutenberg's data store with the Unix timestamp. |
| 53 |
* |
| 54 |
* @param {jQuery} $dateInput The date input element. |
| 55 |
* @param {boolean} updateGutenberg Whether to update Gutenberg store (default true). |
| 56 |
*/ |
| 57 |
function updateHiddenField( $dateInput, updateGutenberg ) { |
| 58 |
if ( typeof updateGutenberg === 'undefined' ) { |
| 59 |
updateGutenberg = true; |
| 60 |
} |
| 61 |
|
| 62 |
// Derive related element IDs from the date input ID. |
| 63 |
// Date input: {key}_date, Time input: {key}_time, Hidden: {key}_hidden |
| 64 |
const baseId = $dateInput.attr( 'id' ).replace( /_date$/, '' ); |
| 65 |
const $timeInput = $( '#' + baseId + '_time' ); |
| 66 |
const $hiddenInput = $( '#' + baseId + '_hidden' ); |
| 67 |
|
| 68 |
if ( ! $hiddenInput.length ) { |
| 69 |
return; |
| 70 |
} |
| 71 |
|
| 72 |
// Get the date value from the datepicker's altField mechanism or parse it. |
| 73 |
let dateValue = $dateInput.datepicker( 'getDate' ); |
| 74 |
if ( ! dateValue ) { |
| 75 |
$hiddenInput.val( '' ); |
| 76 |
if ( updateGutenberg ) { |
| 77 |
updateGutenbergMeta( baseId, '' ); |
| 78 |
} |
| 79 |
return; |
| 80 |
} |
| 81 |
|
| 82 |
// Format date as Y-m-d. |
| 83 |
const year = dateValue.getFullYear(); |
| 84 |
const month = String( dateValue.getMonth() + 1 ).padStart( 2, '0' ); |
| 85 |
const day = String( dateValue.getDate() ).padStart( 2, '0' ); |
| 86 |
const formattedDate = year + '-' + month + '-' + day; |
| 87 |
|
| 88 |
// Get time value (HH:mm format from HTML5 time input). |
| 89 |
let timeValue = $timeInput.val() || '00:00'; |
| 90 |
|
| 91 |
// Combine into 'Y-m-d H:i' format for the hidden field. |
| 92 |
$hiddenInput.val( formattedDate + ' ' + timeValue ); |
| 93 |
|
| 94 |
if ( updateGutenberg ) { |
| 95 |
// Calculate Unix timestamp for Gutenberg. |
| 96 |
const timeParts = timeValue.split( ':' ); |
| 97 |
const hours = parseInt( timeParts[ 0 ], 10 ) || 0; |
| 98 |
const minutes = parseInt( timeParts[ 1 ], 10 ) || 0; |
| 99 |
|
| 100 |
// Create a new Date object with the combined date and time. |
| 101 |
const combinedDate = new Date( year, dateValue.getMonth(), dateValue.getDate(), hours, minutes, 0 ); |
| 102 |
const timestamp = Math.floor( combinedDate.getTime() / 1000 ); |
| 103 |
|
| 104 |
// Update Gutenberg's data store with the Unix timestamp (as string). |
| 105 |
updateGutenbergMeta( baseId, timestamp ); |
| 106 |
} |
| 107 |
} |
| 108 |
|
| 109 |
// Initialize jQuery UI datepicker on .date-pick elements. |
| 110 |
const $datePicks = $( '.date-pick' ); |
| 111 |
|
| 112 |
$datePicks.each( function() { |
| 113 |
const $datePicker = $( this ); |
| 114 |
|
| 115 |
$datePicker.datepicker( { |
| 116 |
dateFormat: 'M dd yy', |
| 117 |
firstDay: ef_week_first_day, |
| 118 |
showButtonPanel: true, |
| 119 |
onSelect: function() { |
| 120 |
updateHiddenField( $datePicker, true ); |
| 121 |
}, |
| 122 |
} ); |
| 123 |
|
| 124 |
// Update hidden field when date input changes (e.g., manual input). |
| 125 |
$datePicker.on( 'change', function() { |
| 126 |
updateHiddenField( $datePicker, true ); |
| 127 |
} ); |
| 128 |
} ); |
| 129 |
|
| 130 |
// Update hidden field when time input changes. |
| 131 |
$( '.time-pick' ).on( 'change', function() { |
| 132 |
const $timeInput = $( this ); |
| 133 |
// Derive the date input from the time input ID. |
| 134 |
const baseId = $timeInput.attr( 'id' ).replace( /_time$/, '' ); |
| 135 |
const $dateInput = $( '#' + baseId + '_date' ); |
| 136 |
|
| 137 |
if ( $dateInput.length ) { |
| 138 |
updateHiddenField( $dateInput, true ); |
| 139 |
} |
| 140 |
} ); |
| 141 |
|
| 142 |
// Initialize hidden fields with current values on page load. |
| 143 |
// Do NOT update Gutenberg here - just set up the hidden field for form submission. |
| 144 |
$datePicks.each( function() { |
| 145 |
const $datePicker = $( this ); |
| 146 |
if ( $datePicker.val() ) { |
| 147 |
updateHiddenField( $datePicker, false ); |
| 148 |
} |
| 149 |
} ); |
| 150 |
|
| 151 |
/** |
| 152 |
* Sync all Editorial Metadata fields to Gutenberg. |
| 153 |
* This handles text, paragraph, checkbox, user, number, and location fields. |
| 154 |
*/ |
| 155 |
function setupMetaboxSync() { |
| 156 |
const $metaBox = $( '#ef_editorial_meta_meta_box' ); |
| 157 |
|
| 158 |
if ( ! $metaBox.length || ! isGutenberg() ) { |
| 159 |
return; |
| 160 |
} |
| 161 |
|
| 162 |
// Text, paragraph, number, and location inputs. |
| 163 |
$metaBox.find( 'input[type="text"]:not(.date-pick), textarea, select' ).on( 'change input', function() { |
| 164 |
const $input = $( this ); |
| 165 |
const name = $input.attr( 'name' ); |
| 166 |
|
| 167 |
// Skip hidden fields and fields without names. |
| 168 |
if ( ! name || name.endsWith( '_hidden' ) ) { |
| 169 |
return; |
| 170 |
} |
| 171 |
|
| 172 |
updateGutenbergMeta( name, $input.val() ); |
| 173 |
} ); |
| 174 |
|
| 175 |
// Checkbox inputs. |
| 176 |
$metaBox.find( 'input[type="checkbox"]' ).on( 'change', function() { |
| 177 |
const $input = $( this ); |
| 178 |
const name = $input.attr( 'name' ); |
| 179 |
|
| 180 |
if ( ! name ) { |
| 181 |
return; |
| 182 |
} |
| 183 |
|
| 184 |
// Store as '1' or '' to match PHP behavior. |
| 185 |
const value = $input.is( ':checked' ) ? '1' : ''; |
| 186 |
updateGutenbergMeta( name, value ); |
| 187 |
} ); |
| 188 |
} |
| 189 |
|
| 190 |
// Set up metabox sync for Gutenberg. |
| 191 |
setupMetaboxSync(); |
| 192 |
} ); |
| 193 |
|