Support » Plugin: CMB2 » Set Field values from database with add_group_field

  • Resolved dkurth

    (@dkurth)


    I have data stored in a different table that I retrieve, but how can I insert my stored values from the database. I do not use the postmeta for a variety of reason. I need to load all the fields, including the repeatable, with my independently stored data.
    Nice job overall.

    UPDATE, NEVER MIND. Found your Callback feature.

    • This topic was modified 9 months, 1 week ago by dkurth.
Viewing 15 replies - 1 through 15 (of 24 total)
  • Found the call back feature, but it does not appear to do anything. Can you see what the problem is? Here is the code:

    $group_field_id = $cmb->add_field( array(
    ‘id’ => ‘ListRecords’,
    ‘type’ => ‘group’,
    ‘description’ => __( ‘Individual Directory Listings’, ‘cmb2’ ),
    ‘options’ => array(
    ‘group_title’ => __( ‘Record {#}’, ‘cmb2’ ),
    ‘add_button’ => __( ‘Add Another Record’, ‘cmb2’ ),
    ‘remove_button’ => __( ‘Remove Record’, ‘cmb2’ ),
    ‘sortable’ => true,
    ),
    ) );

    $cmb->add_group_field( $group_field_id, array(
    ‘name’ => $FieldDesc,
    ‘id’ => $FieldId,
    ‘type’ => ‘text’,
    ‘before_row’ => ‘cmb2_before_row_if_2’,
    ) );

    function cmb2_before_row_if_2( $field_args, $field )
    {
    DebugLog(‘test function’);
    }

    • This reply was modified 9 months, 1 week ago by dkurth.

    ahgggg! I just want to place data in the fields and read them back (is it too much to ask!) . Hard coding data into default, does nothing either. But the boxes are looking good! I even tried this…no results.

    add_action( ‘cmb2_admin_init’, ‘MetaBox’ );
    function MetaBox()
    {
    $prefix = ‘mmdlist’;
    $cmb = new_cmb2_box( array(
    ‘id’ => ‘mmd_lists_ManualEntry’,
    ‘title’ => __( ‘Google Lists – Card Records : Manual Input’, ‘cmb2’ ),
    ‘object_types’ => $prefix,
    ‘context’ => ‘normal’,
    ‘priority’ => ‘high’,
    ‘show_names’ => true,
    ) );

    $group_field_id = $cmb->add_field( array(
    ‘id’ => ‘ListRecords’,
    ‘type’ => ‘group’,
    ‘description’ => __( ‘Individual Directory Listings’, ‘cmb2’ ),
    ‘options’ => array(
    ‘group_title’ => __( ‘Record {#}’, ‘cmb2’ ),
    ‘add_button’ => __( ‘Add Another Record’, ‘cmb2’ ),
    ‘remove_button’ => __( ‘Remove Record’, ‘cmb2’ ),
    ‘sortable’ => true,
    ),
    ) );

    $cmb->add_group_field( $group_field_id, array(
    ‘name’ => $FieldDesc,
    ‘id’ => $prefix . $FieldId,
    ‘type’ => ‘text’,
    ‘on_front’ => false,
    ‘save_field’ => false,
    ‘attributes’ => array(
    ‘placeholder’ => $Field[‘PH’] ,
    ‘required’ => $Field[‘required’],
    ),
    ‘default’ => ‘Debbie’,
    ‘default_cb’ => ‘SetTextBox’,
    ) );
    }

    function SetTextBox($args, $field)
    {
    DebugLog(‘SET FIELD VALUES’);
    }

    • This reply was modified 9 months, 1 week ago by dkurth.
    Plugin Author Justin Sternberg

    (@jtsternberg)

    If you place backticks (`) around your code blocks, it will make them formatted and much more readable for us.

    is it too much to ask!

    No. 🙂
    I have added some info in the Tips/Tricks section of the CMB2 Wiki, as well as a example in the CMB2 Snippet Library (linked from the wiki). Check it out: https://github.com/CMB2/CMB2/wiki/Tips-&-Tricks#override-the-data-storage-location-for-a-cmb2-box

    Got it (and will do on the ticks).

    Forgive the confusion….I have not used filters and hooks very much, as my background is a c++ programmer and not so much a php (but learning quickly).

    Here is what I want to achieve:
    I have a table with membership records. I want to fill the form with all the available records from that table. Then on “Add New Record”, it needs to be blank for the data entry.

    On clicking the “Update” button, I would then read ALL THE records, presently available and store them back into the data base,as a update and an insert for the new record.

    Application
    Now, if I am reading your documentation and sample correctly, I would be applying the filter to the group field, thus disabling all fields from being retrieved, within that group. (Please note, I am not using classes for this plugin, other than your own).

    function MetaBox()
    {
     $prefix = 'mmdlist';                               
     $cmb = new_cmb2_box( array(
    		'id'     => 'mmd_lists_ManualEntry',
    		'title'  => __( 'Google Lists - Card Records : Manual Input', 'cmb2' ),
    		'object_types'  => $prefix,                // Post type
    		'context'       => 'normal',
    		'priority'      => 'high',
    		'show_names'    => true,                   
    		) );
    
    $group_field_id = $cmb->add_field( array(
    	                'id'          => $prefix . '_' . 'Records',
    	                'type'        => 'group',
    	                'description' => __( 'Individual Directory Listings', 'cmb2' ),
    	                'options'              => array(
    		        'group_title'       => __( 'Record {#}', 'cmb2' ), 
    		        'add_button'        => __( 'Add Another Record', 'cmb2' ),
    		        'remove_button'     => __( 'Remove Record', 'cmb2' ),
    		        'sortable'          => true,
    	),
    ) );'
    $data = apply_filters( 'cmb2_override_meta_value', 
                           'cmb2_field_no_override_val', 
                           $group_field_id, 
                           array( 'id'=> $prefix . '_' . 'Records',
                                  'type' => 'group' ), 
                           'cmb2');
    }
    add_filter( 'cmb2_override_meta_value', 'FormFilterOverride', 10, 4 ); 

    function FormFilterOverride( $cmb2_field_no_override_val, $this_object_id, $a, $instance ) {
    // make filter magic happen here…
    return $cmb2_field_no_override_val;
    };`

    or this is applied to each field, one by one? The confusing point for me. Filters are a bit of a gray area for me. I could understand if the array in the group or individual fields had a callback function that would be referenced. Such as

    $cmb->add_group_field( $group_field_id, array(
    	               'name'         => $FieldDesc,
    	               'id'           => $prefix . $FieldId,
    	               'type'         => 'text',
    		      'on_front'     => false,
    		      'save_field'   => false,                               
    		      'attributes'   => array(									 
                          'required'    => $Field['required'],)								 
                          'default'      => 'Debbie',
    		      'value_cb'     => 'SetTextBox',      <---------- THIS
                          ) ); 

    That does not seem to be the case. But apply filters and then add_filter call and to who and where is the data, seems to be a disconnect. Again, forgive the nativity on this point.

    I need some working sample code showing the relationship between which fields are being overwritten and then how do I retrieve the field data so I can store to the the database.

    • This reply was modified 9 months, 1 week ago by dkurth.
    • This reply was modified 9 months, 1 week ago by dkurth.
    • This reply was modified 9 months, 1 week ago by dkurth.
    Plugin Author Michael Beckwith

    (@tw2113)

    The BenchPresser

    I must echo what @jtsternberg has said above, and those are some filters that i’ve used myself for projects/products. My example is that saving a metabox on a post actually didn’t save to post meta, and instead saved to an option in the options table. Alongside that, the value to display for the same post metabox was actually fetched from the same option. Allowed for storing in one place that got reflected in multiple areas that all saved to that same place.

    Worth checking out.

    Michael – I did this technique successfully on my own using custom post with metaboxes, however, I did not have the ability to delete fields and add fields without hitting the database. Caused a lag and I did not have the time to rewrite what you have done quite brilliantly at. Using a cache system. Your system was more elegant in this regard. I am using cmb2 instead, but need to control the same functionality by using my own table for the plugin.

    As a FYI, On a standard custom post metabox, you use a callback hook called ‘save_post’ to get an “Update” call and then you can do whatever you need to do with storage. It is always called with an UPDATE button …or any submit button for that matter.

    add_action( ‘save_post’, ‘Your Function’);

    I can not use the postmeta table, nor do I want the options table. These are membership records, not options or posts. Using postmeta as it has two dangers with that table. 1) if it becomes corrupted, all your data is gone. 2) I am adding thousands of records to a already heavily laid table. It is not performance effective for my application.

    I just need to know how to hook into the filters properly..the examples are confusing to me. It is not how “I think”.

    If you can give me a working sample showing, the proper use of the filter (I will admit I am not used to using filters..not my programming style), the retrieval from your cache and storage to your cache for effective display and retrieve of user entry, I will be good.

    • This reply was modified 9 months, 1 week ago by dkurth.
    Plugin Author Michael Beckwith

    (@tw2113)

    The BenchPresser

    Couple things with the last code paste above.

    You wouldn’t be instantiating your metaboxes on that cmb2_override_meta_value hook. The new_cmb2_box() and field setting still goes on the cmb2_admin_init hook.

    With regards to cmb2_override_meta_value, you hook into that, and you return anything but “cmb2_field_no_override_val” to the filter, and THAT value will get used. Where you get that data from, is up to you. You could hardcode a value, you could query a completely different database table, you could pull in a tweet if you wanted and return that. Whatever you want to return, would get used. If you simply have it return “cmb2_field_no_override_val” then it will continue on with the standard location fetching from post meta, if there’s even anything saved.

    Same thing is going to be true with the save override filter, cmb2_override_meta_save. The only real difference is that the filter defaults to null instead of cmb2_field_no_override_val. You’ll be passed the data that was put into the fields, and you can then process/save that data to wherever you want: custom database table, post a tweet with it, etc. If you return anything but null it’ll return whatever you return after saving. Say, you wanted to return true to indicate success somehow. If you return null, then it’ll save to the postmeta as well, whether you saved it elsewhere or not.

    Very much the same with the delete override, but I haven’t used that one much thus far. It’s going to be the same process though. You handle your own deletion. I won’t repeat my two novels above 😀

    For all cases, what you do with the data is really up to you, for saving/fetching/handling.

    Plugin Author Michael Beckwith

    (@tw2113)

    The BenchPresser

    Also, may just be me, and I’m not angry/upset/etc by it, but there does seem to be reply editing occurring which may or may not end up changing what my replies referred to. So if anyone is slightly confused by parts, that’s probably why.

    ok… hummm, I think there is an assumption that is confusing me. If I understand what you just said, you don’t have a giant array of values in which I would access the field such as:

    $Data = GetFieldValues()
    $Data[Group Card Set][field id] =”;

    From my brains point of view, each of those records are stored somewhere and I can either access that data directly via an array using a field by field and record set by record set method

    OR

    You have a set of function calls (filters) that return one or more fields based on the field. With repeatable fields, which field valued value belongs to which Record set??

    I am retrieving a entire table of records based on a list ID (custom post id). Each of the repeatable record set, a row of data is associated. This is repeated for all rows in the database as repeatable fields. How do I assign the right record to the right repeatable field location? Then the reverse, how do I access the data to store in the database.

    Remember I am a C++ programmer, so you have to return or get something physical or an array or a variable to access something. Trying to figure out how this that works. Which is why I wanted the sample code. The code I saw, it was generic not showing the specifics of the repeatable fields.

    Help me understand..

    Did not take that you were angry. No worries.

    I am just trying to understand the system, so that I can achieve the goal..and quickly. The forms are all up and display correctly. I just need to populate these fields with DB data and store the data from the fields. and then I will be done with this portion of the project.

    Perhaps this will help clarify my question:

    https://github.com/CMB2/CMB2-Snippet-Library/blob/master/filters-and-actions/override-cmb2-data-source.php

    In this sample, you are returning an array from the options table:

    `add_filter( ‘cmb2_override_yourprefix_group_alt_data_demo_meta_value’, ‘yourprefix_group_alt_data_demo_override_meta_value’, 10, 4 );
    function yourprefix_group_alt_data_demo_override_meta_value( $data, $object_id, $args, $field ) {
    return get_option( ‘yourprefix_group_alt_data_demo’, array() );
    }

    What the the format of the array returned by get_option? (second parameter) Does it match the field names of the form. It is like:

    $Data = get_option( ‘yourprefix_group_alt_data_demo’, array());
    $Data[‘field name]
    or
    $Data[record set][field name]

    What is the format of the array data you expect to be returned to the system?

    Plugin Author Michael Beckwith

    (@tw2113)

    The BenchPresser

    the 2nd parameter of get_option() is a default value if there’s nothing found in the options table. So that line is basically saying “if there’s a saved value, return that, otherwise, return an empty array”

    There probably will be a little bit of matching up of structure. I think I’d end up doing a standard location save of data, to see how it’s structured in the end, for example if it’s an array of arrays, what keys are set up, etc. Then adjust my return/data getting to match up with that. The saving would probably be minor reversal of that. Accept what is passed in to the saving callback, and extract out as needed to save to appropriate fields.

    Sadly I personally don’t have any examples of this handy where it’s dealing with anywhere except the options table or meta tables.

    No problem. I can figure it out, with your help and give you some code for others, when it works. I do have the filters working and they appear to be called for every field. But when I attempt to see what field, via the $field parameter, it does not print out (using debug logs).

    Can you tell me what the parameter definition are (or a link to where they are defined) AND what is the return data structure expected?

    dkurth

    (@dkurth)

    I found this:

    https://gist.github.com/tharsheblows/6ea6f0dda3db8df57563d2d169e4dbb7#file-custom-tables-cmb2-php-L41

    and it explains a method that appears to work and it does function, since I tried it.
    There is also this post,
    https://github.com/CMB2/CMB2/issues/728
    that you responded to, a couple years back. Same technique.

    There is a but…..

    Whether this method or the cmb2_override_meta_value method, the associated call back get called for the total number of fields in the group, plus 1.
    Should it not be called only once since it is for the group. Or am I missing something?

    dkurth

    (@dkurth)

    Ok, figured it all out. I still have some other questions on the select and checkbox field front, but here is how saving to your own table and data works. I write it here for others to not have to spend Sunday afternoon, in front of a computer!

    Setting up the groups and the fields is well documented. I wont’ review that. But in terms of the callback, the online docs make it a bit over complicated. Here is the simplified version. 1.) You do not need to put the metagroup name in the function call or the callback type. Direct works just fine for storing fields and retrieving them. The only downside to this call, is that it is called repeatedly for the number of individual fields you have, plus 1. Why I do not know, but I put a flag in that is cleared by the redraw override and that solved the problem..although ungracefully.

    add_filter('cmb2_override_meta_value', 'YourFunction', 10, 4);
    function mmd_get_methods_custom_data( $dont_override, $object_id, $args, $cmb2_field_object )
      {
       // $dont_override = Just a feed back informational
       // $object_id = Same thing as the PostId
       // $args = Giant list of all the settings for the entire form data. Use results = print_r($args, true); and dump the results to a debuglog to see all the forms.
      // $cmb2_field_object = Name of your Group. Same as the Group Id
    
       // To set your data is a multidem array, where each record set (repeatable group) is 
       // an index into the array.  The total number of individual record sets you input, 
       // will be the number of repeatable field groups that will appear on the screen.
    
    $Records = array();
    $Record[0] =  array( 'fieldname1' => 'Your String Value here',
    	              'fieldname2' => 'Your String Value here',
    		      'fieldname3' => 'Your String Value here',
    		      'fieldname4'=> 'Your String Value here' );
    
    $Record[1] =  array( 'fieldname1' => 'Your String Value here2',
    	              'fieldname2' => 'Your String Value here2',
    		      'fieldname3' => 'Your String Value here2',
    		      'fieldname4'=> 'Your String Value here2' );
    $Data[] = $Record[0];
    $Data[] = $Record[1];
    
    return $Records;           // <---------- this sends it to the system.
    }
    
    //-----------------------------
    // this function overides the system to storing it into your postmeta table
    // Again, not necessary to put your metabox group name in the filter call or function
    //-------------------------------------------
    add_filter('cmb2_override_meta_save', 'save_custom_data', 10, 2);
    add_filter('cmb2_override_meta_remove', 'save_custom_data', 10, 2);
    function save_custom_data($data, $values)
    {
    // the only field you care about is $values Here is the format
    //    [type] => post
    //    [id] => <Your Post ID>
    //    [field_id] => <The Name of your Group >
    //    [repeat] => 1
    //    [single] => 1
    //    [value] => Array
    //        (
    //            [0] => Array
    //                (
    //                    [fieldname1] => 'The value in field1'
    //                    [fieldname2] => The value in field2
    //                )
    //        )
    //You can access this as follows:
    
    $Data        = $values['value'];
    $Field1Value = $Data[0]['fieldname1'];
    $Field1Value = $Data[1]['fieldname1'];
     }
    
    

    I would put all the usual prevention around to make sure the field does exist, such as if (!array_key_exists(‘value’, $values)). But you get the idea. Simple, once you know the format of the system.

Viewing 15 replies - 1 through 15 (of 24 total)
  • The topic ‘Set Field values from database with add_group_field’ is closed to new replies.