570 lines
13 KiB
PHP
570 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* Post Meta module
|
|
*
|
|
* Version: 1.0.0
|
|
*/
|
|
|
|
// If this file is called directly, abort.
|
|
if ( ! defined( 'WPINC' ) ) {
|
|
die;
|
|
}
|
|
|
|
if ( ! class_exists( 'Cherry_X_Post_Meta' ) ) {
|
|
|
|
/**
|
|
* Post meta management module.
|
|
*/
|
|
class Cherry_X_Post_Meta {
|
|
|
|
/**
|
|
* Module arguments.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $args = array();
|
|
|
|
/**
|
|
* Interface builder instance.
|
|
*
|
|
* @var object
|
|
*/
|
|
public $builder = null;
|
|
|
|
/**
|
|
* Current nonce name to check.
|
|
*
|
|
* @var null
|
|
*/
|
|
public $nonce = 'cherry-x-meta-nonce';
|
|
|
|
/**
|
|
* Storage of meta values.
|
|
*
|
|
* @since 1.0.0
|
|
* @var array
|
|
*/
|
|
public $meta_values = array();
|
|
|
|
/**
|
|
* Constructor for the module.
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function __construct( $args = array() ) {
|
|
|
|
$this->args = wp_parse_args(
|
|
$args,
|
|
array(
|
|
'id' => 'cherry-post-metabox',
|
|
'title' => '',
|
|
'page' => array( 'post' ),
|
|
'context' => 'normal',
|
|
'priority' => 'high',
|
|
'single' => false,
|
|
'callback_args' => false,
|
|
'builder_cb' => false,
|
|
'fields' => array(),
|
|
)
|
|
);
|
|
|
|
if ( empty( $this->args['fields'] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! is_array( $this->args['page'] ) ) {
|
|
$this->args['page'] = array( $this->args['page'] );
|
|
}
|
|
|
|
$this->init_columns_actions();
|
|
|
|
add_action( 'admin_enqueue_scripts', array( $this, 'init_builder' ), 0 );
|
|
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
|
|
add_action( 'save_post', array( $this, 'save_meta' ), 10, 2 );
|
|
|
|
}
|
|
|
|
/**
|
|
* Initialize builder
|
|
*
|
|
* @return [type] [description]
|
|
*/
|
|
public function init_builder( $hook ) {
|
|
global $post;
|
|
|
|
if ( ! in_array( $hook, array( 'post-new.php', 'post.php' ) ) ) {
|
|
return;
|
|
}
|
|
|
|
$post_type = get_post_type();
|
|
|
|
if ( ! in_array( $post_type, $this->args['page'] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $this->args['builder_cb'] ) || ! is_callable( $this->args['builder_cb'] ) ) {
|
|
return;
|
|
}
|
|
|
|
$this->builder = call_user_func( $this->args['builder_cb'] );
|
|
|
|
$this->get_fields( $post );
|
|
|
|
}
|
|
|
|
/**
|
|
* Initalize admin columns
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init_columns_actions() {
|
|
|
|
if ( empty( $this->args['admin_columns'] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! is_array( $this->args['page'] ) ) {
|
|
$pages = array( $this->args['page'] );
|
|
} else {
|
|
$pages = $this->args['page'];
|
|
}
|
|
|
|
foreach ( $pages as $page ) {
|
|
add_filter( 'manage_edit-' . $page . '_columns', array( $this, 'edit_columns' ) );
|
|
add_action( 'manage_' . $page . '_posts_custom_column', array( $this, 'manage_columns' ), 10, 2 );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Edit admin columns
|
|
*
|
|
* @since 1.1.3
|
|
* @param array $columns current post table columns.
|
|
* @return array
|
|
*/
|
|
public function edit_columns( $columns ) {
|
|
|
|
foreach ( $this->args['admin_columns'] as $column_key => $column_data ) {
|
|
|
|
if ( empty( $column_data['label'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( ! empty( $column_data['position'] ) && 0 !== (int) $column_data['position'] ) {
|
|
|
|
$length = count( $columns );
|
|
|
|
if ( (int) $column_data['position'] > $length ) {
|
|
$columns[ $column_key ] = $column_data['label'];
|
|
}
|
|
|
|
$columns_before = array_slice( $columns, 0, (int) $column_data['position'] );
|
|
$columns_after = array_slice( $columns, (int) $column_data['position'], $length - (int) $column_data['position'] );
|
|
|
|
$columns = array_merge(
|
|
$columns_before,
|
|
array(
|
|
$column_key => $column_data['label'],
|
|
),
|
|
$columns_after
|
|
);
|
|
} else {
|
|
$columns[ $column_key ] = $column_data['label'];
|
|
}
|
|
}
|
|
|
|
return $columns;
|
|
|
|
}
|
|
|
|
/**
|
|
* Add output for custom columns.
|
|
*
|
|
* @since 1.1.3
|
|
* @param string $column current post list categories.
|
|
* @param int $post_id current post ID.
|
|
* @return void
|
|
*/
|
|
public function manage_columns( $column, $post_id ) {
|
|
|
|
if ( empty( $this->args['admin_columns'][ $column ] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! empty( $this->args['admin_columns'][ $column ]['callback'] ) && is_callable( $this->args['admin_columns'][ $column ]['callback'] ) ) {
|
|
call_user_func( $this->args['admin_columns'][ $column ]['callback'], $column, $post_id );
|
|
} else {
|
|
echo get_post_meta( $post_id, $column, true );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Check if defined metabox is allowed on current page
|
|
*
|
|
* @since 1.0.0
|
|
* @return boolean
|
|
*/
|
|
public function is_allowed_page() {
|
|
|
|
global $current_screen;
|
|
|
|
if ( empty( $current_screen ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( is_array( $this->args['page'] ) && ! in_array( $current_screen->id, $this->args['page'] ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( is_string( $this->args['page'] ) && $current_screen->id !== $this->args['page'] ) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Add meta box handler
|
|
*
|
|
* @since 1.0.0
|
|
* @param [type] $post_type The post type of the current post being edited.
|
|
* @param object $post The current post object.
|
|
* @return void
|
|
*/
|
|
public function add_meta_boxes( $post_type, $post ) {
|
|
|
|
if ( ! $this->is_allowed_page() ) {
|
|
return;
|
|
}
|
|
|
|
add_meta_box(
|
|
$this->args['id'],
|
|
$this->args['title'],
|
|
array( $this, 'render_metabox' ),
|
|
$this->args['page'],
|
|
$this->args['context'],
|
|
$this->args['priority'],
|
|
$this->args['callback_args']
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Render metabox funciton
|
|
*
|
|
* @since 1.0.0
|
|
* @param object $post The post object currently being edited.
|
|
* @param array $metabox Specific information about the meta box being loaded.
|
|
* @return void
|
|
*/
|
|
public function render_metabox( $post, $metabox ) {
|
|
|
|
if ( ! $this->builder ) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Filter custom metabox output. Prevent from showing main box, if user output passed
|
|
*
|
|
* @var string
|
|
*/
|
|
$custom_box = apply_filters( 'cx_post_meta/custom_box', false, $post, $metabox );
|
|
|
|
if ( false !== $custom_box ) {
|
|
echo $custom_box;
|
|
return;
|
|
}
|
|
|
|
wp_nonce_field( $this->nonce, $this->nonce );
|
|
|
|
/**
|
|
* Hook fires before metabox output started.
|
|
*/
|
|
do_action( 'cx_post_meta/meta_box/before' );
|
|
|
|
$this->builder->render();
|
|
|
|
/**
|
|
* Hook fires after metabox output finished.
|
|
*/
|
|
do_action( 'cx_post_meta/meta_box/after' );
|
|
|
|
}
|
|
|
|
/**
|
|
* Safely get attribute from field settings array.
|
|
*
|
|
* @since 1.0.0
|
|
* @param array $field arguments array.
|
|
* @param string|int|float $arg argument key.
|
|
* @param mixed $default default argument value.
|
|
* @return mixed
|
|
*/
|
|
public function get_arg( $field, $arg, $default = '' ) {
|
|
if ( is_array( $field ) && isset( $field[ $arg ] ) ) {
|
|
return $field[ $arg ];
|
|
}
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* Get registered control fields
|
|
*
|
|
* @since 1.0.0
|
|
* @since 1.2.0 Use interface builder for HTML rendering.
|
|
* @param mixed $post Current post object.
|
|
* @return void
|
|
*/
|
|
public function get_fields( $post ) {
|
|
|
|
if ( is_array( $this->args['single'] ) && isset( $this->args['single']['key'] ) ) {
|
|
$this->meta_values = get_post_meta( $post->ID, $this->args['single']['key'], true );
|
|
}
|
|
|
|
$zero_allowed = apply_filters(
|
|
'cx_post_meta/zero_allowed_controls',
|
|
array(
|
|
'stepper',
|
|
'slider',
|
|
)
|
|
);
|
|
|
|
foreach ( $this->args['fields'] as $key => $field ) {
|
|
|
|
$default = $this->get_arg( $field, 'value', '' );
|
|
$value = $this->get_meta( $post, $key, $default );
|
|
|
|
if ( isset( $field['options_callback'] ) ) {
|
|
$field['options'] = call_user_func( $field['options_callback'] );
|
|
}
|
|
|
|
$element = $this->get_arg( $field, 'element', 'control' );
|
|
$field['id'] = $this->get_arg( $field, 'id', $key );
|
|
$field['name'] = $this->get_arg( $field, 'name', $key );
|
|
$field['type'] = $this->get_arg( $field, 'type', '' );
|
|
$field['value'] = $value;
|
|
|
|
// Fix zero values for stepper and slider
|
|
if ( ! $value && in_array( $field['type'], $zero_allowed ) ) {
|
|
$field['value'] = 0;
|
|
}
|
|
|
|
$register_callback = 'register_' . $element;
|
|
|
|
if ( method_exists( $this->builder, $register_callback ) ) {
|
|
call_user_func( array( $this->builder, $register_callback ), $field );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save additional taxonomy meta on edit or create tax
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $post_id The ID of the current post being saved.
|
|
* @param object $post The post object currently being saved.
|
|
* @return void|int
|
|
*/
|
|
public function save_meta( $post_id, $post = '' ) {
|
|
|
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $_POST[ $this->nonce ] ) || ! wp_verify_nonce( $_POST[ $this->nonce ], $this->nonce ) ) {
|
|
return;
|
|
}
|
|
|
|
$posts = ! empty( $this->args['page'] ) ? $this->args['page'] : array( 'post' );
|
|
$posts = is_array( $posts ) ? $posts : array( $posts );
|
|
|
|
$maybe_break = false;
|
|
|
|
foreach ( $posts as $post_type ) {
|
|
|
|
if ( get_post_type( $post_id ) !== $post_type ) {
|
|
$maybe_break = true;
|
|
continue;
|
|
}
|
|
|
|
$maybe_break = false;
|
|
$obj = get_post_type_object( $post_type );
|
|
|
|
if ( ! isset( $obj->cap->edit_posts ) || ! current_user_can( $obj->cap->edit_posts ) ) {
|
|
$maybe_break = true;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if ( true === $maybe_break ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! $this->is_allowed_page() ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! is_object( $post ) ) {
|
|
$post = get_post();
|
|
}
|
|
|
|
/**
|
|
* Hook on before current metabox saving
|
|
*/
|
|
do_action( 'cx_post_meta/before_save/' . $this->args['id'], $post_id, $post );
|
|
|
|
if ( is_array( $this->args['single'] ) && isset( $this->args['single']['key'] ) ) {
|
|
$this->save_meta_mod( $post_id );
|
|
} else {
|
|
$this->save_meta_option( $post_id );
|
|
}
|
|
|
|
/**
|
|
* Hook on after current metabox saving
|
|
*/
|
|
do_action( 'cx_post_meta/after_save/' . $this->args['id'], $post_id, $post );
|
|
|
|
}
|
|
|
|
/**
|
|
* Save all meta values as a one array value in `wp_postmeta` table.
|
|
*
|
|
* @since 1.1.0
|
|
* @param int $post_id Post ID.
|
|
*/
|
|
public function save_meta_mod( $post_id ) {
|
|
$meta_key = $this->args['single']['key'];
|
|
|
|
// Array of new post meta value.
|
|
$new_meta_value = array();
|
|
|
|
if ( empty( $_POST[ $meta_key ] ) ) {
|
|
return;
|
|
}
|
|
|
|
foreach ( $_POST[ $meta_key ] as $key => $value ) {
|
|
|
|
$new_meta_value[ $key ] = $this->sanitize_meta( $key, $value );
|
|
}
|
|
|
|
// Get current post meta data.
|
|
$meta_value = get_post_meta( $post_id, $meta_key, true );
|
|
|
|
if ( $new_meta_value && '' == $meta_value ) {
|
|
add_post_meta( $post_id, $meta_key, $new_meta_value, true );
|
|
} elseif ( $new_meta_value && $new_meta_value != $meta_value ) {
|
|
update_post_meta( $post_id, $meta_key, $new_meta_value );
|
|
} elseif ( empty( $new_meta_value ) && $meta_value ) {
|
|
delete_post_meta( $post_id, $meta_key, $meta_value );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save each meta value as a single value in `wp_postmeta` table.
|
|
*
|
|
* @since 1.1.0
|
|
* @param int $post_id Post ID.
|
|
*/
|
|
public function save_meta_option( $post_id ) {
|
|
|
|
foreach ( $this->args['fields'] as $key => $field ) {
|
|
|
|
if ( isset( $field['element'] ) && 'control' !== $field['element'] ) {
|
|
continue;
|
|
}
|
|
|
|
if ( empty( $_POST[ $key ] ) ) {
|
|
update_post_meta( $post_id, $key, false );
|
|
continue;
|
|
}
|
|
|
|
$value = $this->sanitize_meta( $key, $_POST[ $key ] );
|
|
update_post_meta( $post_id, $key, $value );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Sanitize passed meta value
|
|
*
|
|
* @since 1.1.3
|
|
* @param string $key Meta key to sanitize.
|
|
* @param mixed $value Meta value.
|
|
* @return mixed
|
|
*/
|
|
public function sanitize_meta( $key, $value ) {
|
|
|
|
if ( empty( $this->args['fields'][ $key ]['sanitize_callback'] ) ) {
|
|
return $this->sanitize_deafult( $value );
|
|
}
|
|
|
|
if ( ! is_callable( $this->args['fields'][ $key ]['sanitize_callback'] ) ) {
|
|
return $this->sanitize_deafult( $value );
|
|
}
|
|
|
|
return call_user_func(
|
|
$this->args['fields'][ $key ]['sanitize_callback'],
|
|
$value,
|
|
$key,
|
|
$this->args['fields'][ $key ]
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
* Cleare value with sanitize_text_field if not is array
|
|
*
|
|
* @since 1.1.3
|
|
* @param mixed $value Passed value.
|
|
* @return mixed
|
|
*/
|
|
public function sanitize_deafult( $value ) {
|
|
return is_array( $value ) ? $value : sanitize_text_field( $value );
|
|
}
|
|
|
|
/**
|
|
* Retrieve post meta field.
|
|
*
|
|
* @since 1.1.0
|
|
* @since 1.2.0 Process default value.
|
|
*
|
|
* @param object $post Current post object.
|
|
* @param string $key The meta key to retrieve.
|
|
* @param mixed $default Default value.
|
|
* @return string
|
|
*/
|
|
public function get_meta( $post, $key, $default = false ) {
|
|
|
|
if ( ! is_object( $post ) ) {
|
|
return '';
|
|
}
|
|
|
|
if ( is_array( $this->args['single'] ) && isset( $this->args['single']['key'] ) ) {
|
|
return isset( $this->meta_values[ $key ] ) ? $this->meta_values[ $key ] : $default;
|
|
}
|
|
|
|
$meta = get_post_meta( $post->ID, $key, false );
|
|
|
|
return ( empty( $meta ) ) ? $default : $meta[0];
|
|
}
|
|
|
|
/**
|
|
* Returns the instance.
|
|
*
|
|
* @since 1.0.0
|
|
* @return object
|
|
*/
|
|
public static function get_instance( $core, $args ) {
|
|
|
|
if ( ! is_admin() ) {
|
|
return;
|
|
}
|
|
|
|
return new self( $core, $args );
|
|
}
|
|
}
|
|
}
|