Simplistic way to Disable Dates on Ninja Forms datepicker using ACF Repeater from the Options Page
Note: Ninja Forms version 3.4.31 and above no longer uses PikaDate it was updated to Flatpickr
While working on a recent project I needed to disable specific dates on the date picker within Ninja Forms.
I kept running into Uncaught SyntaxError: Invalid or unexpected token error
when using the disableDayFn
function while following the date picker documentation. After testing on my client's site for a few hours I had thought the documentation was outdated. It turns out I was wrong1.
Ninja Forms Setup
Finally I decided that maybe I should test on my local environment instead of a live website, so I spun up my local WordPress install, installed ninja forms, and imported a test form.
Then carefully coping over each piece of code from the documentation over one by one but this time instead I would not combine the two JS files but keep them separate. Not sure why but this seemed to have worked and resolved my SyntaxError
for the disableDayFn
.
So keep the scripts.js
and customDatePicker.js
separate.
After cleaning all the comments and removing the labels and enabled days functions I was left with this:
var customDatePickerStuff = Marionette.Object.extend( {
initialize: function() {
this.listenTo( Backbone.Radio.channel( 'pikaday' ), 'init', this.modifyDatepicker );
},
modifyDatepicker: function( dateObject, fieldModel ) {
dateObject.pikaday._o.disableDayFn = function( date ) {
var disabledDays = ["2017-04-28", "2017-04-29", "2017-04-30"];
if ( _.indexOf( disabledDays, moment( date ).format( "YYYY-MM-DD" ) ) !== –1 ) {
return true;
}
}
}
});
jQuery( document ).ready( function() {
new customDatePickerStuff();
} );
1Update October 29th 2020:
Emailed Free Support and heres what they found
I figured out the syntax issue. It was missing a parenthesis around the 'if' statement. See the following code,
dateObject.pikaday._o.disableDayFn = function( date ) { var disabledDays = ["2020-10-29"]; if ( (_.indexOf( disabledDays, moment( date ).format( "YYYY-MM-DD" ) ) ) !== -1 ) { return true; } }
Once you add the parenthesis it disables all days except for the 29th .... or whatever days you want disabled. Please let us know if you need anything else.
Step 1. Completed. ff..finally.
Setup ACF Options Page and repeater fields.
//ACF Options Page
if( function_exists('acf_add_options_page') ) {
acf_add_options_page();
}
After updated the disabledDays
array to more current/futures dates to test, the dates are disabled.
A good sign of progress.
During the ACF repeater field setup, you'll need to match the date format to the disabledDays
array above. So in the date subfield select the return format to custom and enter
Y-m-d
One step forward another step back
While going down another Google rabbit hole and open tabs hell, I decided to just search the ACF support forums (because I'm definitely not the only one who had had this question of getting ACF repeater values into a JavaScript file) and BOOM found like 2 articles [1][2].
Question: How do I pass ACF field values into a JavaScript file?
Answer: wp_localize_script
/*
* Plugin Name: Ninja Forms – Datepicker Customizations
*/
add_filter( 'ninja_forms_enqueue_scripts', 'nf_datepicker_options' );
function nf_datepicker_options() {
wp_enqueue_script( 'nf_datepicker_options', plugin_dir_url( __FILE__ ) . 'script.js', array( 'jquery' ), false, true );
wp_register_script( 'nf_datepicker_options-custom', plugin_dir_url( __FILE__ ) . 'customDatePicker.js' );
wp_localize_script( 'nf_datepicker_options-custom', 'acf_dates', array(
'block_dates' => get_field("block_dates", 'option')
) );
wp_enqueue_script( 'nf_datepicker_options-custom' );
}
Sounds nice and easy right?
It is actually is pretty easy. Just pass in the field names into wp_localize_script
wp_localize_script( 'nf_datepicker_options-custom', 'acf_data', array(
'field_name' => get_field("field_name"),
'field_type' => get_field("field_type", 'option') // if youre using the options page
) );
Inside the JS file, call the data:
console.log ( acf_data.field_name );
console.log ( acf_data.field_type );
So close yet so far.
First, move the disabledDays
array out of the modifyDatepicker
function and after a lot of console.logging, hard refreshes, clearing the browser cache and 1 final 'quick' google search on "convert nested objects to an array, javascript" and landing on stack overflow one final time, thanks internet! You're really the one doing my job for me!
const array = acf_dates.block_dates;
var disabledDays = [].concat(...array.map(Object.values));
var customDatePickerStuff = Marionette.Object.extend( {
initialize: function() {
this.listenTo( Backbone.Radio.channel( 'pikaday' ), 'init', this.modifyDatepicker );
},
modifyDatepicker: function( dateObject, fieldModel ) {
dateObject.pikaday._o.disableDayFn = function( date ) {
if ( _.indexOf( disabledDays, moment( date ).format( "YYYY-MM-DD" ) ) !== -1 ) {
return true;
}
}
}
});
jQuery( document ).ready( function() {
new customDatePickerStuff();
} );
Hope this will help someone spend less time in front of the computer screen and more time outside maybe... leave a comment in the comments below.
Update November 24th 2020:
Recently updated Ninja Forms on the client's site and all the hard work above came crashing down below is what Ninja Form Free Support said in an email
In the Ninja Forms version 3.4.31 and above the library for the Date field was updated to use the Flatpickr library.
The developer documentation has not yet been updated for the Flatpickr at this time.
While custom code is outside the scope of support that we're able to help with, you can find documentation for Flatpickr here:
https://flatpickr.js.org/
Update February 7th 2021:
If you're looking to disable the past dates on the date picker; check out the updated code here