Support

Account

Home Forums Backend Issues (wp-admin) Saving and restoring flexible content layouts in JavaScript

Unread

Saving and restoring flexible content layouts in JavaScript

  • I would like to get the user-data of a flexible content layout block as JSON to create the exact same layout block on another page or even another website (of course with the same theme and flexible content container).
    The goal is to create a library of content block templates.

    Generating JSON of the current user-data of a content block is not that hard and works fine. Albeit I first tried to get a recursive representation of the data (e.g. when repeaters are used in the content block) and failed as every nested container type (repeater, groups, flexible contents, clone fields) needs to be addressed separately.
    Because of this and the problem that creating the new field with populating nested containers is really hard.

    Currently I am facing following issues:
    1) The values for e.g. image fields and date-time-picker fields are not set correctly. They seem to be empty. But when the post is saved, and the page reloads all values are filled and correct.
    2) Repeater rows will be in wrong order. Strictly speaking the last item will be the first, the others are fine.
    3) If the visibility of a field depends on the value of another field (conditional_logic) the field is only filled when the field it depends on is set before. I guess this could be circumvented by setting all field values once again, but that would be a real hack.
    4) Tabs within the new content block are not working as expected: All fields are visible until the tabs are clicked once, the only the fields belonging to the currently selected tab are visible. This could be prevented be triggering a click event on every tab.

    Here is our demo code.
    The code adds a Save button between the “duplicate layout” button and the “delete layout” button. When clicked the user-data is aggregated and written to console and then the same layout is added to the flexible content and filled with the data of the original layout.
    Yes this is actually the duplicate layout function, but this is just for testing.

    jQuery(function() {
    
    	let $buttonSave = jQuery('<a class="acf-icon -save-as-template small light acf-js-tooltip" href="#" data-name="save-as-template" title="Save layout">S</a>');
    	jQuery('.acf-fc-layout-controls a.acf-icon[data-name="duplicate-layout"]').after($buttonSave);
    	
    	jQuery(document).on('click', '.acf-fc-layout-controls a.acf-icon.-save-as-template', function(e) {
    		let $contentBlock = jQuery(this).closest('.layout');
    		let $flexible_content = $contentBlock.closest('.acf-field-flexible-content');
    		let flexible_content = acf.getField($flexible_content);
    
    		let data = {
    			layout: $contentBlock.data('layout'),
    			fields: getContentBlockData($contentBlock),
    		};
    		console.log(data);
    		console.log(JSON.stringify(data));
    
    		let setAcfValue = function(field) {
    			let fieldKey = field.get('key');
    			for (let i = 0; i < data.fields.length; i++) {
    				let entry = data.fields[i];
    				if (entry.key && entry.key === fieldKey && entry.value != null) {
    					if (entry.type === 'repeater') {
    						for (let j = 0; j < entry.value; j++) {
    							if (field.getValue() >= entry.value) {
    								break;
    							}
    							field.add();
    						}
    					} else {
    						field.val(entry.value);
    					}
    					data.fields[i].key = null;
    					break;
    				}
    			}
    		}.bind(data);
    
    		acf.addAction('new_field', setAcfValue);
    		flexible_content.add({
    			layout: data.layout,
    			before: $contentBlock,
    		});
    		acf.removeAction('new_field', setAcfValue);
    	});
    
    	let getContentBlockData = function(parent) {
    		let data = [];
    		$fields = acf.findFields({
    			parent: parent,
    		});
    		if ($fields.size() <= 0) {
    			return data;
    		}
    		for (let i = 0; i < $fields.size(); i++) {
    			let $element = jQuery($fields[i]);
    			let field = acf.getField($element);
    			let type = field.get('type');
    			let key = field.get('key');
    			let name = field.get('name');
    			let value = null;
    			if (type === 'tab' || type === 'message') {
    				continue;
    			}
    			if (type === 'select_freetext') {
    				i++;
    				$element = jQuery($fields[i]);
    				field = acf.getField($element);
    			}
    			value = field.val();
    			data.push({
    				type: type,
    				key: key,
    				name: name,
    				value: value,
    			});
    		}
    		return data;
    	}
    
    });

    Is there a better, maybe totally different, way to achieve this?
    Has anybody ever done something similar?
    Help is very appreciated.

Viewing 1 post (of 1 total)

You must be logged in to reply to this topic.

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 Cookie Policy. If you continue to use this site, you consent to our use of cookies.