Home › Forums › General Issues › Does ACF have a JS API? › Reply To: Does ACF have a JS API?
Thank you very much. I’m doing a similar thing at the moment:
– I use ACF hooks in order to run callback when an image field value is changed
– Then I read the image field data,
– Then I read the EXIF data from the image field,
– Then I update other fields values based on the EXIF data.
So, as long as it’s just a matter of updating existing fields, it’s not a big problem. But if I wanted to create some taxonomy fields on the fly, then it would be tricky, because there’s no way to re-render a field and/or a field group.
I will probably end up with writing my own ACF custom field that will handle taxonomies update. This will be a simpler and a cleaner solution because I want to have as little DOM traversing in my code as possible. I don’t want my code to break if ACF HTML structure will change.
Thank you for your help anyway! I hope that in future ACF will be more flexible in this area. I would love to see a real, non-DOM-dependant JS API. I would love to be able to render ACF fields anywhere, with a custom HTML templates, etc. But I know how much work it requires. At the moment this part of ACF code is very monolithic and DOM-oriented. I dream of a MVC-like architecture where models and collections are separated from the view layer (like Backbone Models/Collection/Views).
If it was implemented then ACF could become something more than just a powerful custom fields manager. If ACF has such an API and architecture then It would be even possible to build something like a page builder (like visual composer) on top of ACF!
Sorry for the offtopic 🙂
This is a piece of code I wrote:
import $ from 'jquery';
export default () => {
const $$ = {
template: $('#js-exif-data')
};
const nonce = $$.template.data('nonce');
// ACF fields identifiers
const imageInputName = 'acf[field_56d99d7de115e]';
const orientationInputName = 'acf[field_56d8b43f73de1]';
const allowedExifData = {
created_timestamp: 'Data',
iso: 'ISO',
focal_length: 'Ogniskowa',
shutter_speed: 'Migawka',
aperture: 'Przysłona',
keywords: 'Tagi'
};
const utils = {
/**
* @param {int} exifValue
* @returns {string} - <code>landscape</code> or <code>portrait</code>
*/
getOrientationByExifValue(exifValue) {
const orientations = [{
name: 'landscape',
values: [1, 2, 3, 4]
}, {
name: 'portrait',
values: [5, 6, 7, 8]
}];
const orientation = orientations
.filter(orientation => {
return orientation.values.indexOf(exifValue) !== -1;
});
return orientation.length === 0 ? 'unknown' : orientation[0].name;
},
/**
* @param {int} attachmentId
* @returns {Promise}
*/
loadExifData(attachmentId) {
return $.ajax({
type: 'post',
url: acf.o.ajaxurl,
data: {
nonce,
attachmentId,
action: 'get_image_meta',
}
});
},
/**
* @returns {Promise}
*/
getOrientationTerms() {
return $.ajax({
type: 'post',
url: acf.o.ajaxurl,
data: {
nonce,
action: 'get_orientation_terms',
}
});
},
/**
* @param {object} response
*/
renderExifData(response) {
$.each(response.data, (k, v) => {
if (!allowedExifData.hasOwnProperty(k)) {
return true;
}
// Convert array values to coma-separated string.
const value = (function () {
if (v.constructor === Array) {
return v.join(', ');
}
return v;
}());
const $p = $('<li />').html(<code><strong>${allowedExifData[k]}</strong>: ${value}</code>);
$$.template.append($p);
});
},
/**
* @param {object} response
*/
setOrientation(response) {
if (!response.data.hasOwnProperty('orientation')) {
return;
}
utils.getOrientationTerms().done(termsResponse => {
const wpTerms = termsResponse.data;
if (wpTerms.constructor !== Array) {
return;
}
const exifOrientation = parseInt(response.data.orientation, 10);
const orientationHumanReadable = utils.getOrientationByExifValue(exifOrientation);
const wpTerm = wpTerms.filter(term => {
return term.name === orientationHumanReadable;
});
if (wpTerm.length === 0) {
return;
}
const orientationTermId = parseInt(wpTerm[0].id, 10);
const $radios = $(<code>input[name="${orientationInputName}"]</code>);
const $radio = $radios.filter((index, el) => {
return parseInt($(el).val(), 10) === orientationTermId;
});
$radio
.prop('checked', true)
.trigger('click')
});
}
};
const handlers = {
imageOnLoad() {
const $input = $(<code>input[name="${imageInputName}"]</code>);
const attachmentId = $input.val();
if ($input.length === 0 || attachmentId === '') {
return;
}
$$.template.empty();
utils.loadExifData(attachmentId).done(utils.renderExifData);
},
/**
* @param {object} $input - an array of jQuery DOM objects
*/
imageInputOnChange($input) {
const attachmentId = $input.val();
if ($input.context.name !== imageInputName) {
return;
}
$$.template.empty();
if (attachmentId === '') {
return;
}
utils.loadExifData(attachmentId).done(response => {
utils.renderExifData(response);
utils.setOrientation(response);
})
}
};
acf.add_action('change', handlers.imageInputOnChange);
acf.add_action('load', handlers.imageOnLoad);
}
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.