<?php
/**
* Meta boxes manager
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
if ( ! class_exists( 'Jet_Engine_Meta_Boxes' ) ) {
/**
* Define Jet_Engine_Meta_Boxes class
*/
class Jet_Engine_Meta_Boxes extends Jet_Engine_Base_WP_Intance {
/**
* Base slug for CPT-related pages
* @var string
*/
public $page = 'jet-engine-meta';
/**
* Action request key
*
* @var string
*/
public $action_key = 'cpt_meta_action';
/**
* Set object type
* @var string
*/
public $object_type = '';
/**
* Meta fields for object
*
* @var null
*/
public $meta_fields = array();
private $custom_groups = array();
/**
* Meta fields with `save custom` option
*
* @var array
*/
public $meta_fields_save_custom = array();
/**
* Init data instance
*
* @return [type] [description]
*/
public function init_data() {
add_action( 'jet-engine/pages/cpt/register', array( $this, 'add_meta_fields_to_rel_components' ) );
add_action( 'jet-engine/pages/taxonomies/register', array( $this, 'add_meta_fields_to_rel_components' ) );
require $this->component_path( 'data.php' );
$this->data = new Jet_Engine_Meta_Boxes_Data( $this );
}
/**
* Add meta fields editor to components where it allowed
*/
public function add_meta_fields_to_rel_components() {
$pages = $this->get_instance_pages();
if ( ! class_exists( 'Jet_Engine_Meta_Boxes_Page_Edit' ) ) {
require $pages['Jet_Engine_Meta_Boxes_Page_Edit'];
}
add_action(
'jet-engine/post-type/edit/before-enqueue-assets',
array( 'Jet_Engine_Meta_Boxes_Page_Edit', 'enqueue_meta_fields' )
);
add_action(
'jet-engine/taxonomies/edit/before-enqueue-assets',
array( 'Jet_Engine_Meta_Boxes_Page_Edit', 'enqueue_meta_fields' )
);
add_action(
'jet-engine/post-types/meta-fields',
function() {
echo '<jet-meta-fields v-model="metaFields"></jet-meta-fields>';
}
);
add_action(
'jet-engine/taxonomies/meta-fields',
function() {
echo '<jet-meta-fields v-model="metaFields"></jet-meta-fields>';
}
);
}
/**
* Initiizlize post type specific API endpoints
*
* @param Jet_Engine_REST_API $api_manager API manager instance.
* @return void
*/
public function init_rest( $api_manager ) {
require_once $this->component_path( 'rest-api/add-meta-box.php' );
require_once $this->component_path( 'rest-api/edit-meta-box.php' );
require_once $this->component_path( 'rest-api/get-meta-box.php' );
require_once $this->component_path( 'rest-api/get-meta-boxes.php' );
require_once $this->component_path( 'rest-api/delete-meta-box.php' );
$api_manager->register_endpoint( new Jet_Engine_Meta_Boxes_Rest_Add() );
$api_manager->register_endpoint( new Jet_Engine_Meta_Boxes_Rest_Edit() );
$api_manager->register_endpoint( new Jet_Engine_Meta_Boxes_Rest_Get() );
$api_manager->register_endpoint( new Jet_Engine_Meta_Boxes_Rest_Get_All() );
$api_manager->register_endpoint( new Jet_Engine_Meta_Boxes_Rest_Delete() );
}
/**
* Return path to file inside component
*
* @param [type] $path_inside_component [description]
* @return [type] [description]
*/
public function component_path( $path_inside_component ) {
return jet_engine()->plugin_path( 'includes/components/meta-boxes/' . $path_inside_component );
}
/**
* Regiter custom group
*
* @param [type] $name [description]
* @param [type] $label [description]
* @return [type] [description]
*/
public function register_custom_group( $name, $label ) {
$this->custom_groups[ $name ] = $label;
}
/**
* Register metaboxes
*
* @return void
*/
public function register_instances() {
$meta_boxes = $this->data->get_raw();
do_action( 'jet-engine/meta-boxes/register-instances', $this );
if ( empty( $meta_boxes ) ) {
$this->store_default_user_meta_fields();
return;
}
foreach ( $meta_boxes as $meta_box ) {
$args = $meta_box['args'];
$meta_fields = $meta_box['meta_fields'];
$object_type = isset( $args['object_type'] ) ? esc_attr( $args['object_type'] ) : 'post';
switch ( $object_type ) {
case 'post':
if ( ! class_exists( 'Jet_Engine_CPT_Meta' ) ) {
require $this->component_path( 'post.php' );
}
$post_types = ! empty( $args['allowed_post_type'] ) ? $args['allowed_post_type'] : array();
$title = isset( $args['name'] ) ? $args['name'] : '';
foreach ( $post_types as $post_type ) {
if ( ! post_type_exists( $post_type ) ) {
continue;
}
$this->store_fields( $post_type, $meta_fields );
$this->find_meta_fields_with_save_custom( $object_type, $post_type, $meta_box['id'], $meta_fields );
if ( ! empty( $args['allowed_posts'] ) ) {
$post_id = $this->get_post_id();
if ( ! $post_id || ! in_array( $post_id, $args['allowed_posts'] ) ) {
continue;
}
}
if ( ! empty( $args['excluded_posts'] ) && is_array( $args['excluded_posts'] ) ) {
$post_id = $this->get_post_id();
if ( $post_id && in_array( $post_id, $args['excluded_posts'] ) ) {
continue;
}
}
$meta_instance = new Jet_Engine_CPT_Meta( $post_type, $meta_fields, $title );
if ( ! empty( $args['show_edit_link'] ) ) {
$meta_instance->add_edit_link( add_query_arg(
array(
'page' => 'jet-engine-meta',
'cpt_meta_action' => 'edit',
'id' => $meta_box['id'],
),
admin_url( 'admin.php' )
) );
}
}
break;
case 'tax':
case 'taxonomy':
if ( ! class_exists( 'Jet_Engine_CPT_Tax_Meta' ) ) {
require $this->component_path( 'tax.php' );
}
$taxonomies = ! empty( $args['allowed_tax'] ) ? $args['allowed_tax'] : array();
foreach ( $taxonomies as $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
continue;
}
$meta_instance = new Jet_Engine_CPT_Tax_Meta( $taxonomy, $meta_fields );
if ( ! empty( $args['show_edit_link'] ) ) {
$meta_instance->add_edit_link( add_query_arg(
array(
'page' => 'jet-engine-meta',
'cpt_meta_action' => 'edit',
'id' => $meta_box['id'],
),
admin_url( 'admin.php' )
) );
}
$this->store_fields( $taxonomy, $meta_fields );
$this->find_meta_fields_with_save_custom( $object_type, $taxonomy, $meta_box['id'], $meta_fields );
}
break;
case 'user':
if ( ! class_exists( 'Jet_Engine_CPT_User_Meta' ) ) {
require $this->component_path( 'user.php' );
}
$meta_instance = new Jet_Engine_CPT_User_Meta( $args, $meta_fields );
if ( ! empty( $args['show_edit_link'] ) ) {
$meta_instance->add_edit_link( add_query_arg(
array(
'page' => 'jet-engine-meta',
'cpt_meta_action' => 'edit',
'id' => $meta_box['id'],
),
admin_url( 'admin.php' )
) );
}
$object_name = $args['name'] . ' ' . __( '(User fields)', 'jet-engine' );
$this->store_fields( $object_name, $meta_fields );
$this->find_meta_fields_with_save_custom( $object_type, 'user', $meta_box['id'], $meta_fields );
foreach ( $meta_fields as $field ) {
if ( ! empty( $field['object_type'] ) && 'field' !== $field['object_type'] ) {
continue;
}
if ( empty( $field['name'] ) ) {
continue;
}
jet_engine()->listings->data->user_fields[] = $field['name'];
}
break;
default:
do_action( 'jet-engine/meta-boxes/register-custom-source/' . $object_type, $meta_box, $this );
break;
}
}
$this->store_default_user_meta_fields();
$this->add_hooks_to_save_custom_values();
}
/**
* Register the same metabox as default but from outside of this instance
*
* @return [type] [description]
*/
public function register_metabox( $post_type = '', $meta_fields = array(), $title = '', $object_name = null ) {
$object_name = ! empty( $object_name ) ? $object_name : $post_type;
$this->store_fields( $object_name, $meta_fields );
if ( ! class_exists( 'Jet_Engine_CPT_Meta' ) ) {
require $this->component_path( 'post.php' );
}
new Jet_Engine_CPT_Meta( $post_type, $meta_fields, $title );
}
/**
* Strore information aboutt all registered fields
*
* @param string $post_type [description]
* @param array $meta_fields [description]
* @return [type] [description]
*/
public function store_fields( $object_type = 'post', $meta_fields = array() ) {
if ( empty( $this->meta_fields[ $object_type ] ) ) {
$this->meta_fields[ $object_type ] = array();
}
$this->meta_fields[ $object_type ] = array_merge(
$this->meta_fields[ $object_type ],
array_values( $meta_fields )
);
}
/**
* Return all registered meta fields
*
* @return array
*/
public function get_registered_fields() {
return $this->meta_fields;
}
/**
* Find meta fields with enabling `save custom` option
*
* @param $object_type
* @param $sub_type
* @param $meta_box_id
* @param $fields
*/
public function find_meta_fields_with_save_custom( $object_type, $sub_type, $meta_box_id, $fields ) {
foreach ( $fields as $field ) {
if ( empty( $field['object_type'] ) ) {
continue;
}
if ( 'field' !== $field['object_type'] || ! in_array( $field['type'], array( 'checkbox', 'radio' ) ) ) {
continue;
}
$allow_custom = ! empty( $field['allow_custom'] ) && filter_var( $field['allow_custom'], FILTER_VALIDATE_BOOLEAN );
$save_custom = ! empty( $field['save_custom'] ) && filter_var( $field['save_custom'], FILTER_VALIDATE_BOOLEAN );
if ( ! $allow_custom || ! $save_custom ) {
continue;
}
if ( empty( $this->meta_fields_save_custom[ $object_type ] ) ) {
$this->meta_fields_save_custom[ $object_type ] = array();
}
$field_args = array_merge( array( 'meta_box_id' => $meta_box_id ), $field );
if ( empty( $this->meta_fields_save_custom[ $object_type ][ $sub_type ] ) ) {
$this->meta_fields_save_custom[ $object_type ][ $sub_type ] = array();
}
$this->meta_fields_save_custom[ $object_type ][ $sub_type ][ $field['name'] ] = $field_args;
}
}
/**
* Add hooks to save custom values
*/
public function add_hooks_to_save_custom_values() {
if ( empty( $this->meta_fields_save_custom ) ) {
return;
}
foreach ( $this->meta_fields_save_custom as $object_type => $sub_types ) {
switch ( $object_type ) {
case 'post':
foreach ( $sub_types as $post_type => $fields ) {
add_action( "save_post_{$post_type}", array( $this, 'save_custom_values' ) );
}
break;
case 'tax':
case 'taxonomy':
foreach ( $sub_types as $tax => $fields ) {
add_action( "created_{$tax}", array( $this, 'save_custom_values' ) );
add_action( "edited_{$tax}", array( $this, 'save_custom_values' ) );
}
break;
case 'user':
add_action( 'edit_user_profile_update', array( $this, 'save_custom_values' ) );
add_action( 'personal_options_update', array( $this, 'save_custom_values' ) );
break;
}
}
}
/**
* Save custom values
*
* @param $id Object ID
*/
public function save_custom_values( $id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( empty( $_POST ) ) {
return;
}
$action = current_action();
if ( false !== strpos( $action, 'save_post_' ) ) {
$action = 'save_post';
} elseif ( false !== strpos( $action, 'created_' ) ) {
$action = 'created_term';
} elseif ( false !== strpos( $action, 'edited_' ) ) {
$action = 'edited_term';
}
if ( 'created_term' === $action ) {
if ( ! isset( $_POST['_wpnonce_add-tag'] ) ) {
return;
}
} else {
if ( ! isset( $_POST['_wpnonce'] ) ) {
return;
}
}
switch ( $action ) {
case 'save_post':
$object_type = 'post';
$sub_type = $_POST['post_type'];
if ( ! current_user_can( 'edit_post', $id ) ) {
return;
}
break;
case 'created_term':
case 'edited_term':
$object_type = 'taxonomy';
$sub_type = $_POST['taxonomy'];
if ( ! current_user_can( 'edit_term', $id ) ) {
return;
}
break;
case 'edit_user_profile_update':
case 'personal_options_update':
$object_type = $sub_type = 'user';
if ( ! current_user_can( 'edit_user', $id ) ) {
return;
}
break;
default:
$object_type = $sub_type = false;
}
if ( ! $object_type || ! $sub_type ) {
return;
}
$raw = $this->data->get_raw();
$update = false;
foreach ( $this->meta_fields_save_custom[ $object_type ][ $sub_type ] as $field => $field_args ) {
if ( ! isset( $_POST[ $field ] ) || '' === $_POST[ $field ] ) {
continue;
}
do_action( 'jet-engine/meta-boxes/save-custom-value', $field, $field_args );
$meta_box_item = $raw[ $field_args['meta_box_id'] ];
$meta_fields = $meta_box_item['meta_fields'];
$_meta_fields = $this->maybe_add_custom_values_to_options( $meta_fields, $field, $field_args );
if ( $_meta_fields ) {
$raw[ $field_args['meta_box_id'] ]['meta_fields'] = $_meta_fields;
$update = true;
}
}
if ( $update ) {
update_option( $this->data->option_name, $raw );
}
}
/**
* Maybe add custom values to options.
*
* @param $meta_fields
* @param $field
* @param $field_args
*
* @return mixed
*/
public function maybe_add_custom_values_to_options( $meta_fields, $field, $field_args ) {
$update_meta = false;
$meta_index = array_search( $field, array_column( $meta_fields, 'name' ) );
$meta_options = ! empty( $meta_fields[ $meta_index ]['options'] ) ?
array_column( $meta_fields[ $meta_index ]['options'], 'key' )
: array();
if ( ! isset( $meta_fields[ $meta_index ]['options'] ) ) {
$meta_fields[ $meta_index ]['options'] = array();
}
switch ( $field_args['type'] ) {
case 'checkbox':
$custom_values = array_diff( array_keys( $_POST[ $field ] ), $meta_options );
if ( ! empty( $custom_values ) ) {
foreach ( $custom_values as $custom_value ) {
$custom_item_value = filter_var( $_POST[ $field ][ $custom_value ], FILTER_VALIDATE_BOOLEAN );
if ( $custom_item_value ) {
$meta_fields[ $meta_index ]['options'][] = array(
'key' => esc_attr( $custom_value ),
'value' => esc_attr( $custom_value ),
'is_checked' => '',
);
$update_meta = true;
}
}
}
break;
case 'radio':
$custom_value = ! in_array( $_POST[ $field ], $meta_options ) ? $_POST[ $field ] : false;
if ( ! Jet_Engine_Tools::is_empty( $custom_value ) ) {
$meta_fields[ $meta_index ]['options'][] = array(
'key' => esc_attr( $custom_value ),
'value' => esc_attr( $custom_value ),
'is_checked' => '',
);
$update_meta = true;
}
break;
}
if ( ! $update_meta ) {
return false;
}
return $meta_fields;
}
/**
* Try to get current post ID from request
*
* @return [type] [description]
*/
public function get_post_id() {
$post_id = isset( $_GET['post'] ) ? $_GET['post'] : false;
if ( ! $post_id && isset( $_REQUEST['post_ID'] ) ) {
$post_id = $_REQUEST['post_ID'];
}
return $post_id;
}
/**
* Return fields list registered for users
*
* @return [type] [description]
*/
public function store_default_user_meta_fields() {
$this->store_fields(
__( 'Default user fields', 'jet-engine' ),
array(
array(
'name' => 'first_name',
'title' => __( 'First Name', 'jet-enegine' ),
'type' => 'text',
),
array(
'name' => 'last_name',
'title' => __( 'Last Name', 'jet-enegine' ),
'type' => 'text',
),
array(
'name' => 'description',
'title' => __( 'Biographical Info', 'jet-enegine' ),
'type' => 'text',
),
)
);
}
/**
* Return list of meta fields for post type
*
* @param string $object [description]
* @return [type] [description]
*/
public function get_meta_fields_for_object( $object = 'post' ) {
if ( isset( $this->meta_fields[ $object ] ) ) {
return $this->meta_fields[ $object ];
} else {
return array();
}
}
/**
* Returns all registered options (or depends on context) to use in select
*
* @return [type] [description]
*/
public function get_fields_for_select( $context = 'plain', $where = 'elementor', $for = 'all' ) {
$result = array();
$post_types = get_post_types( array(), 'objects' );
$taxonomies = get_taxonomies( array(), 'objects' );
foreach ( $this->meta_fields as $object => $fields ) {
$group_label = false;
if ( isset( $post_types[ $object ] ) ) {
if ( ! in_array( $for, array( 'all', 'posts' ) ) ) {
continue;
}
$group_label = $post_types[ $object ]->labels->name;
} elseif ( isset( $taxonomies[ $object ] ) ) {
if ( ! in_array( $for, array( 'all', 'taxonomies' ) ) ) {
continue;
}
$group_label = $taxonomies[ $object ]->labels->name;
} else {
if ( ! in_array( $for, array( 'all', 'user' ) ) ) {
continue;
}
$group_label = $object;
}
if ( ! $group_label ) {
continue;
}
$group = array();
$blocks_group = array();
foreach ( $fields as $field_data ) {
if ( ! empty( $field_data['object_type'] ) && 'field' !== $field_data['object_type'] ) {
continue;
}
if ( 'html' === $field_data['type'] ) {
continue;
}
$name = $field_data['name'];
$title = ! empty( $field_data['title'] ) ? $field_data['title'] : $name;
switch ( $context ) {
case 'all':
$group[ $name ] = $title;
$blocks_group[] = array(
'value' => $name,
'label' => $title,
);
break;
case 'plain':
if ( 'repeater' !== $field_data['type'] ) {
$group[ $name ] = $title;
$blocks_group[] = array(
'value' => $name,
'label' => $title,
);
}
break;
case 'repeater':
if ( 'repeater' === $field_data['type'] ) {
$group[ $name ] = $title;
$blocks_group[] = array(
'value' => $name,
'label' => $title,
);
}
break;
case 'media':
if ( 'media' === $field_data['type'] ) {
$group[ $name ] = $title;
$blocks_group[] = array(
'value' => $name,
'label' => $title,
);
}
break;
case 'gallery':
if ( 'gallery' === $field_data['type'] ) {
$group[ $name ] = $title;
$blocks_group[] = array(
'value' => $name,
'label' => $title,
);
}
break;
}
}
if ( ! empty( $group ) ) {
if ( 'blocks' === $where ) {
$result[] = array(
'label' => $group_label,
'values' => $blocks_group,
);
} else {
$result[] = array(
'label' => $group_label,
'options' => $group,
);
}
}
}
if ( 'elementor' === $where ) {
$result = array( '' => esc_html__( 'Select...', 'jet-engine' ) ) + $result;
}
return $result;
}
/**
* Return admin pages for current instance
*
* @return array
*/
public function get_instance_pages() {
$base_path = $this->component_path( 'pages/' );
return array(
'Jet_Engine_Meta_Boxes_Page_List' => $base_path . 'list.php',
'Jet_Engine_Meta_Boxes_Page_Edit' => $base_path . 'edit.php',
);
}
/**
* Returns current menu page title (for JetEngine submenu)
* @return [type] [description]
*/
public function get_page_title() {
return __( 'Meta Boxes', 'jet-engine' );
}
/**
* Returns current instance slug
*
* @return [type] [description]
*/
public function instance_slug() {
return 'meta';
}
/**
* Returns default config for add/edit page
*
* @param array $config [description]
* @return [type] [description]
*/
public function get_admin_page_config( $config = array() ) {
$default_settings = array(
'type' => 'text',
'width' => '100%',
);
$default = array(
'api_path_edit' => '', // Set individually for apropriate page
'api_path_get' => jet_engine()->api->get_route( 'get-meta-box' ),
'api_path_search' => jet_engine()->api->get_route( 'search-posts' ),
'edit_button_label' => '', // Set individually for apropriate page,
'item_id' => false,
'post_types' => Jet_Engine_Tools::get_post_types_for_js(),
'taxonomies' => Jet_Engine_Tools::get_taxonomies_for_js(),
'redirect' => '', // Set individually for apropriate page,
'general_settings' => array( 'object_type' => 'post' ),
'meta_fields' => array(),
'notices' => array(
'name' => __( 'Please, set meta box title', 'jet-engine' ),
'success' => __( 'Meta box updated', 'jet-engine' ),
),
);
return array_merge( $default, $config );
}
}
}