columns_example = array(
'column_id' => array(
'name' => __( 'Column Name', 'advanced-post-manager' ),
'meta' => '_some_meta', // in most cases, this piece of meta will be queried to provide column contents
),
);
$this->nonce .= $post_type; // keep it tidy
$this->user_meta .= $post_type;
$this->post_type = $post_type;
$this->set_active( $active );
$this->set_columns( $columns );
$this->set_fallback( $fallback );
$this->add_actions_and_filters();
$this->url = trailingslashit( plugins_url( '', __FILE__ ) );
}
// PUBLIC API METHODS
/**
* Sets the columns to be shown in the list view for associated post type
* See documentation for column array construction
* @param $columns array of column arrays
*/
public function set_columns( $columns = array() ) {
if ( ! empty( $columns ) ) {
$this->columns = $columns;
$this->alphabetize_columns();
}
}
/**
* Adds columns to the current set of registered columns
* See documentation for column array construction
* @param $columns array of column arrays
*/
public function add_columns ( $columns = array() ) {
if ( ! empty( $columns ) ) {
$this->columns = array_merge( $this->columns, $columns );
$this->alphabetize_columns();
}
}
/**
* Whether registered columns should be shown after or before WordPress defaults
* @param $append bool 'before' or 'after'
*/
public function set_override( $override ) {
$this->override = (bool) $override;
}
/**
* Set fallback defaults for when custom column are cleared
* When fallback is empty, all columns will be shown on reset
* @param $fallback array one-dimensional array of column keys
*/
public function set_fallback( $fallback = array() ) {
$this->fallback = (array) $fallback;
}
/**
* Explicitly set an active set of columns. Usually not set.
* This will override any other internal method of retrieving active columns
* @param $active array one-dimensional array of column keys
*/
public function set_active( $active = array() ) {
$this->active = (array) $active;
}
/**
* Outputs the drag & drop columns view.
* Expects to be inside a form
*/
public function output_form() {
wp_nonce_field( $this->nonce, $this->nonce, false );
$headers = $this->get_column_headers();
// make sure there are no strays
$this->sweep_empties();
// key 'em up
$active = array();
foreach ( $this->active as $v ) {
$active[ $v ] = $v;
}
$inactive = array_diff_key( $headers, $active );
unset( $active );
?>
active as $v ) {
if ( ! isset( $headers[ $v ] ) ) {
continue;
}
// the comments header is typically an icon. This swaps it out with text
if ( 'comments' == $v ) {
$headers[ $v ] = __( 'Comments' );
}//end if
echo '';
echo ' ';
echo esc_html( wp_strip_all_tags( $headers[ $v ] ) );
echo '× ';
echo ' ';
$i++;
}
?>
' . esc_html__( 'Add a Column', 'advanced-post-manager' ) . '';
foreach ( $inactive as $key => $value ) {
$name = ( is_string( $value ) ) ? $value : $value['name'];
if ( empty( $name ) ) {
continue;
}
if ( false !== strstr( $name, '="Comments"' ) ) {
$name = __( 'Comments' );
}
echo '' . esc_html( wp_strip_all_tags( $name ) ) . ' ';
}
?>
post_type.'_posts_custom_column', array( $this, 'custom_columns' ), 10, 2 );
add_filter( 'manage_' . $this->post_type.'_posts_columns', array( $this, 'column_headers' ) );
add_filter( 'manage_edit-' . $this->post_type.'_sortable_columns', array( $this, 'sortable_columns' ) );
add_action( 'load-edit.php', array( $this, 'init_active' ), 10 );
add_action( 'load-edit.php', array( $this, 'save_active' ), 20 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
add_filter( 'tribe_columns_column', array( $this, 'date_column' ), 10, 3 );
// Needs to be executed when quick edit is saved, hence the following line.
add_action( 'save_post', array( $this, 'init_active' ) );
}
public function date_column( $value, $column_id, $column ) {
if ( ! empty( $value ) && self::is_date( $column ) && isset( $column['date_format'] ) ) {
$value = date( $column['date_format'], strtotime( $value ) );
}
return $value;
}
public function sortable_columns( $columns ) {
$sort_prefix = apply_filters( 'tribe_sort_prefix', 'tribe_sort_' );
$new_cols = array();
foreach ( $this->columns as $k => $v ) {
$sort_key = false;
// Custom Type must have the sortable flag set
if ( isset( $v['custom_type'] ) && isset( $v['sortable'] ) && $v['sortable'] ) {
$sort_key = $v['custom_type'];
}
// Meta is always sortable
elseif ( isset( $v['meta'] ) ) {
$sort_key = $v['meta'];
}
// Got it?
if ( $sort_key ) {
$new_cols[ $k ] = $sort_prefix . $sort_key;
}
} // endforeach
$columns = array_merge( $columns, $new_cols );
return $columns;
}
public function enqueue() {
global $current_screen;
$resources_url = apply_filters( 'tribe_apm_resources_url', $this->url . 'resources' );
$resources_url = trailingslashit( $resources_url );
if ( $current_screen->id == 'edit-' . $this->post_type ) {
wp_enqueue_script( 'tribe-columns', $resources_url . 'tribe-columns.js', array( 'jquery-ui-sortable' ) );
}
}
public function init_active() {
global $userdata;
// get active from usermeta
if ( empty( $this->active ) ) {
$this->active = get_user_meta( $userdata->ID, $this->user_meta, true );
}
// if empty, try the fallback
if ( empty( $this->active ) ) {
$this->active = $this->fallback;
}
// if still empty, show everything. God help us.
if ( empty( $this->active ) ) {
$this->active = array_keys( $this->get_column_headers() );
}
}
public function save_active() {
if ( ! isset( $_REQUEST[ $this->nonce ] ) || ! wp_verify_nonce( $_REQUEST[ $this->nonce ], $this->nonce ) ) {
return;
}
// Clear button on frontend
if ( isset( $_POST['tribe-clear'] ) ) {
$this->reset_active();
return;
}
$data = $_REQUEST;
$i = 1;
while ( $i <= count( $this->get_column_headers() ) ) {
if ( isset( $data[ $this->prefix . $i ] ) ) {
$to_save[] = $data[ $this->prefix . $i ];
}
$i++;
}
if ( ! empty( $to_save ) ) {
global $userdata;
update_user_meta( $userdata->ID, $this->user_meta, $to_save );
$this->using_fallbacks = false;
$this->active = $to_save;
}
}
public function column_headers( $columns ) {
if ( ! $this->is_our_post_type() )
return $columns;
if ( ! empty( $this->active ) ) {
$headers = $this->get_column_headers( false );
$columns = array( 'cb' => $headers['cb'] );
foreach ( $this->active as $v ) {
$columns[ $v ] = $headers[ $v ];
}
}
do_action( 'tribe_apm_headers_' . $this->post_type, $columns );
return $columns;
}
public function custom_columns( $column_id, $post_id ) {
if ( ! $this->is_our_post_type() )
return;
$post = get_post( $post_id );
if ( array_key_exists( $column_id, $this->columns ) ) {
$column = $this->columns[ $column_id ];
// meta ?
if ( isset( $column['meta'] ) ) {
$value = get_post_meta( $post_id, $column['meta'], true );
// Do an options map for prettiness
if ( isset( $column['options'] ) && isset( $column['options'][ $value ] ) ) {
$value = $column['options'][ $value ];
}
}
// taxonomy?
elseif ( isset( $column['taxonomy'] ) ) {
$value = $this->taxonomy_column( $post_id, $column['taxonomy'] );
}
// custom type?
elseif ( isset( $column['custom_type'] ) ) {
$value = apply_filters( 'tribe_custom_column' . $column['custom_type'], '', $column_id, $post_id );
}
// filter time
$value = apply_filters( 'tribe_columns_column', $value, $column_id, $column, $post_id );
$value = apply_filters( 'tribe_columns_column_' . $column_id, $value, $post_id );
// if name isn't set, and first in $this->columns, let's link it up
if ( ! array_key_exists( 'title', $this->active ) && reset( $this->active ) == $column_id ) {
// if value is empty, we've got a problem for, you know, clicking.
$value = ( empty( $value ) ) ? '–Blank–' : $value;
$value = sprintf( '%s %s ',
esc_url( get_admin_url( null, "post.php?post={$post_id}&action=edit" ) ),
'Edit ‘' . strip_tags( esc_attr( get_the_title( $post_id ) ) ) . '’',
$value,
// Post status, if not published
( $post->post_status !== 'publish' ) ? " - {$post->post_status}" : ''
);
}
echo $value;
}
}
// UTLITIES AND INTERNAL METHODS
protected function sweep_empties() {
$headers = $this->get_column_headers();
foreach ( $headers as $k => $v ) {
if ( empty( $v ) ) {
unset( $this->active[ $k ] );
}
}
}
private function get_column_headers( $omit_checkbox = true ) {
if ( ! empty( $this->column_headers ) ) {
$headers = $this->column_headers;
}
else {
// If we're nuking the existing columns, still provide checkboxes
if ( $this->override ) {
$headers = array( 'cb' => ' ' );
}
else {
// Cause infinite loops get boring after a while
remove_filter( 'manage_' . $this->post_type . '_posts_columns', array( $this, 'column_headers' ) );
$this->load_list_table();
$list = new WP_Posts_List_Table();
$headers = $list->get_columns();
add_filter( 'manage_' . $this->post_type . '_posts_columns', array( $this, 'column_headers' ) );
}
foreach ( $this->columns as $key => $value ) {
$headers[ $key ] = $value['name'];
}
$this->column_headers = $headers;
}
if ( $omit_checkbox && isset( $headers['cb'] ) ) {
unset( $headers['cb'] );
}
/**
* Filters the column headers markup to be shown in the "Active Columns" section.
*
* @since 4.1
*
* @param array $headers An associative array of filter keys to column headers.
*/
return apply_filters( 'tribe_apm_column_headers', $headers );
}
private function load_list_table() {
if ( ! class_exists( 'WP_Posts_List_Table' ) ) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-posts-list-table.php' );
}
}
private function alphabetize_columns() {
$columns = (array) $this->columns;
if ( empty( $columns ) )
return;
foreach ( $columns as $k => $v ) {
if ( ! empty( $v['name'] ) )
$temp[ $k ] = $v['name'];
}
asort( $temp );
foreach ( $temp as $k => $v ) {
$alpha_columns[ $k ] = $columns[ $k ];
}
$this->columns = $alpha_columns;
unset( $alpha_columns, $temp );
}
public function log( $data = array() ) {
error_log( print_r( $data, true ) );
}
protected function taxonomy_column( $post_id, $taxonomy ) {
$terms = get_the_terms( $post_id, $taxonomy );
if ( ! $terms || empty( $terms ) ){
return '–';
}
$ret = array();
$post = get_post( $post_id );
foreach ( $terms as $term ) {
$url = add_query_arg( array(
'post_type' => $post->post_type,
$taxonomy => $term->slug,
), admin_url( 'edit.php' ) );
$ret[] = sprintf( '%s ', esc_url( $url ), esc_html( $term->name ) );
}
return implode( ', ', $ret );
}
private function reset_active() {
global $userdata;
delete_user_meta( $userdata->ID, $this->user_meta );
$this->active = array();
$this->init_active();
}
protected function is_date( $column ) {
if ( isset( $column['cast'] ) ) {
$cast = ucwords( $column['cast'] );
if ( in_array( $cast, array( 'DATE', 'DATETIME' ) ) ) {
return true;
}
}
elseif ( isset( $column['type'] ) && 'DATE' === ucwords( $column['type'] ) ) {
return true;
}
return false;
}
protected function is_our_post_type() {
$screen = get_current_screen();
if ( empty( $screen ) ) {
global $typenow;
$post_type = empty( $typenow ) ? 'post' : $typenow;
}
else {
$post_type = $screen->post_type;
}
if ( $post_type === $this->post_type )
return true;
else
return false;
}
}