-
-
Save bronwynv/4481cd9e091b145a94c62e4424b593aa to your computer and use it in GitHub Desktop.
This is set of helper classes to create and manage custom post types for WordPress. It gets added to a theme's logic folder, or libs or includes folders, and included in functions.php. Then the primary tracker class is initiated once, and used to create new CTPs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/***********************************************************************/ | |
/*************************** TRACKER CLASS ***************************/ | |
/***********************************************************************/ | |
class Custom_Post_Types_Manager { | |
public $ctp_slugs; | |
public $prefix; | |
function __construct($init_data) { | |
$this->prefix = $init_data['prefix']; | |
$this->ctp_slugs = array(); | |
} | |
public function setup_ctp($ctp_options) { | |
$ctp_options['prefix'] = $this->prefix; | |
$ctp = new Custom_Post_Type($ctp_options); | |
array_push( $this->ctp_slugs, $ctp->full_slug() ); | |
} | |
public function get_slugs() { | |
return $this->ctp_slugs; | |
} | |
} | |
/***********************************************************************/ | |
/*********************** INDIVIDUAL CTP CLASS ************************/ | |
/***********************************************************************/ | |
class Custom_Post_Type { | |
public $prefix; | |
public $slug; | |
public $supports; | |
public $icon; | |
public $metaboxes; | |
public $metadata; | |
function __construct($init_data) { | |
$this->prefix = $init_data['prefix']; | |
$this->slug = $init_data['slug']; | |
$this->taxonomy_slug = $init_data['taxonomy_slug']; | |
$this->supports = array_key_exists('supports', $init_data) ? $init_data['supports'] : array( 'title', 'editor' ); | |
$this->icon = $init_data['icon']; | |
$this->metaboxes = $init_data['metaboxes']; | |
$this->metadata = $init_data['metadata']; | |
$this->display_page = $init_data['display_page']; | |
$this->hierarchical = array_key_exists('hierarchical', $init_data) ? $init_data['hierarchical'] : false; | |
add_action( 'init', array( $this, 'create_ctp' ) ); | |
add_action( 'admin_head', array( $this, 'create_ctp_icons' ) ); | |
add_action( 'save_post', array( $this, 'save_ctp_custom_metadata' ), 1, 2 ); | |
add_action( 'rest_api_init', array( $this, 'expose_metadata_via_restapi' ) ); | |
} | |
public function full_slug() { | |
return strtolower($this->prefix.'_'.$this->slug); | |
} | |
public function create_ctp() { | |
$post_type_slug = strtolower($this->prefix.'_'.$this->slug); | |
$post_label = ucfirst( $this->slug ); | |
if ( $this->taxonomy_slug ) { | |
$taxonomy_slug = $post_type_slug.'_'.$this->taxonomy_slug; | |
$taxonomy_label = ucwords( str_replace( '_', ' ', $this->taxonomy_slug ) ); | |
} else { | |
$taxonomy_slug = $post_type_slug.'_type'; | |
$taxonomy_label = $post_label.' Type'; | |
} | |
$display_page = $this->display_page; | |
register_taxonomy($taxonomy_slug, $post_type_slug, | |
array( | |
'labels' => array( | |
'name' => $taxonomy_label, | |
'add_new_item' => 'Add New '.$taxonomy_label | |
), | |
'public' => true, | |
'show_ui' => true, | |
'show_tagcloud' => true, | |
'hierarchical' => true, | |
'show_in_nav_menus' => true, | |
'show_admin_column' => true, | |
'rewrite' => array( 'slug' => $display_page, 'with_front' => false ), | |
) | |
); | |
register_post_type($post_type_slug, | |
array( | |
'labels' => array( | |
'name' => $post_label.'s', | |
'singular_name' => $post_label, | |
'all_items' => $post_label.' '.__( 'List' ), | |
'add_new' => 'Add New'.' '.$post_label, | |
'add_new_item' => 'Add New'.' '.$post_label, | |
'edit_item' => 'Edit'.' '.$post_label, | |
'new_item' => 'New'.' '.$post_label, | |
'view_item' => 'View'.' '.$post_label, | |
'search_items' => 'Search', | |
), | |
'hierarchical' => $this->hierarchical, | |
'public' => true, | |
'show_in_rest' => true, | |
'has_archive' => true, | |
'rewrite' => array( 'slug' => $display_page,'with_front' => false ), | |
'supports' => $this->supports, | |
'register_meta_box_cb' => array( $this, 'create_ctp_custom_metaboxes' ), | |
'taxonomies' => array( $taxonomy_slug ), | |
) | |
); | |
} | |
function create_ctp_custom_metaboxes( $post ) { | |
$post_type_slug = get_post_type($post); | |
if ( $this->metaboxes != null ) { | |
foreach ($this->metaboxes as $metabox) { | |
$metabox_id = $post_type_slug.'_metabox_'.$metabox['slug']; | |
$metabox_label = $metabox['label']; | |
$metabox_callback = array( $this, 'create_ctp_custom_metadata' ); | |
$metabox_screen = $post_type_slug; | |
$metabox_content = $metabox['position']; | |
$metabox_priority = 'default'; | |
$metabox_callback_args = array( $metabox['metadata'], $post_type_slug ); | |
add_meta_box($metabox_id, $metabox_label, $metabox_callback, $metabox_screen, $metabox_content, $metabox_priority, $metabox_callback_args ); | |
} | |
} | |
} | |
function create_ctp_custom_metadata($post, $data) { | |
global $admin_colors; | |
$metadata = $data['args'][0]; | |
$post_type_slug = $data['args'][1]; | |
$html = ''; | |
foreach ( $metadata as $metadatum ) { | |
register_meta( $post_type_slug, $metadatum_id, array( | |
'single' => true, | |
'show_in_rest' => true | |
)); | |
$html .= '<div class="metadata-wrap">'; | |
$metadatum_type = $metadatum['type']; | |
$metadatum_label = $metadatum['label']; | |
$metadatum_desc = $metadatum['desc']; | |
$metadatum_id = $post_type_slug.'_metadata_'.$metadatum['slug']; | |
$metadatum_default = $metadatum['default'] ? $metadatum['default'] : ''; | |
$metadatum_value = get_post_meta($post->ID, $metadatum_id, true); | |
$metadatum_value = $metadatum_value ? $metadatum_value : $metadatum_default; | |
$metadatum_options = $metadatum['options'] ? $metadatum['options'] : null; | |
switch ( $metadatum_type ) { | |
case 'hidden' : | |
$html .= '<input type="hidden" name="' . $metadatum_id .'" id="' . $metadatum_id .'" value="' . $metadatum_value . '" class="widefat" />'; | |
break; | |
case 'select' : | |
$html .= '<label class="metadata-label" for="' . $metadatum_id . '">' . $metadatum_label .'</label>'; | |
$html .= '<div class="metadata-desc">' . $metadatum_desc .'</div>'; | |
$html .= '<select name="' . $metadatum_id .'" id="' . $metadatum_id .'" class="widefat">'; | |
foreach ( $metadatum_options as $metadatum_option_label => $metadatum_option_value ) { | |
$html .= '<option' . ( $metadatum_option_value == $metadatum_value ? ' selected="selected"' : '' ) . ' value="' . $metadatum_option_value . '">' . $metadatum_option_label . '</option>'; | |
} | |
$html .= '</select>'; | |
break; | |
case 'textarea' : | |
$html .= '<label class="metadata-label" for="' . $metadatum_id . '">' . $metadatum_label .'</label>'; | |
$html .= '<div class="metadata-desc">' . $metadatum_desc .'</div>'; | |
$html .= '<textarea name="' . $metadatum_id .'" id="' . $metadatum_id .'" class="widefat">' . $metadatum_value . '</textarea>'; | |
break; | |
case 'textarea_googlemappolygon' : | |
$html .= '<label class="metadata-label" for="' . $metadatum_id . '">' . $metadatum_label .'</label>'; | |
$html .= '<div class="metadata-desc">' . $metadatum_desc .'</div>'; | |
$html .= '<div id="map-wrap" style="max-height:400px;height:80vw;margin-bottom:10px"></div>'; | |
$html .= '<label class="metadata-label" for="' . $metadatum_id . '">Encoded Polygon (Creates the Above Preview)</label>'; | |
$html .= '<textarea style="min-height:200px;" name="' . $metadatum_id . '" id="' . $metadatum_id . '" class="widefat">' . $metadatum_value . '</textarea>'; | |
$html .= ' | |
<script> | |
(function(window, Mapstractor) { | |
window.setTimeout(function(){ | |
// Grab Input Elements that Control the Map | |
var encodedCoordinatesElement = document.getElementById(\'' . $metadatum_id . '\'); | |
var colorElement = document.getElementById(\'' . str_replace('shape', 'color', $metadatum_id) . '\'); | |
var polygon = null; | |
// Setup Map | |
var map = new Mapstractor({ | |
mapWrapID: \'map-wrap\', | |
mapOptions: { | |
center: { | |
lat: 40, | |
lng: -95 | |
}, | |
zoom: 4, | |
minZoom: 3, | |
maxZoom: 9, | |
scrollwheel: true, | |
draggable: true, | |
mapTypeControl:false, | |
streetViewControl:false, | |
zoomControl:false, | |
mapTypeId: google.maps.MapTypeId.ROADMAP, | |
} | |
}); | |
// Add Polygon to Map | |
if ( encodedCoordinatesElement.value ) { | |
polygon = map.addPolygon({ | |
encodedCoordinates: encodedCoordinatesElement.value, | |
color: colorElement.value | |
}); | |
map.gMap.panTo(polygon.getCenter()); | |
} | |
// Add Event Listener to Preview Changes | |
encodedCoordinatesElement.addEventListener(\'change\', function() { | |
if ( encodedCoordinatesElement.value ) { | |
if ( polygon == null ) { | |
polygon = map.addPolygon({ | |
encodedCoordinates: encodedCoordinatesElement.value, | |
color: colorElement.value | |
}); | |
map.gMap.panTo(polygon.getCenter()); | |
} else { | |
polygon.setOptions({paths: google.maps.geometry.encoding.decodePath(encodedCoordinatesElement.value)}); | |
map.gMap.panTo(polygon.getCenter()); | |
} | |
} else { | |
polygon.setMap(null); | |
polygon = null; | |
} | |
}, false); | |
colorElement.addEventListener(\'change\', function() { | |
polygon.setOptions({fillColor: colorElement.value}); | |
}, false); | |
}, 100); | |
}(window, window.Mapstractor || (window.Mapstractor == {}))); | |
</script> | |
'; | |
break; | |
case 'text_googleaddress' : | |
$metadatum_value_latlng = get_post_meta($post->ID, $metadatum_id.'_latlng', true); | |
$html .= '<label class="metadata-label" for="' . $metadatum_id . '">' . $metadatum_label .'</label>'; | |
$html .= '<div class="metadata-desc">' . $metadatum_desc .'</div>'; | |
$html .= '<textarea name="' . $metadatum_id .'" id="' . $metadatum_id .'" class="widefat">' . $metadatum_value . '</textarea>'; | |
$html .= '<input type="hidden" name="' . $metadatum_id .'_latlng" id="' . $metadatum_id .'_latlng" value="' . $metadatum_value_latlng . '" class="widefat">'; | |
$html .= ' | |
<script> | |
(function(window, google) { | |
var addressBoxElement = document.getElementById(\'' . $metadatum_id . '\'); | |
var latlngBoxElement = document.getElementById(\'' . $metadatum_id . '_latlng\'); | |
var addressBox = new google.maps.places.Autocomplete(addressBoxElement, {types: [\'address\'] }); | |
addressBox.addListener(\'place_changed\', function() { | |
var selectedPlace = addressBox.getPlace(); | |
addressBoxElement.value = selectedPlace.formatted_address.replace(\', USA\',\'\'); | |
latlngBoxElement.value = selectedPlace.geometry.location.lat() + \',\' + selectedPlace.geometry.location.lng(); | |
}); | |
}(window, google)); | |
</script> | |
'; | |
break; | |
case 'toggle' : | |
$html .= ' | |
<style> | |
toggle::after { | |
display:block; | |
clear:both; | |
content:""; | |
} | |
toggle input { | |
position:absolute; | |
left:-99999999px; | |
} | |
toggle svg { | |
height:20px; | |
width:20px; | |
display:block; | |
} | |
toggle label div { | |
display:block; | |
float:left; | |
padding:6px 12px; | |
border:solid 1px rgb(160,160,160); | |
fill:gray; | |
position: relative; | |
} | |
toggle label:first-child div { | |
border-radius:5px 0 0 5px; | |
left: 1px; | |
} | |
toggle label:last-child div { | |
border-radius:0 5px 5px 0; | |
right: 1px; | |
} | |
toggle input:checked ~ div { | |
color:white; | |
fill:white; | |
background-color: ' . $admin_colors . '; | |
border-color: ' . $admin_colors . '; | |
z-index:1; | |
} | |
</style>'; | |
$html .= '<div class="metadata-label">' . $metadatum_label .'</div>'; | |
$html .= '<div class="metadata-desc">' . $metadatum_desc .'</div>'; | |
$html .= '<toggle id="' . $random . '">'; | |
foreach ( $metadatum_options as $metadatum_option ) { | |
$html .= '<label><input type="radio" name="' . $metadatum_id .'"' . ( $metadatum_option['value'] == $metadatum_value ? ' checked="checked"' : '' ) . ' value="' . $metadatum_option['value'] . '"><div>' . $metadatum_option['label'] . '</div></label>'; | |
} | |
$html .= '</toggle>'; | |
break; | |
default : | |
$html .= '<label class="metadata-label" for="' . $metadatum_id . '">' . $metadatum_label .'</label>'; | |
$html .= '<div class="metadata-desc">' . $metadatum_desc .'</div>'; | |
$html .= '<input type="' . $metadatum_type . '" name="' . $metadatum_id .'" id="' . $metadatum_id .'" value="' . $metadatum_value . '" class="widefat" />'; | |
break; | |
} | |
$html .= '</div>'; | |
} | |
echo $html . '<input type="hidden" name="custommeta_noncename" id="custommeta_noncename" value="' . wp_create_nonce( plugin_basename(__FILE__) ) . '" />'; | |
} | |
function expose_metadata_via_restapi() { | |
if ( $this->metaboxes != null ) { | |
foreach ($this->metaboxes as $metabox) { | |
foreach ( $metabox['metadata'] as $metadatum ) { | |
register_rest_field( | |
strtolower($this->prefix.'_'.$this->slug), | |
strtolower($this->prefix.'_'.$this->slug) . '_metadata_' . $metadatum['slug'], | |
array( | |
'get_callback' => array( $this, 'slug_get_post_meta_cb' ), | |
'update_callback' => array( $this, 'slug_update_post_meta_cb' ), | |
'schema' => null, | |
) | |
); | |
} | |
} | |
} | |
} | |
function slug_get_post_meta_cb( $object, $field_name, $request ) { | |
return get_post_meta( $object['id'], $field_name ); | |
} | |
function slug_update_post_meta_cb( $value, $object, $field_name ) { | |
return update_post_meta( $object['id'], $field_name, $value ); | |
} | |
function save_ctp_custom_metadata($post_id, $post) { | |
if (empty($_POST["custommeta_noncename"])) {return;} | |
if ( !wp_verify_nonce( $_POST['custommeta_noncename'], plugin_basename(__FILE__) )) {return;} | |
if ( !current_user_can( 'edit_post', $post->ID )) {return;} | |
if ( $post->post_type == 'revision' ) {return;} | |
$post_type_slug = get_post_type($post); | |
$metadata_id = ''; | |
$metadata_object = array(); | |
if ( $this->metaboxes != null ) { | |
foreach ( $this->metaboxes as $metabox ) { | |
foreach ( $metabox['metadata'] as $metadatum ) { | |
$metadata_id = $post_type_slug . '_metadata_' . $metadatum['slug']; | |
$metadata_object[$metadata_id] = $_POST[$metadata_id]; | |
if ( $metadatum['type'] == 'text_googleaddress' ) { | |
$metadata_id = $post_type_slug . '_metadata_' . $metadatum['slug'].'_latlng'; | |
$metadata_object[$metadata_id] = $_POST[$metadata_id]; | |
} | |
} | |
} | |
} | |
// Add values of $metadata_saving as custom fields | |
foreach ($metadata_object as $key => $value) { | |
$value = implode(',', (array)$value); | |
if (get_post_meta($post->ID, $key, FALSE)) { | |
update_post_meta($post->ID, $key, $value); | |
} else { | |
add_post_meta($post->ID, $key, $value); | |
} if (!$value) { | |
delete_post_meta($post->ID, $key); | |
} | |
} | |
} | |
function create_ctp_icons(){ | |
$post_type_slug = strtolower($this->prefix.'_'.$this->slug); | |
$post_type_icon = $this->icon; | |
echo '<style>#adminmenu #menu-posts-'.$post_type_slug.' div.wp-menu-image:before {content: "'.$post_type_icon.'";}</style>'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment