Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of using post_meta, i.e page custom css #463

Open
pingram3541 opened this issue Nov 1, 2015 · 22 comments
Open

Example of using post_meta, i.e page custom css #463

pingram3541 opened this issue Nov 1, 2015 · 22 comments
Labels
Milestone

Comments

@pingram3541
Copy link
Contributor

Is there an example of how to use Kirki fields to get/put post_meta? For example, my theme has custom SEO fields for each page, I'd like to add editing capabilities in the customizer. I can't seem to find in the documentation all the possibilities for the config item 'option_name'. Does it currently only support options and theme_mods? If so, seems like post_meta would a great addition. Thanks.

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@aristath
Copy link
Contributor

aristath commented Nov 3, 2015

Hey again!

Yes, for the time being Kirki can only use options & theme_mods 'cause that's what people use 99% of the time.
I've been looking fore a way to abstract that however... I'd love to hear your thoughts.
What other data types can be used? Have you ever done it?
Is changing the type in $wp_customize->add_setting() all that's required or should we take into account anything more? 'Cause if it's just that it should be pretty simple to implement

@aristath aristath added this to the 1.2 milestone Nov 3, 2015
@aristath aristath self-assigned this Nov 3, 2015
@aristath
Copy link
Contributor

aristath commented Nov 3, 2015

I just read this article http://torquemag.io/using-wordpress-customizer-saving-user-specific-options/ that explains how to use different types of data types.
It looks simple enough so I'll take a look at it. :)
The problem is that for data types other than option & theme_mod we'll have to create methods that will be triggered on customize_save_{data_type}
We can do that... but it will have to be a different method for user_meta, post_meta and anything else we come up with.

@pingram3541
Copy link
Contributor Author

I had also come across customize_update_$type and customize_preview_$type here https://make.wordpress.org/core/2014/07/08/customizer-improvements-in-4-0/ but struggled to find a working example. I'm loving how easy it was for me jump right in with kirki, Thanks again.

@pingram3541
Copy link
Contributor Author

Just had a look at this again and I built a custom setting as follows:

Kirki::add_config( 'post_meta', array(
    'capability'    => 'edit_theme_options',
    'option_type'   => 'post_meta',
) );

I then built my field:

Kirki::add_field( 'post_meta', array(
    'type'        => 'code',
    'settings'     => 'custom-post-css',
    'label'       => __( 'Custom Page CSS', 'tt-opts' ),
    'description' => __( 'Edit the page\'s custom css located: Edit Page > Options > Custom CSS', 'tt-opts' ),
    'help'        => __( 'Make changes here to apply page only style changes to your website.', 'tt-opts' ),
    'section'     => 'tt_page_css',
    'default'     => __( '', 'tt-opts' ),
    'priority'    => 10,
    'transport'   => 'postMessage', \\we'll use cm's update capabilities for preview
    'choices'     => array(
        'language' => 'css',
        'theme'    => 'monokai',
    ),
) );

I then built the the preview function for this custom setting which I've verified does indeed fire upon loading the customizer:

add_action( 'customize_preview_post_meta', 'tt_preview_post_meta');
function tt_preview_post_meta( $value, $setting ) {
    //$postid = get_the_ID(); //nope
    //$custom_css = get_post_meta( $postid, 'custom-post-css' );
    if ( isset( $_POST['customized'] ) ) {
        $post_values = json_decode( wp_unslash( $_POST['customized'] ), true );
    }
    write_log( $post_values ); // result in empty array
}

However I can't seem to figure out how to get the post id or post object. I think I need to modify the core Kirki class to make that object available because $_POST['customized'] is empty.

Any help is greatly appreciated.

@aristath
Copy link
Contributor

Hey again

We will provide additional data types for the customizer, but tbh at this time it's just not a priority... We have to fix bugs first before adding any new features.
So after we release a stable version I'll start working on providing these. :)

@aristath aristath modified the milestones: 1.2, 2.1 Nov 24, 2015
@pingram3541
Copy link
Contributor Author

Great news and no hurry. Looking into this -> https://gist.github.com/westonruter/1feb78845c8e562dd59d but in my situation I don't need to pass the post id and data back and forth via ajax, Kirki can handle that with the code (hidden textarea) type field already. I simply need the post ID so I can grab the meta key value, populate my cm instance and let the cm object's built in update method provide the live preview to a dynamically added DOM style element in the iframe which I already do with my global custom css in wp_options perfectly. So maybe I just need to wrap my stuff in a class extending the Kirki class to pass the post id after a few checks like is_single and such?

i.e. lines 52 - 56 in class-customize-queried-post-info.php

@pingram3541
Copy link
Contributor Author

I finally got this working with the help of @westonruter and @aristath, thank you both.

  1. Add the Kirki code type field but set it's config to a dummy config so as not to save to as an option or theme_mod.
Kirki::add_config( 'mytheme_post_meta', array(
    'capability'    => 'edit_theme_options',
    'option_type'   => 'mytheme_post_meta', //something unique but doesn't really "do" anything
    //don't use 'option_name' otherwise value is stored in wp_options under that key
) );

Kirki::add_field( 'mytheme_post_meta', array(
    'type'        => 'code',
    'settings'     => 'mytheme-post-css',
    'label'       => __( 'Custom Page CSS', 'mytheme-opts' ),
    'description' => __( 'Edit the page\'s custom css located in post_meta', 'mytheme-opts' ),
    'help'        => __( 'Make changes here to apply page only style changes to your website.', 'mytheme-opts' ),
    'section'     => '', //whatever section you want to use
    'default'     => __( 'loading...', 'mytheme-opts' ), //shows while waiting for preview to load
    'priority'    => 10,
    'transport'   => 'postMessage', //let's us define our own refresh callback via js
    'choices'     => array(
        'language' => 'css',
        'theme'    => 'monokai',
    ),
    'sanitize_callback' => 'mytheme_post_css', //the callback to execute when saving
) );
  1. I modified the above linked gist from @westonruter to store the queried post id in window.pid replacing L27 in customize-controls.js with:
window.pid = newPost.ID.toString(); // see console.log(window.pid);
  1. Now that the code editor is in the customizer and I have the post id in js I decided to populate the code editor from my preview's DOM using js. My custom page css is already provided on the front end via my theme and uses a unique id on the style tag such as:
<style id="post-custom-css">...

So I use the following js (just below L27 we modified in customize-controls.js) to update the code editor from that style element's contents.

var post_css_editor = $('body #customize-control-mytheme-post-css .CodeMirror')[0].CodeMirror;
var post_css_style = $('#customize-preview iframe').contents().find('#post-custom-css');
var post_css = post_css_style.html(); //get contents of style element
if(post_css){
    post_css_editor.setValue(post_css.replace(/^\s+|\s+$/g, '')); //set editor value removing opening and closing line breaks
}
  1. Ok, now we have the editor with our custom page specific css. We'll now use the listener event on the code editor so we can see our live edits. I copied Kirki's code control from /kirki/assets/js/controls/code.js. I also modified the control that returns the value to our sanitize_callback function in step 1 so that it passes both the post id and the editor value. I added this code just before the last line in customize-controls.js (before closing the anonymous function)
wp.customize.controlConstructor['code'] = wp.customize.Control.extend( {
    ready: function() {
        var control = this;
        var element = control.container.find( '#kirki-codemirror-editor-' + control.id );

        var editor  = CodeMirror.fromTextArea( element[0] );
        editor.setOption( "value", control.setting._value );
        editor.setOption( "mode", control.params.choices.language );
        editor.setOption( "lineNumbers", true );
        editor.setOption( "theme", control.params.choices.theme );
        editor.setOption( "height", control.params.choices.height + 'px' );

        editor.on('change', function() {
            if( element.attr('id') == 'kirki-codemirror-editor-mfn-post-css'){
                //update our preview style element w/ code editor 
                $('#customize-preview iframe').contents().find('#post-custom-css').html(editor.setValue());
                var postData = 
                {
                    "postid" :  window.pid,
                    "data" :    editor.getValue(),
                }
                control.setting.set( postData ); //passes id and css value back to php
            } else {
            control.setting.set( editor.getValue() ); //in case we have other code editors
            }
        });

    element.parents('.accordion-section').on('click', function(){
            editor.refresh();
    });
    }
});

Everytime the code editor is updated we are doing 2 things, 1) updating the preview's css style element contents for the live preview and 2) updating the customizer object's value with an object containing the queried post id and the contents of our code editor.

  1. Back in our php (functions.php or some other include) just below where we defined our Kirki config and field (in step 1) we use the following callback to save our data:
function mytheme_post_css($value){
    update_post_meta($value['postid'], 'post-custom-css', $value['data']); //where "post-custom-css" is the meta key I am storing the page/post only custom css
}

fin =)

@pingram3541 pingram3541 changed the title Example of using post_meta Example of using post_meta, i.e page custom css Dec 8, 2015
@pingram3541 pingram3541 reopened this Dec 8, 2015
@pingram3541
Copy link
Contributor Author

Sorry, should probably leave this open as I still think it would be beneficial to have this built into kirki as a config type 'option', 'theme_mods' AND 'post_meta' =)

@lmartins
Copy link

This will such an incredible addition to Kirki. Per-page layout options, customisations, the applications are immense and will solve many practical needs I have today. Im not an experienced developer but if you need any help, maybe testing or something, please let me know. I have deep interest in this feature.

@aristath
Copy link
Contributor

aristath commented Mar 5, 2016

Just an update here, I just added the ability to use user_meta as an option_type.
Adding post_meta is next on my list. 👍

@lmartins
Copy link

lmartins commented Mar 5, 2016

Cool! Post a hopefully term meta open so many options. Thanks for the update. ;)

Luís Martins

@aristath
Copy link
Contributor

aristath commented Mar 5, 2016

After reviewing the changes made by @pingram3541 this is going to be harder than I thought.
His implementation is solid, but pretty specific since he basically hard-coded these for a specific field.
The problem I'm facing right now is abstracting his logic so that it works for all controls...
This is gonna take some time.

@pingram3541
Copy link
Contributor Author

I think we need to tie this in once selective refresh (https://make.wordpress.org/core/2016/02/16/selective-refresh-in-the-customizer/) is part of the core, then we will have more control by adding the specific refresh callback desired for that particular field in the field settings array.

Oh and regarding the solution I posted above, the main reason I chose to do it that way was specifically because the page's unique css (stored as post_meta) is already in the preview window as a "style" element so we can use that to populate our code editor's initial value since there's no way to pass it directly with php without modifying the core wp_customize method.

We essentially go the long way, pass post_id and post_meta to the customizer js object. Use js to update our Kirki fields initial value from those objects (or the DOM in my example). Use js again to update the wp_customize postData object anytime our fields change which is also what is passed when saving. Our field's sanitize_callback function is executed when saving updating post_meta from the post id and field's value.

The magic is all in the above mentioned gist by @westonruter where the post_meta is passed to the customizer "newPost" object. You have all the post meta at your disposal as a js object in which specific keys can be extrapolated for use with any Kirki field type that has a sanitize_callback method.

newPost.ID and newPost.meta

Since choosing to pass the field's value back via its sanitize_callback function, all that is needed to accomplish the task is the post id and the value because the field itself implies what post_meta key we need to update.

@aristath aristath modified the milestones: 2.2, 2.3, 3.0 Mar 23, 2016
@guillaumemolter
Copy link
Contributor

👍 for post_meta

@aristath
Copy link
Contributor

Yeah, I agree post_meta will be awesome.
For the time being I'm trying to figure out the best way to implement it and I'm watching closely the https://github.com/xwp/wp-customize-posts plugin (which at some point will probably be merged in WP Core).
See xwp/wp-customize-posts#1

@Bobolions
Copy link

+1 for me.
Tested this plugin: https://github.com/Invulu/custom-customizer-postmeta
It works with WP Customize Posts plugin: https://github.com/xwp/wp-customize-posts
It loads the values from a JSON file.

It would be awesome if we could somehow add (some) Kirki controls to the WP Customize Posts plugin.

@pingram3541
Copy link
Contributor Author

Yes +1 on this.

@aristath aristath modified the milestones: 3.1, 3.0 May 18, 2017
aristath added a commit that referenced this issue Jul 18, 2017
@JiveDig
Copy link

JiveDig commented Aug 11, 2017

+1 on post_meta, and another +1 on term_meta. Kirki would be killer with these features. There are enough users ok Kirki now, I wonder if a bit of crowdfunding would be worth it to "buy" more time for @aristath to keep this moving?

@Alanimus
Copy link

How is my code half-working if post_meta isn't even yet added to WP Core?

My page is ordered into "sections". I created code that uses the Kirki sortable control to reorganise certain sections of the page template.

I see the customizer preview update if I move a section to the middle, but it doesn't update properly if I move a sortable section to the "top".

Kirki control:

Gomaxchild_Kirki::add_field( 'gomaxchild', array(
	'type'        => 'sortable',
	'settings'    => 'gm_sortable_sections',
	'label'       => __( 'This is the label', 'gomax_child' ),
	'section'     => 'gm_sections',
	'default'     => array(),
	'choices'     => array(
		'section_54d9441ccc989' => esc_attr__( '3 Features', 'gomax_child' ),
		'section_54d9465e8f5fc' =>    esc_attr__('Info + Slider', 'gomax_child'),
		'section_104962947159e309f02801f' => esc_attr__('Rates', 'gomax_child'),
		'section_54d948bc49b31' => esc_attr__('More Features','gomax_child'),
		'section_54d947d51e12f' => esc_attr__( 'Testimonials', 'gomax_child' ),
	),
	'priority'    => 10,
	'transport' => 'auto',
) );

My function:

function gm_test_section_order(){
	$post_id = themeblvd_config( 'builder_post_id' );
	$sections = get_post_meta( $post_id, '_tb_builder_elements', true );
	$defaults = array(
		'section_54d9441ccc989',
		'section_54d9465e8f5fc',
		'section_104962947159e309f02801f',
		'section_54d948bc49b31',
		'section_54d947d51e12f',
	);
	$gm_options_sections = get_theme_mod('gm_sortable_sections', $defaults);

	array_unshift( $gm_options_sections, 'primary' ); // Make sure primary is always on top
	
	$new_section_order = array_replace( array_flip( $gm_options_sections ), $sections );
	update_post_meta( $post_id, '_tb_builder_elements', $new_section_order);
	
}
add_action('themeblvd_section_top', 'gm_test_section_order', 10);

@aristath aristath modified the milestones: 3.1, Future Release Nov 12, 2017
@amans2k
Copy link

amans2k commented Apr 10, 2018

Hello @aristath

Kirki is fantastic, almost everything is available now.
Any update on option_type = post_meta
I have displayed customizer on a specific post type and each post have separate fields
post_id is coming as a query parameter.

Let me know. Thanks!

@aristath
Copy link
Contributor

No update here yet... I'm working on something similar on a custom theme but so far haven't found a way to abstract it in a way that can be reliably used by generic controls.

@amans2k
Copy link

amans2k commented Apr 19, 2018

Thanks for the update.

For now, I have managed my work. Saved as option and option_name has post id
So each post settings are saved on a single key in the wp_options table.

But yeah option_type - post_meta would be really good.

@aristath aristath removed their assignment Sep 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants