has_been_started !== false) return; //Output metaboxes before the main editor add_action( 'edit_form_after_title', array($this ,'early_metaboxes')); //Output normal metaboxes add_action( 'add_meta_boxes', array($this ,'wp_add_custom_metabox' )); //Make sure we save the values add_action( 'save_post', array($this ,'save_data' )); //Make sure we can use the colorpicker. It's the admin interface, who cares about optimizing non-loading of this..? add_action( 'admin_enqueue_scripts', array($this ,'include_colorpicker')); //Make sure we do not repeat these actions $this->has_been_started = true; } /* --------------------------------------------------------------------------- FILTERS ------------------------------------------------------------------------------ */ //Give some array with settings, and the post to verify. Will run all checks! private function check_if_filters_approve($params, $post){ $post_id = $post->ID; $post_type = $post->post_type; //Wordpress adds a metabox per post type. Only add metabox if current post type is correct $post_type_matches = $this->filter_post_type($params, $post_type); if(!$post_type_matches){ return false; //Abort, Wrong post type } //Check if post id matches $post_id_matches = $this->filter_post_id($params, $post_id); if(!$post_id_matches){ return false; //Abort, Wrong post id } //Check if post special filter matches $post_special_matches = $this->filter_post_special($params, $post_id); if(!$post_special_matches){ return false; //Abort, Wrong special params } //Nothing wrong, all is actually OK! :) return true; } /* special filters - conversion to normal stuff 'frontpage' => page id, if set 'blogpage' => page id, if set */ private function specials_to_post_ids($array_of_specials){ //Abort early if nothing to iterate if(!$array_of_specials || $array_of_specials === 'all'){return $array_of_specials;} $converted_specials = array(); foreach($array_of_specials as $special){ if($special === 'frontpage'){ $frontpage_id = $this->get_frontpage_id(); if($frontpage_id){ $converted_specials[] = $frontpage_id; } }else if($special === 'blogpage'){ $blogpage_id = $this->get_blogpage_id(); if($blogpage_id){ $converted_specials[] = $blogpage_id; } } } return $converted_specials; } /* Give params and desired post type to verify */ private function filter_post_type($params, $current_post_type){ $target_post_types = isset($params['post_type__in']) ? $params['post_type__in'] : $this->default_post_types; $avoid_post_types = isset($params['post_type__not_in']) ? $params['post_type__not_in'] : array(); $target_post_type_matches = in_array($current_post_type, $target_post_types); $avoid_post_type_matches = ($avoid_post_types && in_array($current_post_type, $avoid_post_types)); $can_show = ($target_post_type_matches && !$avoid_post_type_matches); return $can_show; } /* Give params and desired post id to verify */ private function filter_post_id($params, $current_post_id){ $target_post_ids = isset($params['post_id__in']) ? $params['post_id__in'] : 'all'; $avoid_post_ids = isset($params['post_id__not_in']) ? $params['post_id__not_in'] : array(); //Gather some flags $target_all = ($target_post_ids === 'all'); $target_post_id_matches = ($target_all || in_array($current_post_id, $target_post_ids)); $avoid_post_id_matches = ($avoid_post_ids && in_array($current_post_id, $avoid_post_ids)); //Figure out if we need to return false $can_show = ($target_post_id_matches && !$avoid_post_id_matches); return $can_show; } /* Give params and desired post id to verify against special params */ private function filter_post_special($params, $current_post_id){ $target_specials = isset($params['special__in']) ? $params['special__in'] : 'all'; $avoid_specials = isset($params['special__not_in']) ? $params['special__not_in'] : array(); //Convert specials into something useable $target_specials = $this->specials_to_post_ids($target_specials); $avoid_specials = $this->specials_to_post_ids($avoid_specials); //Gather some flags $target_all = ($target_specials === 'all'); $target_special_matches = ($target_all || in_array($current_post_id, $target_specials)); $avoid_special_matches = ($avoid_specials && in_array($current_post_id, $avoid_specials)); //Figure out if we need to return false $can_show = ($target_special_matches && !$avoid_special_matches); return $can_show; } /* --------------------------------------------------------------------------- METABOX ------------------------------------------------------------------------------ */ /**** Prepare a new metabox */ public function add_metabox($metabox_id, $title_or_params = array()){ $this->enable_metaboxes(); //Enable if not already enabled /* Prepare the metabox ID */ $prefix = $this->name_prefix; $prefixed_metabox_id = $prefix.$metabox_id; /* Prepare title and parameters. Note: Title can be part of params. */ if(is_string($title_or_params)){ $params = array(); //Default to no params $title = $title_or_params; }else if(is_array($title_or_params)){ $params = $title_or_params; $title = isset($params['title']) ? $params['title'] : 'Custom Fields'; } /* The title */ $params['title'] = $title; /* Filter by post types? */ $params['post_type__in'] = isset($params['post_type__in']) ? $params['post_type__in'] : $this->default_post_types; /* Context? */ $params['context'] = isset($params['context']) ? $params['context'] : 'normal'; /* Priority? */ $params['priority'] = isset($params['priority']) ? $params['priority'] : 'default'; /* Custom - Is early? */ $params['early'] = (isset($params['early']) && $params['early']) ? true : false; /* Custom - Is early? */ $params['style'] = (isset($params['style']) && $params['style']) ? $params['style'] : false; /* reserve a space for the metabox fields */ $params['fields'] = array(); /* Prepare for possible override */ if(isset($this->metaboxes[$metabox_id])){ //Box exists. Keep fields $existing_metabox_fields = $this->metaboxes[$metabox_id]['fields']; }else{$existing_metabox_fields = false;} /* Remember this metabox for later - This is the main shizzle in this fuzzle */ $this->metaboxes[$metabox_id] = $params; $this->metaboxes_order[] = $metabox_id; /* reinsert previously existing fields, if any */ if($existing_metabox_fields){ $this->metaboxes[$metabox_id]['fields'] = $existing_metabox_fields; } } /* This function makes wordpress happy, knowing what metaboxes to display and where. * This is run automatically from some hooks */ public function wp_add_custom_metabox(){ $output_function = array($this ,'wp_metabox_output'); $prefix = $this->name_prefix; //This might be useful global $post; $current_post = $post; $current_post_id = $post->ID; $current_post_type = $post->post_type; //Respect the order they were added foreach($this->metaboxes_order as $metabox_id){ // The metabox id, prefixed edition $prefixed_metabox_id = $prefix.$metabox_id; //Get the metabox - Shorter vars $metabox = $this->metaboxes[$metabox_id]; $metabox_fields = $metabox['fields']; //Wait, do we output early boxes here? No! $is_early = $metabox['early']; if($is_early){ continue; //There is another function for outputting these } //optional filters include post id, post type and some specials $filters_are_ok_with_this = $this->check_if_filters_approve($metabox, $current_post); if(!$filters_are_ok_with_this){ continue; //Skip this metabox } //Normal wordpress custom fields $title = $metabox['title']; $context = $metabox['context']; $priority = $metabox['priority']; $has_fields = strlen($this->get_metabox_output($metabox_id, true))>0; if(!$has_fields){ continue; //Not suitable for output here.. } //Should be ok! add_meta_box($prefixed_metabox_id, $title, $output_function, $current_post_type, $context, $priority); } } public function early_metaboxes($post){ $prefix = $this->name_prefix; $post_id = $post->ID; //Respect the order they were added foreach($this->metaboxes_order as $metabox_id){ // The metabox id, prefixed edition $prefixed_metabox_id = $prefix.$metabox_id; //Get the metabox - Shorter vars $metabox = $this->metaboxes[$metabox_id]; $metabox_fields = $metabox['fields']; $metabox_title = $metabox['title']; //Wait, do we output NON-early boxes here? No! $is_early = $metabox['early']; if(!$is_early){ continue; //There is another function for outputting these } //optional filters include post id, post type and some specials $filters_are_ok_with_this = $this->check_if_filters_approve($metabox, $post); if(!$filters_are_ok_with_this){ continue; //Skip this metabox } //Fake a metabox echo '
'; } } /**/ public function wp_metabox_output($post, $wp_metabox_params){ $prefix = $this->name_prefix; $prefixed_metabox_id = $wp_metabox_params['id']; $metabox_id = str_replace($prefix, '', $prefixed_metabox_id); echo $this->get_metabox_output($metabox_id); } /* All added custom fields are iterated and outputteded in this function */ public function get_metabox_output($metabox_id, $force_recreate =false){ $has_cache = isset($this->metaboxes_output[$metabox_id]); if(!$force_recreate && $has_cache){ //We got cache, and we return it! return $this->metaboxes_output[$metabox_id]; } $metabox_output = ''; $fields_output = array(); $prefix = $this->name_prefix; $metabox = $this->metaboxes[$metabox_id]; $metabox_fields = $metabox['fields']; foreach($metabox_fields as $field){ $_output = $this->get_metabox_field($field); if($_output){ $fields_output[] = $_output; } } //Did we get anything yet? $has_fields_output = (count($fields_output) > 0); if(!$has_fields_output){ //Remember that we found nothing $this->metaboxes_output[$metabox_id] = ''; return ''; //NOTHING! } //Include box-styles from style-param $metabox_style = $metabox['style']; if($metabox_style){ $style_output = str_replace('##', '#'.$prefix.$metabox_id, $metabox_style); $fields_output[] = ''; } //create output $metabox_output = ''; //Remember that we got output $this->metaboxes_output[$metabox_id] = $metabox_output; return $metabox_output; } /* --------------------------------------------------------------------------- FIELDS ------------------------------------------------------------------------------ */ /* Check filters and return a single metabox field output. Empty output if N/A because of anything */ private function get_metabox_field($field){ //These might be useful global $post; $current_post_id = $post->ID; $current_post_type = $post->post_type; //do the filters find anything wrong with this field? $filters_are_ok_with_this = $this->check_if_filters_approve($field, $post); if(!$filters_are_ok_with_this){ return ''; //Some filter was disappointed. Some might call it upset, or angry even. I call it filled with hate and revenge, and thus this field will never see the light of day. Not this way, atleast. But glory for those who wait, another day comes, another pageview or post type. Such is the life of the custom fields in this glorious world of Evolution. } //If code reaches here, then go ahead and create output $prefix = $this->name_prefix; $prefixed_fieldname = $prefix.$field['name']; $current_value = get_post_meta($current_post_id, $prefixed_fieldname, true); $output = $this->get_field($field, $current_value); //Done! return $output; } public function add_metabox_field($metabox_id, $field_params){ $prefix = $this->name_prefix; if(!isset($this->metaboxes[$metabox_id])){ //Create a metabox? $this->add_metabox($metabox_id); } $this->metaboxes[$metabox_id]['fields'][] = $field_params; } /* --------------------------------------------------------------------------- GETTERS SETTERS - FIELD VALUES ------------------------------------------------------------------------------ */ private function get_frontpage_id(){ if(!isset($this->frontpage_id)){ $this->frontpage_id = get_option('page_on_front'); } return $this->frontpage_id; } private function get_blogpage_id(){ if(!isset($this->blogpage_id)){ $this->blogpage_id = get_option('page_for_posts'); } return $this->blogpage_id; } /* if any default value, return something !== false */ public function get_default_value($post_id, $fieldname_raw){ foreach((array) $this->metaboxes as $metaboxid => $metabox){ foreach($metabox['fields'] as $k => $field){ if(isset($field['default'])){ return $field['default']; } } } return false; } /* Helper function, save field by given name */ private function savemeta($metatag){ global $post_id; if(!isset($_POST[$metatag])) return; //Wordpress will not save falsy values... if($_POST[$metatag] === ''){ $_POST[$metatag] = '__EMPTY_STRING__'; }else if(is_numeric($_POST[$metatag]) && $_POST[$metatag] == 0){ $_POST[$metatag] = '__ZERO_INT__'; } update_post_meta( $post_id, $metatag, $_POST[$metatag] ); } private function saveable($field){ return !in_array($field['type'], $this->unsaveables); } /** * Save all options, but only if saving is supposed to happen. * This function runs automatically when it should, and must remain public for Wordpress to understand how to run it. * Do not use manually. */ public function save_data($post_id){ $prefix = $this->name_prefix; $post = get_post($post_id); foreach((array) $this->metaboxes as $metaboxid => $metabox){ //This post may not be big enough for the both of us. $filters_are_ok_with_this = $this->check_if_filters_approve($metabox, $post); if(!$filters_are_ok_with_this){ continue; //Leave town } //I like your attitude, now save your fields and get out of here foreach($metabox['fields'] as $k => $field){ if(!$this->saveable($field)){ continue; //You're not supposed to be here kid, now get lost } $filters_are_ok_with_this = $this->check_if_filters_approve($field, $post); if(!$filters_are_ok_with_this){ continue; //This one looks funny. Get out of here. } //Here, take a cookie. I promise, by the time you're done eating it, you'll feel right as rain. $this->savemeta($prefix.$field['name']); } } } /* This function makes the sircon meta prefix abstracted. * Param1 should be post id or array containing postid and name. * Param2 should be the name of the field you want, if param1 is just a post id */ public function get_post_meta($param1, $param2=false){ if(is_numeric($param1)){ $post_id = $param1; $fieldname = $param2; }else{ $post_id = get_the_ID(); $fieldname = $param1; } $prefix = $this->name_prefix; $prefixed_fieldname = $prefix.$fieldname; $value = get_post_meta($post_id, $prefixed_fieldname, true); if(!$value){ //figure out default value, if any.. $value = $this->get_default_value($post_id, $fieldname); } //Wordpress will not save falsy values, so they are converted upon saving. This is the re-conversion if($value === '__EMPTY_STRING__'){ $value = ''; }else if($value === '__ZERO_INT__'){ $value = 0; } if(!is_admin()){ $value = do_shortcode($value); } return $value; } /* This function makes the sircon meta prefix abstracted. * Param1 should be post id. * Param2 should be boolean true if you want some non-informative or utilitary fields */ public function get_post_metas($post_id = false){ if(!$post_id){ $post_id = get_the_ID(); } $return_fields = array(); $post = get_post($post_id); foreach((array) $this->metaboxes as $metaboxid => $metabox){ //We only get what's coming to us $filters_are_ok_with_this = $this->check_if_filters_approve($metabox, $post); if(!$filters_are_ok_with_this){ continue; //not coming } //Who else are invited? foreach($metabox['fields'] as $k => $field){ if(!$this->saveable($field)){ continue; //Not you } $filters_are_ok_with_this = $this->check_if_filters_approve($field, $post); if(!$filters_are_ok_with_this){ continue; //Especially not you! } //Welcome! $value = $this->get_post_meta($post_id, $fieldname); if(!is_admin()){ $value = do_shortcode($value); } $return_fields[$field['name']] = $value; } } return $return_fields; } /** ##--- UTILITY FUNCTIONS ---## **/ } /* Highly related functions and procedures */ global $Sircontheme_Custom_Postdata_obj; $Sircontheme_Custom_Postdata_obj = new Sircontheme_Custom_Postdata(); //Returns the global object for this class function get_sircontheme_postdata_object(){ global $Sircontheme_Custom_Postdata_obj; return $Sircontheme_Custom_Postdata_obj; } function add_sircontheme_postbox($id, $params){ $Postdata = get_sircontheme_postdata_object(); $Postdata->add_metabox($id, $params); } /* Function-style add postdata box * example usage in top of this file */ function add_sircontheme_postdata($postbox_id, $field_data){ $Postdata = get_sircontheme_postdata_object(); $Postdata->add_metabox_field($postbox_id, $field_data); } /* Retrieve post data. Param 1 can be data-idstring or postid. param2 must be data-idstring if param 1 is postid */ function get_sircontheme_postdata($param1, $param2 = false){ $Postdata = get_sircontheme_postdata_object(); return $Postdata->get_post_meta($param1, $param2); } /* Retrieve all post data, every field. Param 1 can be data-idstring or postid. param2 must be data-idstring if param 1 is postid */ function get_sircontheme_postdatas($pid = false){ $Postdata = get_sircontheme_postdata_object(); return $Postdata->get_post_metas($pid); } function get_sircontheme_imgurl($img_id, $img_size = 'large'){ $thumb_url = wp_get_attachment_image_src($img_id, $img_size, true); if(is_array($thumb_url)) $thumb_url = $thumb_url[0]; return $thumb_url; } /* Retrieve post data of type IMAGE, fetch the url instead of the image id. */ function get_sircontheme_postdata_url($post_id, $dataname, $img_size = 'large'){ $img_id = get_sircontheme_postdata($post_id, $dataname); if(!$img_id) return false; $thumb_url = get_sircontheme_imgurl($img_id, $img_size); return $thumb_url; } /* SETTINGS FOR CPT, Example code: array('post','page'), 'fields'=>array( array( 'type'=>'text', 'name'=>'sometest' ), array( 'type'=>'image', 'label'=>'Select an image: ', 'name'=>'wowimage' ) ) )); //Get saved settings: $saved_page_value = get_sircontheme_cpt_setting('page', 'sometest'); $saved_post_value = get_sircontheme_cpt_setting('post', 'sometest'); /**/