Skip to content

Instantly share code, notes, and snippets.

@bronwynv
Forked from Kelderic/custom_post_types.php
Created March 19, 2017 03:27
Show Gist options
  • Save bronwynv/4481cd9e091b145a94c62e4424b593aa to your computer and use it in GitHub Desktop.
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.
<?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