Title: Custom database table
Last modified: August 30, 2016

---

# Custom database table

 *  Resolved [calello](https://wordpress.org/support/users/calello/)
 * (@calello)
 * [10 years, 9 months ago](https://wordpress.org/support/topic/custom-database-table/)
 * Hi to everyone,
    thank you so much for the work on this plugin.
 * Is it possible to save all the fields of a CMB2 metabox into a new custom table
   in WP database instead of _prefix\__postmeta?
 * Thank you in advance for the help!
 * [https://wordpress.org/plugins/cmb2/](https://wordpress.org/plugins/cmb2/)

Viewing 8 replies - 1 through 8 (of 8 total)

 *  Plugin Contributor [Michael Beckwith](https://wordpress.org/support/users/tw2113/)
 * (@tw2113)
 * The BenchPresser
 * [10 years, 9 months ago](https://wordpress.org/support/topic/custom-database-table/#post-6498969)
 * If it is, it’s something we haven’t tried to implement at all, since meta box
   values are generally intended to be saved as post meta, and using the prefix_postmeta
   table makes all of the data accessible to the WP core API without any hassle.
   The closest that we come to something besides prefix_postmeta/prefix_usermeta
   would be the options table.
 *  [mooberrydreams](https://wordpress.org/support/users/mooberrydreams/)
 * (@mooberrydreams)
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499198)
 * (I realize this is an old question, but putting my response here in case someone
   else finds it looking for the same info.)
 * I have done this by using the `cmb2_override_meta_save`, `cmb2_override_meta_remove`,`
   cmb2_override_meta_value` filters to override the getting/setting of the values.
 * The issue I’m having (and how I stumbled upon this old question) is that filter
   is called for each individual field rather than once for the custom post type.
   So it’s a lot of database calls that could be done in a single SELECT or UPDATE/
   INSERT call.
 * Sometimes the postmeta table isn’t the best place to store custom post type data.
   A single row for each post’s data instead of a row for every piece of data makes
   querying much more efficient if you need to do something other than just display
   the post type’s content.
 *  Plugin Author [Justin Sternberg](https://wordpress.org/support/users/jtsternberg/)
 * (@jtsternberg)
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499199)
 * If you wanted to do the reads/writes/deletes with one SELECT/UPDATE/INSERT/DELETE,
   you could certainly do it. Without out getting into the nitty-gritty, Take a 
   look at the network-theme-options example, as it’s doing something very similar:
   [https://github.com/WebDevStudios/CMB2-Snippet-Library/blob/master/options-and-settings-pages/network-options-cmb.php](https://github.com/WebDevStudios/CMB2-Snippet-Library/blob/master/options-and-settings-pages/network-options-cmb.php)
 *  [mooberrydreams](https://wordpress.org/support/users/mooberrydreams/)
 * (@mooberrydreams)
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499200)
 * Thanks! I’ll have to look through that code deeper. I thought the options were
   saved in a single database transaction because they were stored as a single column
   of serialized data via something WP was doing.
 *  [mooberrydreams](https://wordpress.org/support/users/mooberrydreams/)
 * (@mooberrydreams)
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499201)
 * Ah! I think the `cmb2_save_{$object_type}_fields` hook is what I need.
 *  Plugin Contributor [Michael Beckwith](https://wordpress.org/support/users/tw2113/)
 * (@tw2113)
 * The BenchPresser
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499202)
 * Some field types get saved as serialized data, but not all of them, if I recall
   right.
 *  [mooberrydreams](https://wordpress.org/support/users/mooberrydreams/)
 * (@mooberrydreams)
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499203)
 * Okay I have this working (without multiple database calls). Here’s is some pseudocode
   of how I did it:
 * Because my plugin is currently not written with classes, I used a global variable.
   A class variable would probably be better.
 * For the retrieval of the data, I didn’t change anything, because on the first
   call to the database, the results are cached so each subsequent field just pulls
   from the cache.
 * For the saving of the data, I did it in two steps.
 * The first step saves the updated data to the global variable on CMB2’s override
   hook in an array of ( post_meta_field_id => value ). Some of my fields are saved
   in a custom table, and some are saved using WordPress’ tables via CMB2 (mainly,
   repeated groups). So I have a check for if the field is part of the custom table
   or not.
 * The 2nd step is triggered through WP’s save_post hook to actually save to the
   database, from the global variable I created.
 *     ```
       add_filter('cmb2_override_meta_remove', 'your_save_meta_data_function', 10, 2);
        add_filter('cmb2_override_meta_save', 'your_save_meta_data_function', 10, 2);
        function your_save_meta_data_function( $override, $a ) {
       // if not the right post type, return what we got in
       	if ( get_post_type() != 'your_post_type' ) {
       		return $override;
       	}
   
       	// v3.1 by adding meta_remove filter, now this is sometimes called without the value element
       	// add the element as blank text
       	// this is necessary (vs just exiting the function) because otherwise if a field is left blank
       	// it won't get saved as such without the meta_remove filter
       	if (!array_key_exists('value', $a)) {
       		$a['value'] = null;
       	}
   
               // if not a field for the custom table, just return
               // what we got in and let CMB2 handle saving it.
       	global $mbdb_edit_book;
       	if ( in_custom_table( $a['field_id'] ) ) {
       		$mbdb_edit_book[$a['field_id']] = $a['value'];
       		return 'override';
       	} else {
       		return $override;
       	}
       }
   
       // set priority to 20 to ensure it runs after CMB2's hook
       add_action('save_post', 'you_save_custom_table_function', 20);
       function you_save_custom_table_function( $post_id ) {
       	if (!get_post_type() == 'your_post_type') {
       		return;
       	}
   
       	// save custom database fields to database
       	global $mbdb_edit_book;
   
               // this translates post meta field ids to column names,
               // sanitizes the data, and ultimately calls wpdb->update or insert
       	save_custom_post( $mbdb_edit_book, $post_id );
   
       }
       ```
   
 *  Plugin Contributor [Michael Beckwith](https://wordpress.org/support/users/tw2113/)
 * (@tw2113)
 * The BenchPresser
 * [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499204)
 * Cool

Viewing 8 replies - 1 through 8 (of 8 total)

The topic ‘Custom database table’ is closed to new replies.

 * ![](https://ps.w.org/cmb2/assets/icon.svg?rev=2866672)
 * [CMB2](https://wordpress.org/plugins/cmb2/)
 * [Frequently Asked Questions](https://wordpress.org/plugins/cmb2/#faq)
 * [Support Threads](https://wordpress.org/support/plugin/cmb2/)
 * [Active Topics](https://wordpress.org/support/plugin/cmb2/active/)
 * [Unresolved Topics](https://wordpress.org/support/plugin/cmb2/unresolved/)
 * [Reviews](https://wordpress.org/support/plugin/cmb2/reviews/)

## Tags

 * [database](https://wordpress.org/support/topic-tag/database/)

 * 8 replies
 * 4 participants
 * Last reply from: [Michael Beckwith](https://wordpress.org/support/users/tw2113/)
 * Last activity: [10 years, 1 month ago](https://wordpress.org/support/topic/custom-database-table/#post-6499204)
 * Status: resolved