function layotter() { // ACF abstraction layer is always required require_once __DIR__ . '/core/acf-abstraction.php'; // include files only if ACF is available if (Layotter_ACF::is_available()) { require_once __DIR__ . '/core/core.php'; require_once __DIR__ . '/core/ajax.php'; require_once __DIR__ . '/core/assets.php'; require_once __DIR__ . '/core/interface.php'; require_once __DIR__ . '/core/templates.php'; require_once __DIR__ . '/core/layouts.php'; require_once __DIR__ . '/core/acf-locations.php'; require_once __DIR__ . '/core/shortcode.php'; require_once __DIR__ . '/core/views.php'; require_once __DIR__ . '/core/revisions.php'; require_once __DIR__ . '/components/form.php'; require_once __DIR__ . '/components/editable.php'; require_once __DIR__ . '/components/options.php'; require_once __DIR__ . '/components/post.php'; require_once __DIR__ . '/components/row.php'; require_once __DIR__ . '/components/col.php'; require_once __DIR__ . '/components/element.php'; // this library takes care of saving custom fields for each post revision // see https://wordpress.org/plugins/wp-post-meta-revisions/ if (!class_exists('WP_Post_Meta_Revisioning')) { require_once __DIR__ . '/lib/wp-post-meta-revisions.php'; } // include example element after theme is loaded (allows disabling the // example element with a settings filter in the theme) add_action('after_setup_theme', 'layotter_include_example_element'); } }
protected function attributes() { $this->title = __('Example element', 'layotter'); $this->description = __('Use this element to play around and get started with Layotter.', 'layotter'); $this->icon = 'star'; $this->field_group = Layotter_ACF::get_example_field_group_name(); }
/** * Get ACF fields for options in a specific post * * @param int $post_id Post ID * @return array ACF fields */ private function get_fields($post_id) { $post_id = intval($post_id); $post_type = get_post_type($post_id); $fields = array(); // get ACF field groups for this option and post type $field_groups = Layotter_ACF::get_filtered_field_groups(array('post_type' => $post_type, 'layotter' => $this->type . '_options')); foreach ($field_groups as $field_group) { $fields = array_merge($fields, Layotter_ACF::get_fields($field_group)); } return $fields; }
/** * Get form data as array * * @return array Form data */ public function get_data() { // used in the form.php template $title = $this->title; $icon = $this->icon; $fields = array(); // loop through allowed fields and add field values to the array (where provided) foreach ($this->allowed_fields as $field) { $field_name = $field['name']; if (isset($this->provided_values[$field_name])) { $field['value'] = $this->provided_values[$field_name]; } $fields[] = $field; } return array('title' => $title, 'icon' => $icon, 'nonce' => wp_create_nonce('post'), 'fields' => Layotter_ACF::get_form_html($fields)); }
function layotter_assets_admin_enqueue_scripts() { // load assets only if necessary if (!Layotter::is_enabled()) { return; } // styles wp_enqueue_style('layotter', plugins_url('assets/css/editor.css', __DIR__)); wp_enqueue_style('layotter-font-awesome', plugins_url('assets/css/font-awesome.min.css', __DIR__)); // jQuery plugin used to serialize form data wp_enqueue_script('layotter-serialize', plugins_url('assets/js/vendor/jquery.serialize-object.compiled.js', __DIR__), array('jquery')); // Angular scripts $scripts = array('angular' => 'assets/js/vendor/angular.js', 'angular-animate' => 'assets/js/vendor/angular-animate.js', 'angular-sanitize' => 'assets/js/vendor/angular-sanitize.js', 'angular-ui-sortable' => 'assets/js/vendor/angular-ui-sortable.js', 'layotter' => 'assets/js/app/app.js', 'layotter-controller-editor' => 'assets/js/app/controllers/editor.js', 'layotter-controller-templates' => 'assets/js/app/controllers/templates.js', 'layotter-controller-form' => 'assets/js/app/controllers/form.js', 'layotter-service-state' => 'assets/js/app/services/state.js', 'layotter-service-data' => 'assets/js/app/services/data.js', 'layotter-service-content' => 'assets/js/app/services/content.js', 'layotter-service-templates' => 'assets/js/app/services/templates.js', 'layotter-service-layouts' => 'assets/js/app/services/layouts.js', 'layotter-service-view' => 'assets/js/app/services/view.js', 'layotter-service-forms' => 'assets/js/app/services/forms.js', 'layotter-service-modals' => 'assets/js/app/services/modals.js', 'layotter-service-history' => 'assets/js/app/services/history.js'); foreach ($scripts as $name => $path) { wp_enqueue_script($name, plugins_url($path, __DIR__)); } // fetch allowed row layouts and default layout $allowed_row_layouts = Layotter_Settings::get_allowed_row_layouts(); $default_row_layout = Layotter_Settings::get_default_row_layout(); // fetch default values for post, row and element options $default_post_options = new Layotter_Options('post'); $default_row_options = new Layotter_Options('row'); $default_col_options = new Layotter_Options('col'); $default_element_options = new Layotter_Options('element'); // fetch content structure for the current post $post_id = get_the_ID(); $content_structure = new Layotter_Post($post_id); // fetch post layouts and element templates $saved_layouts = Layotter_Layouts::get_all(); $saved_templates = Layotter_Templates::get_all_for_post($post_id); // fetch available element types $element_objects = Layotter::get_filtered_element_types($post_id); $element_types = array(); foreach ($element_objects as $element_object) { $element_types[] = array('type' => $element_object->get('type'), 'title' => $element_object->get('title'), 'description' => $element_object->get('description'), 'icon' => $element_object->get('icon')); } // fetch general settings $enable_post_layouts = Layotter_Settings::post_layouts_enabled(); $enable_element_templates = Layotter_Settings::element_templates_enabled(); // inject data for use with Javascript wp_localize_script('layotter', 'layotterData', array('postID' => $post_id, 'isACFPro' => Layotter_ACF::is_pro_installed(), 'contentStructure' => $content_structure->to_array(), 'allowedRowLayouts' => $allowed_row_layouts, 'defaultRowLayout' => $default_row_layout, 'savedLayouts' => $saved_layouts, 'savedTemplates' => $saved_templates, 'enablePostLayouts' => $enable_post_layouts, 'enableElementTemplates' => $enable_element_templates, 'elementTypes' => $element_types, 'options' => array('post' => array('enabled' => $default_post_options->is_enabled(), 'defaults' => $default_post_options->get_clean_values()), 'row' => array('enabled' => $default_row_options->is_enabled(), 'defaults' => $default_row_options->get_clean_values()), 'col' => array('enabled' => $default_col_options->is_enabled(), 'defaults' => $default_col_options->get_clean_values()), 'element' => array('enabled' => $default_element_options->is_enabled(), 'defaults' => $default_element_options->get_clean_values())), 'i18n' => array('delete_row' => __('Delete row', 'layotter'), 'delete_element' => __('Delete element', 'layotter'), 'delete_template' => __('Delete template', 'layotter'), 'edit_template' => __('Edit template', 'layotter'), 'cancel' => __('Cancel', 'layotter'), 'discard_changes' => __('Discard changes', 'layotter'), 'discard_changes_confirmation' => __('Do you want to cancel and discard all changes?', 'layotter'), 'delete_row_confirmation' => __('Do you want to delete this row and all its elements?', 'layotter'), 'delete_element_confirmation' => __('Do you want to delete this element?', 'layotter'), 'delete_template_confirmation' => __('Do you want to delete this template? You can not undo this action.', 'layotter'), 'edit_template_confirmation' => __('When editing a template, your changes will be reflected on all pages that are using it. Do you want to edit this template?', 'layotter'), 'save_new_layout_confirmation' => __('Please enter a name for your layout:', 'layotter'), 'save_layout' => __('Save layout', 'layotter'), 'rename_layout_confirmation' => __('Please enter the new name for this layout:', 'layotter'), 'rename_layout' => __('Rename layout', 'layotter'), 'delete_layout_confirmation' => __('Do want to delete this layout? You can not undo this action.', 'layotter'), 'delete_layout' => __('Delete layout', 'layotter'), 'load_layout_confirmation' => __('Do want to load this layout and overwrite the existing content?', 'layotter'), 'load_layout' => __('Load layout', 'layotter'), 'history' => array('undo' => __('Undo:', 'layotter'), 'redo' => __('Redo:', 'layotter'), 'add_element' => __('Add element', 'layotter'), 'edit_element' => __('Edit element', 'layotter'), 'duplicate_element' => __('Duplicate element', 'layotter'), 'delete_element' => __('Delete element', 'layotter'), 'move_element' => __('Move element', 'layotter'), 'save_element_as_template' => __('Save element as template', 'layotter'), 'create_element_from_template' => __('Create element from template', 'layotter'), 'add_row' => __('Add row', 'layotter'), 'change_row_layout' => __('Change row layout', 'layotter'), 'duplicate_row' => __('Duplicate row', 'layotter'), 'delete_row' => __('Delete row', 'layotter'), 'move_row' => __('Move row', 'layotter'), 'edit_post_options' => __('Edit post options', 'layotter'), 'edit_row_options' => __('Edit row options', 'layotter'), 'edit_column_options' => __('Edit column options', 'layotter'), 'edit_element_options' => __('Edit element options', 'layotter'), 'load_post_layout' => __('Load layout', 'layotter'))))); }
/** * Output form wrapper HTML depending on the installed version of ACF */ public static function output_form_wrapper() { if (Layotter_ACF::is_pro_installed()) { ?> <div class="acf-postbox"> <div id="acf-form-data" class="acf-hidden"> <input type="hidden" name="_acfnonce" value="{{ form.nonce }}"> <input id="layotter-changed" type="hidden" name="_acfchanged" value="0"> </div> <div class="acf-fields" ng-bind-html="form.fields | rawHtml"></div> </div> <?php } else { ?> <div class="acf_postbox"> <div class="inside" ng-bind-html="form.fields | rawHtml"></div> </div> <?php } }
function layotter_ajax_update_template() { $post_data = layotter_get_angular_post_data(); // type and field values are required if (isset($post_data['template_id']) and is_int($post_data['template_id'])) { $id = $post_data['template_id']; $template = Layotter_Templates::get($id); if ($template) { $values = Layotter_ACF::unwrap_post_values(); $element = Layotter::create_element($template['type'], $values); if ($element) { $element->set_template_id($id); Layotter_Templates::update($id, $element->get_template_data()); echo json_encode($element->to_array()); } } } die; // required by Wordpress after any AJAX call }
/** * Check if this element type is enabled for a specific post * * @param int $post_id Post ID * @return bool Whether this element type is enabled */ public final function is_enabled_for($post_id) { $post_id = intval($post_id); $post_type = get_post_type($post_id); if (is_int($this->field_group)) { $field_group = Layotter_ACF::get_field_group_by_id($this->field_group); } else { $field_group = Layotter_ACF::get_field_group_by_key($this->field_group); } return Layotter_ACF::is_field_group_visible($field_group, array('post_id' => $post_id, 'post_type' => $post_type, 'layotter' => 'element')); }
<h2>{{ form.title }}</h2> </div> <div class="layotter-modal-head-fullscreen"> <span class="layotter-modal-head-fullscreen-expand" ng-click="toggleFullscreen()" title="<?php __('Switch to fullscreen editor', 'layotter'); ?> "><i class="fa fa-expand"></i></span> <span class="layotter-modal-head-fullscreen-compress hidden" ng-click="toggleFullscreen()" title="<?php __('Switch to small editor', 'layotter'); ?> "><i class="fa fa-compress"></i></span> </div> </div> <div class="layotter-modal-body"> <?php Layotter_ACF::output_form_wrapper(); ?> </div> <div class="layotter-modal-loading-container"> </div> <div class="layotter-modal-foot"> <button type="submit" class="button button-primary button-large"><?php _e('Save', 'layotter'); ?> </button> <button type="button" class="button button-large" ng-click="cancelEditing()"><?php _e('Cancel', 'layotter'); ?> </button> <button type="button" class="button button-large" ng-click="backToShowNewElementTypes()" ng-show="showBackButton"><?php _e('Back', 'layotter');
<?php /** * Register the field group required for the example element that comes with Layotter */ $key = Layotter_ACF::get_example_field_group_name(); $title = __('Example element for Layotter', 'layotter'); $message_label = __('Thank you for trying out Layotter!', 'layotter'); $message = __("This is an example element you can use to get started with Layotter. When you're ready to create your own element types, go to the settings page to disable it.", 'layotter'); $default_text = __("Welcome to the text editor! Write something, insert links or images, and click save when you're done.", 'layotter') . "\n\n" . __("By the way, Layotter isn't limited to text fields. You can create all kinds of content, like embedded Google maps, image galleries, file uploads, and much more!", 'layotter'); $content_label = __('Content', 'layotter'); if (Layotter_ACF::is_pro_installed()) { acf_add_local_field_group(array('key' => $key, 'title' => $title, 'fields' => array(array('key' => 'field_5605a6602418d', 'label' => $message_label, 'name' => '', 'type' => 'message', 'instructions' => '', 'required' => 0, 'conditional_logic' => 0, 'wrapper' => array('width' => '', 'class' => '', 'id' => ''), 'message' => $message, 'esc_html' => 0), array('key' => 'field_5605a6ed2418e', 'label' => $content_label, 'name' => 'content', 'type' => 'wysiwyg', 'instructions' => '', 'required' => 0, 'conditional_logic' => 0, 'wrapper' => array('width' => '', 'class' => '', 'id' => ''), 'default_value' => $default_text, 'tabs' => 'all', 'toolbar' => 'full', 'media_upload' => 1)), 'location' => array(array(array('param' => 'layotter', 'operator' => '==', 'value' => 'element'))), 'menu_order' => 0, 'position' => 'normal', 'style' => 'default', 'label_placement' => 'top', 'instruction_placement' => 'label', 'hide_on_screen' => '', 'active' => 1, 'description' => '')); } else { register_field_group(array('id' => $key, 'title' => $title, 'fields' => array(array('key' => 'field_58011c544f031', 'label' => $message_label, 'name' => '', 'type' => 'message', 'message' => $message), array('key' => 'field_58011c654f032', 'label' => $content_label, 'name' => 'content', 'type' => 'wysiwyg', 'default_value' => $default_text, 'toolbar' => 'full', 'media_upload' => 'yes')), 'location' => array(array(array('param' => 'layotter', 'operator' => '==', 'value' => 'element', 'order_no' => 0, 'group_no' => 0))), 'options' => array('position' => 'normal', 'layout' => 'no_box', 'hide_on_screen' => array()), 'menu_order' => 0)); }
/** * Format user-provided values for output * * @param array $existing_fields Existing fields as provided by an ACF field group * @param array $clean_values Array with clean values (that were run through $this->clean_values() first) * @return array Formatted values for output */ protected static final function format_values($existing_fields, $clean_values) { $values = array(); // run all provided values through formatting filters foreach ($existing_fields as $field_data) { $field_name = $field_data['name']; // skip ACF 'tab' and 'message' fields to prevent pollution of $values with empty keys and values if (empty($field_name)) { continue; } // note: // in default ACF, field values are run through the acf/load_value filter before formatting // this filter can break fields in Layotter's context and is therefore not applied // format values using ACF's formatting filters $values[$field_name] = Layotter_ACF::format_value($clean_values[$field_name], $field_data); } return $values; }