├── README.md └── flexible-templates-for-acf-pro ├── acf-flexible-templates.php ├── css └── style.css ├── class-flexible-templates.php └── js └── script.js /README.md: -------------------------------------------------------------------------------- 1 | # Flexible Templates for ACF PRO 2 | WP Plugin that allows saving templates of the "Flexible Content" field, for easy and fast re-use of them on other pages. It also separates templates by post types. 3 | 4 | ## Install / How to use 5 | 6 | Install as any other wp plugin and activate. 7 | 8 | When you go to page that has Flexible Content, you'll notice a button on top left corner with saved templates. Hover the button to see a dropdown with template selection, click the template name to load it. Be aware that loading the template will overwrite the existing one. You also able to delete templates from there, by pressing the "minus" button/circle. 9 | 10 | To save your template, go to the bottom of your Flexible Content field, you will see the input field for the name of your tempalte and save button. Before saving plugin checks for the already existing template with name you input, every template name have to be unique. 11 | 12 | ## How it works? 13 | ACF saves all the field values to own meta. But to save templates, we created a new table in DB for storing them, as we store the HTML code that has been generated by the plugin to show the layout in Flexible Content field. This way we save all the fields and values in one place. When loading it back to Flexible Content field, we than have save/update page, as this reinitializes the fields like "Wysiwyg Editor". 14 | 15 | ## Contributors 16 | I would like to avoid saving the page after the template is loaded, but couldn't find a solution yet, to reint the tinymce plugin. If you have and ideas or a solution for the issue, please contribute! :) 17 | -------------------------------------------------------------------------------- /flexible-templates-for-acf-pro/acf-flexible-templates.php: -------------------------------------------------------------------------------- 1 | prefix . 'flexible_templates_acf'; 31 | 32 | if($wpdb->get_var( "show tables like '$acf_ft_table_name'" ) != $acf_ft_table_name) { 33 | 34 | $sql = "CREATE TABLE $acf_ft_table_name ( 35 | id mediumint(9) NOT NULL AUTO_INCREMENT, 36 | time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, 37 | name text NOT NULL, 38 | template longblob NOT NULL, 39 | post_type text NOT NULL, 40 | PRIMARY KEY (id) 41 | );"; 42 | 43 | dbDelta( $sql ); 44 | } 45 | 46 | } 47 | 48 | add_action('init', 'acf_ft_updatetables'); 49 | function acf_ft_updatetables(){ 50 | global $wpdb, $acf_ft_version; 51 | 52 | $acf_ft_table_updated = get_option( 'acf_ft_table_updated' ); 53 | $acf_ft_table_name = $wpdb->prefix . 'flexible_templates_acf'; 54 | 55 | if( !$acf_ft_table_updated || $acf_ft_table_updated == '' ) { 56 | 57 | $sql = "ALTER TABLE $acf_ft_table_name ADD post_type text NOT NULL AFTER template"; 58 | 59 | $row = $wpdb->get_results( "SELECT post_type FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '$acf_ft_table_name'" ); 60 | 61 | if(empty($row)){ 62 | $wpdb->query("ALTER TABLE $acf_ft_table_name ADD post_type text NOT NULL AFTER template"); 63 | } 64 | 65 | update_option( 'acf_ft_table_updated', 'updated' ); 66 | } 67 | } 68 | 69 | 70 | 71 | function acfft_add_template( $name, $template, $post_type = 'page' ) { 72 | global $wpdb; 73 | 74 | $acf_ft_table_name = $wpdb->prefix . 'flexible_templates_acf'; 75 | 76 | if( !$name || !$template ) return false; 77 | 78 | $wpdb->insert( 79 | $acf_ft_table_name, 80 | array( 81 | 'time' => current_time( 'mysql' ), 82 | 'name' => $name, 83 | 'template' => $template, 84 | 'post_type' => $post_type, 85 | ) 86 | ); 87 | 88 | return true; 89 | } 90 | 91 | function acfft_remove_template( $name ) { 92 | global $wpdb; 93 | 94 | $acf_ft_table_name = $wpdb->prefix . 'flexible_templates_acf'; 95 | 96 | if( !$name ) return false; 97 | 98 | $wpdb->delete( $acf_ft_table_name, array( 'name' => $name ) ); 99 | 100 | return true; 101 | } 102 | 103 | 104 | 105 | function acfft_get_templates( $post_type = 'page' ){ 106 | global $wpdb; 107 | 108 | $acf_ft_table_name = $wpdb->prefix . "flexible_templates_acf"; 109 | 110 | $row = $wpdb->get_results( "SELECT * FROM $acf_ft_table_name WHERE post_type = '$post_type'" ); 111 | if( !empty($row) ) return $row; 112 | 113 | return false; 114 | } 115 | 116 | function acfft_get_templates_by_name( $name ){ 117 | global $wpdb; 118 | 119 | $acf_ft_table_name = $wpdb->prefix . "flexible_templates_acf"; 120 | 121 | $row = $wpdb->get_results( "SELECT * FROM $acf_ft_table_name WHERE name = '$name'" ); 122 | if( !empty($row) ) return $row; 123 | 124 | return false; 125 | } 126 | 127 | function acfft_check_name( $name ){ 128 | $row = acfft_get_templates_by_name( $name ); 129 | 130 | if( !empty($row) ) return 'name_exists'; 131 | return 'ok'; 132 | } 133 | 134 | 135 | include_once('class-flexible-templates.php'); 136 | ?> 137 | -------------------------------------------------------------------------------- /flexible-templates-for-acf-pro/css/style.css: -------------------------------------------------------------------------------- 1 | .acf-flexible-content .acf-ft-save-wrap{ 2 | float: left; 3 | margin-left: 0; 4 | width: 50%; 5 | min-width: 400px; 6 | } 7 | 8 | .acf-flexible-content .acf-ft-save-wrap .acf-ft-template-name{ 9 | float: left; 10 | width: 62%; 11 | margin-right: 1%; 12 | } 13 | 14 | .acf-flexible-content .acf-ft-save-wrap .acf-ft-save{ 15 | float: left; 16 | width: 37%; 17 | text-align: center; 18 | box-shadow: none; 19 | } 20 | 21 | 22 | 23 | .acfft_flexible_templates.button-primary{ 24 | position: relative; 25 | padding: 3px 35px 3px 10px; 26 | top: -4px; 27 | float: right; 28 | height: auto; 29 | font-weight: normal; 30 | line-height: 16px; 31 | z-index: 9; 32 | } 33 | 34 | .acfft_flexible_templates:after{ 35 | font-family: "acf"; 36 | content: '\e80f'; 37 | position: absolute; 38 | right: 14px; 39 | top: 4px; 40 | } 41 | 42 | .acfft_flexible_templates .acfft-dropdown{ 43 | position: absolute; 44 | display: none; 45 | background: #fff; 46 | border: 1px solid #999; 47 | border-radius: 2px; 48 | right: -1px; 49 | top: 100%; 50 | width: 250px; 51 | height: 0px; 52 | max-height: 204px; 53 | overflow: auto; 54 | box-shadow: 0 4px 6px rgba(0,0,0,0.1); 55 | } 56 | .acfft_flexible_templates:hover .acfft-dropdown{ 57 | display: block !important; 58 | height: auto; 59 | } 60 | 61 | .acfft_flexible_templates .acfft-dropdown .acfft-option, 62 | .acfft_flexible_templates .acfft-dropdown .info{ 63 | padding: 8px 5px 8px 15px; 64 | color: #000; 65 | text-shadow: none; 66 | border-bottom: 1px solid #f1f1f1; 67 | cursor: pointer; 68 | overflow: hidden; 69 | white-space: normal; 70 | } 71 | .acfft_flexible_templates .acfft-dropdown .acfft-option:hover{ 72 | background: #efefef; 73 | } 74 | 75 | 76 | .acfft_flexible_templates .acfft-dropdown .acfft-option .acfft-select{ 77 | display: block; 78 | float: left; 79 | width: 180px; 80 | cursor: pointer; 81 | } 82 | 83 | .acfft_flexible_templates .acfft-dropdown .acfft-option.acfft-separator{ 84 | display: block; 85 | background-color: #f7f7f7; 86 | font-weight: bold; 87 | } 88 | .acfft_flexible_templates .acfft-dropdown .acfft-option.acfft-separator.new{ 89 | background-color: #dedede; 90 | } 91 | 92 | .acfft_flexible_templates .acfft-dropdown .acfft-option .acfft-remove{ 93 | display: block; 94 | float: right; 95 | width: 30px; 96 | text-align: center; 97 | position: relative; 98 | cursor: pointer; 99 | } 100 | .acfft_flexible_templates .acfft-dropdown .acfft-option .acfft-remove:after{ 101 | font-family: "acf"; 102 | content: '\e801'; 103 | width: 18px; 104 | height: 18px; 105 | line-height: 18px; 106 | font-size: 14px; 107 | color: #999; 108 | border: 1px solid #ddd; 109 | background-color: #fff; 110 | border-radius: 100%; 111 | position: absolute; 112 | left: 50%; 113 | top: 50%; 114 | margin: -9px 0 0 -9px; 115 | } 116 | 117 | .acfft_flexible_templates .acfft-dropdown .acfft-option .acfft-remove:hover:after{ 118 | background-color: #F55E4F; 119 | border-color: #F55E4F; 120 | color: #fff; 121 | } 122 | 123 | 124 | .acf-ft-save-error{ 125 | float: left; 126 | width: 100%; 127 | padding: 5px; 128 | color: #F55E4F; 129 | } 130 | 131 | .acf-ft-save-error.saved{ 132 | color: green; 133 | } 134 | 135 | 136 | .acf-ft-updating-template { 137 | position: fixed; 138 | top: 0; 139 | left: 0; 140 | width: 100%; 141 | height: 100%; 142 | background: rgba(0,0,0,0.5); 143 | z-index: 999999; 144 | transition: opacity 0.5s ease; 145 | } 146 | 147 | .acf-ft-updating-template span{ 148 | position: absolute; 149 | left: 50%; 150 | top: 50%; 151 | transform: translate(-50%, -50%); 152 | color: #fff; 153 | } -------------------------------------------------------------------------------- /flexible-templates-for-acf-pro/class-flexible-templates.php: -------------------------------------------------------------------------------- 1 | template; 58 | 59 | echo $template; 60 | }else{ 61 | echo 'not ok'; 62 | } 63 | die(); 64 | } 65 | 66 | public function ajax_template_save() { 67 | global $post; 68 | 69 | if( isset($_POST['name']) && $_POST['template'] != '' ){ 70 | 71 | $name = strip_tags($_POST['name']); 72 | $template = strip_tags($_POST['template']); 73 | $pt = strip_tags($_POST['post_type']); 74 | 75 | $check = acfft_check_name( $name ); 76 | 77 | if( $check === 'ok' ){ 78 | acfft_add_template( $name, $template, $pt ); 79 | 80 | echo $check; 81 | } 82 | 83 | }else{ 84 | echo 'not ok'; 85 | } 86 | die(); 87 | } 88 | 89 | 90 | public function input_admin_enqueue_scripts(){ 91 | 92 | $dir = plugin_dir_url(__FILE__); 93 | 94 | // register & include JS 95 | wp_register_script('acf-ft-scripts', "{$dir}js/script.js"); 96 | wp_enqueue_script('acf-ft-scripts'); 97 | 98 | $localized = array(); 99 | $localized['ajaxurl'] = admin_url( 'admin-ajax.php' ); 100 | $localized['no_name'] = __('Please input template name.', 'acf-ft'); 101 | $localized['name_exists'] = __('Template with same name already exists.', 'acf-ft'); 102 | $localized['saved'] = __('Template saved.', 'acf-ft'); 103 | $localized['tpl_name'] = __("Template name", 'acf-ft'); 104 | $localized['tpl_save'] = __("Save this template", 'acf-ft'); 105 | 106 | wp_localize_script('acf-ft-scripts', 'acfft', $localized ); 107 | 108 | // register & include CSS 109 | wp_register_style('acf-ft-styles', "{$dir}css/style.css"); 110 | wp_enqueue_style('acf-ft-styles'); 111 | 112 | } 113 | 114 | public function filter_get_field_label($label, $field){ 115 | global $post; 116 | /* 117 | echo '
'; 118 | print_r( $post ); 119 | echo ''; 120 | */ 121 | 122 | if( $field['type'] == 'flexible_content' && $post->post_type != 'acf-field-group' ) { 123 | $label .= $this->get_templates_list(); 124 | } 125 | 126 | return $label; 127 | } 128 | 129 | 130 | public function cmp($a, $b){ 131 | return strcmp($a->name, $b->name); 132 | } 133 | 134 | 135 | public function get_templates_list(){ 136 | global $post; 137 | 138 | $post_type = $post->post_type; 139 | 140 | $templates = acfft_get_templates( $post_type ); 141 | 142 | // old templates withour post_type 143 | $depricated_templates = acfft_get_templates( '' ); 144 | 145 | $out = ''; 191 | 192 | // $out = ''; 207 | 208 | return $out; 209 | } 210 | 211 | } 212 | 213 | new Flexible_Templates(); 214 | 215 | endif; 216 | 217 | ?> -------------------------------------------------------------------------------- /flexible-templates-for-acf-pro/js/script.js: -------------------------------------------------------------------------------- 1 | jQuery.expr[':'].parents = function(a,i,m){ 2 | return jQuery(a).parents(m[3]).length < 1; 3 | }; 4 | 5 | (function($){ 6 | 7 | 8 | $(window).load(function(){ 9 | 10 | 11 | 12 | //if( $('.acf-field-flexible-content').length ){ 13 | 14 | var button = '