Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

jsarnowski / jsarnowski/jet-engine   php

Repository URL to install this package:

Version: 2.7.7 

/ components / relations / manager.php

<?php
/**
 * Relations manager
 */

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

if ( ! class_exists( 'Jet_Engine_Relations' ) ) {

	/**
	 * Define Jet_Engine_Relations class
	 */
	class Jet_Engine_Relations extends Jet_Engine_Base_WP_Intance {

		/**
		 * Base slug for CPT-related pages
		 * @var string
		 */
		public $page = 'jet-engine-relations';

		/**
		 * Action request key
		 *
		 * @var string
		 */
		public $action_key = 'cpt_relation_action';

		/**
		 * Set object type
		 * @var string
		 */
		public $object_type = '';

		public $hierarchy = null;

		private $_active_relations         = array();
		private $_relations_for_post_types = array();

		/**
		 * Constructor for the class
		 */
		function __construct() {

			add_action( 'admin_menu', array( $this, 'add_menu_page' ), 20 );
			add_action( 'init', array( $this, 'register_instances' ), 11 );

			$this->init_data();

			add_action( 'jet-engine/rest-api/init-endpoints', array( $this, 'init_rest' ) );
			add_action( 'admin_enqueue_scripts', array( $this, 'relations_box_assets' ), 10 );

			require_once $this->component_path( 'hierarchy.php' );
			$this->hierarchy = new Jet_Engine_Relations_Hierarchy();

			if ( ! $this->is_cpt_page() ) {
				return;
			}

			add_action( 'admin_init', array( $this, 'register_pages' ) );
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ), 0 );
			add_action( 'admin_init', array( $this, 'handle_actions' ) );

		}

		/**
		 * Enqueue relations assets to posts edit screen
		 *
		 * @param  [type] $hook [description]
		 * @return [type]       [description]
		 */
		public function relations_box_assets( $hook ) {

			if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ) ) ) {
				return;
			}

			wp_enqueue_style(
				'jet-engine-relations',
				jet_engine()->plugin_url( 'assets/css/admin/relations.css' ),
				array(),
				jet_engine()->get_version()
			);

		}

		/**
		 * 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-relation.php' );
			require_once $this->component_path( 'rest-api/edit-relation.php' );
			require_once $this->component_path( 'rest-api/get-relation.php' );
			require_once $this->component_path( 'rest-api/delete-relation.php' );
			require_once $this->component_path( 'rest-api/get-relations.php' );

			$api_manager->register_endpoint( new Jet_Engine_CPT_Rest_Add_Relation() );
			$api_manager->register_endpoint( new Jet_Engine_CPT_Rest_Edit_Relation() );
			$api_manager->register_endpoint( new Jet_Engine_CPT_Rest_Get_Relation() );
			$api_manager->register_endpoint( new Jet_Engine_CPT_Rest_Delete_Relation() );
			$api_manager->register_endpoint( new Jet_Engine_CPT_Rest_Get_Relations() );

		}

		/**
		 * Return allowed relations types
		 *
		 * @return array
		 */
		public function get_relations_types() {

			return array(
				'one_to_one'   => __( 'One to one', 'jet-engine' ),
				'one_to_many'  => __( 'One to many', 'jet-engine' ),
				'many_to_many' => __( 'Many to many', 'jet-engine' ),
			);

		}

		/**
		 * Returns allowed relations types prepared to use in JS formst
		 *
		 * @return [type] [description]
		 */
		public function get_relations_types_for_js() {

			$result = array();

			foreach ( $this->get_relations_types() as $value => $label ) {
				$result[] = array(
					'value' => $value,
					'label' => $label,
				);
			}

			return $result;
		}

		/**
		 * 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/relations/' . $path_inside_component );
		}

		/**
		 * Init data instance
		 *
		 * @return [type] [description]
		 */
		public function init_data() {
			require $this->component_path( 'data.php' );
			$this->data = new Jet_Engine_Relations_Data( $this );
		}

		/**
		 * Returns unique relation name for post types pair
		 *
		 * @param  [type] $post_type_1 [description]
		 * @param  [type] $post_type_2 [description]
		 * @return [type]              [description]
		 */
		public function get_relation_hash( $post_type_1, $post_type_2 ) {
			$hash = md5( $post_type_1 . $post_type_2 );
			return 'relation_' . $hash;
		}

		/**
		 * Register relations meta boxes
		 *
		 * @return void
		 */
		public function register_instances() {

			$relations     = $this->data->get_raw();
			$has_hierarchy = false;

			$relations = apply_filters( 'jet-engine/relations/registered-relation', $relations );

			if ( empty( $relations ) ) {
				return;
			}

			foreach ( $relations as $relation ) {

				$post_type_1 = $relation['post_type_1'];
				$post_type_2 = $relation['post_type_2'];
				$type        = explode( '_to_', $relation['type'] );
				$type_1      = $type[0];
				$type_2      = $type[1];
				$meta_key    = $this->get_relation_hash( $post_type_1, $post_type_2 );
				$control_1   = isset( $relation['post_type_1_control'] ) ? $relation['post_type_1_control'] : 'true';
				$control_2   = isset( $relation['post_type_2_control'] ) ? $relation['post_type_2_control'] : 'true';
				$control_1   = filter_var( $control_1, FILTER_VALIDATE_BOOLEAN );
				$control_2   = filter_var( $control_2, FILTER_VALIDATE_BOOLEAN );

				// Allow single relation for post type 1 - post type 2 pair
				if ( ! empty( $this->_active_relations[ $meta_key ] ) ) {
					continue;
				}

				if ( ! class_exists( 'Jet_Engine_CPT_Meta' ) ) {
					require_once jet_engine()->plugin_path( 'includes/components/meta-boxes/post.php' );
				}

				$obj_1 = get_post_type_object( $post_type_1 );
				$obj_2 = get_post_type_object( $post_type_2 );

				if ( ! $obj_1 || ! $obj_2 ) {
					continue;
				}

				if ( is_admin() ) {

					$title_1 = sprintf( __( 'Related %s', 'jet-engine' ), $obj_2->labels->name );
					$title_2 = sprintf( __( 'Related %s', 'jet-engine' ), $obj_1->labels->name );

					if ( $control_1 ) {

						if ( 'one' === $type_1 && 'many' === $type_2 ) {
							$multiple_1 = 'true';
						} elseif ( 'many' === $type_1 ) {
							$multiple_1 = 'true';
						} else {
							$multiple_1 = 'false';
						}

						$meta_field_1 = array(
							'name'             => $meta_key,
							'type'             => 'posts',
							'element'          => 'control',
							'title'            => sprintf( __( 'Select %s', 'jet-engine' ), $obj_2->labels->name ),
							'is_multiple'      => $multiple_1,
							'search_post_type' => $post_type_2,
							'description'      => sprintf( __( 'Set Child %s', 'jet-engine' ), $obj_2->labels->name ),
						);

						new Jet_Engine_CPT_Meta( $post_type_1, array( $meta_field_1 ), $title_1, 'side', 'default' );

						if ( jet_engine()->meta_boxes ) {
							$meta_field_1['title'] = $title_1;
							jet_engine()->meta_boxes->store_fields( $post_type_1, array( $meta_field_1 ) );
						}

					}

					if ( $control_2 ) {

						if ( 'one' === $type_1 && 'many' === $type_2 ) {
							$multiple_2 = 'false';
						} elseif ( 'many' === $type_2 ) {
							$multiple_2 = 'true';
						} else {
							$multiple_2 = 'false';
						}

						$meta_field_2 = array(
							'name'             => $meta_key,
							'type'             => 'posts',
							'element'          => 'control',
							'title'            => sprintf( __( 'Select %s', 'jet-engine' ), $obj_1->labels->name ),
							'is_multiple'      => $multiple_2,
							'search_post_type' => $post_type_1,
							'description'      => sprintf( __( 'Set Parent %s', 'jet-engine' ), $obj_1->labels->name ),
						);

						new Jet_Engine_CPT_Meta( $post_type_2, array( $meta_field_2 ), $title_2, 'side', 'default' );

						if ( jet_engine()->meta_boxes ) {
							$meta_field_2['title'] = $title_2;
							jet_engine()->meta_boxes->store_fields( $post_type_2, array( $meta_field_2 ) );
						}

					}

				}

				$relation['label_1'] = $obj_1->labels->name;
				$relation['label_2'] = $obj_2->labels->name;

				$this->add_relation_to_post_types( $meta_key, $relation );

				$this->_active_relations[ $meta_key ] = $relation;

				if ( ! empty( $relation['parent_relation'] ) ) {
					$has_hierarchy = true;
				}

				add_filter( 'cx_post_meta/pre_process_key/' . $meta_key, array( $this, 'process_meta' ), 10, 3 );
				add_filter( 'cx_post_meta/pre_get_meta/' . $meta_key, array( $this, 'get_meta' ), 10, 5 );

			}

			if ( $has_hierarchy ) {
				$this->hierarchy->create_hierarchy( $this->_active_relations );
			}

		}

		/**
		 * Store relation meta keys for post type
		 *
		 * @param string $meta_key [description]
		 * @param array  $relation [description]
		 */
		public function add_relation_to_post_types( $meta_key = null, $relation = array() ) {

			$post_type_1 = $relation['post_type_1'];
			$label_1     = $relation['label_1'];
			$post_type_2 = $relation['post_type_2'];
			$label_2     = $relation['label_2'];

			if ( ! isset( $this->_relations_for_post_types[ $post_type_1 ] ) ) {
				$this->_relations_for_post_types[ $post_type_1 ] = array();
			}

			if ( ! isset( $this->_relations_for_post_types[ $post_type_2 ] ) ) {
				$this->_relations_for_post_types[ $post_type_2 ] = array();
			}

			$this->_relations_for_post_types[ $post_type_1 ][ $meta_key ] = array(
				'title' => sprintf( __( 'Child %s', 'jet-engine' ), $label_2 ),
				'type'  => 'select',
				'name'  => $meta_key,
			);

			$this->_relations_for_post_types[ $post_type_2 ][ $meta_key ] = array(
				'title' => sprintf( __( 'Parent %s', 'jet-engine' ), $label_1 ),
				'type'  => 'select',
				'name'  => $meta_key,
			);

		}

		/**
		 * Get values for relations meta fields early
		 *
		 * @param  [type] $result  [description]
		 * @param  [type] $post    [description]
		 * @param  [type] $key     [description]
		 * @param  [type] $default [description]
		 * @param  [type] $field   [description]
		 * @return [type]          [description]
		 */
		public function get_meta( $result, $post, $key, $default, $field ) {

			$relation = isset( $this->_active_relations[ $key ] ) ? $this->_active_relations[ $key ] : false;

			if ( ! $relation ) {
				return $result;
			}

			$meta = get_post_meta( $post->ID, $key, false );
			$meta = array_filter( $meta );
			$meta = array_values( $meta );

			if ( ! isset( $field['multiple'] ) || ! $field['multiple'] ) {
				$meta = isset( $meta[0] ) ? $meta[0] : null;
			}

			if ( ! empty( $meta ) ) {
				return $meta;
			} else {
				return null;
			}

		}

		/**
		 * Check if is relation meta key
		 *
		 * @param  [type]  $meta_key [description]
		 * @return boolean           [description]
		 */
		public function is_relation_key( $meta_key = null ) {
			return isset( $this->_active_relations[ $meta_key ] );
		}

		/**
		 * Synchronize realted meta on post save
		 *
		 * @return void
		 */
		public function process_meta( $result, $post_id, $meta_key, $related_posts = array() ) {

			$relation = isset( $this->_active_relations[ $meta_key ] ) ? $this->_active_relations[ $meta_key ] : false;

			if ( ! $relation ) {
				return $result;
			}

			if ( empty( $related_posts ) ) {
				$related_posts = ! empty( $_POST[ $meta_key ] ) ? $_POST[ $meta_key ] : false;
			}

			if ( empty( $related_posts ) ) {
				$this->data->delete_all_related_meta( $meta_key, $post_id );
			}

			if ( ! is_array( $related_posts ) ) {
				$related_posts = array( $related_posts );
			}

			$prev_related    = get_post_meta( $post_id, $meta_key );
			$saved_post_type = get_post_type( $post_id );
			$type            = explode( '_to_', $relation['type'] );

			if ( $relation['post_type_1'] === $saved_post_type ) {
				$current_type = $type[0];
				$related_type = $type[1];
			} elseif ( $relation['post_type_2'] === $saved_post_type ) {
				$current_type = $type[1];
				$related_type = $type[0];
			} else {
				return $result;
			}

			$result    = true;
			$to_delete = array_diff( $prev_related, $related_posts );
			$to_delete = array_filter( $to_delete );

			if ( ! empty( $to_delete ) ) {
				foreach ( $to_delete as $delete_post_id ) {
					delete_post_meta( $delete_post_id, $meta_key, $post_id );
					delete_post_meta( $post_id, $meta_key, $delete_post_id );
				}
			}

			foreach ( $related_posts as $related_post_id ) {

				if ( $related_post_id && ! in_array( $related_post_id, $prev_related ) ) {
					add_post_meta( $post_id, $meta_key, $related_post_id, false );
				}

				$stored = get_post_meta( $related_post_id, $meta_key, false );

				if ( ! is_array( $stored ) ) {
					$stored = array( $stored );
					$stored = array_filter( $stored );
				}

				if ( 'one' === $current_type ) {
					foreach ( $stored as $stored_id ) {
						if ( absint( $stored_id ) !== $post_id ) {
							delete_post_meta( $related_post_id, $meta_key );
							delete_post_meta( $stored_id, $meta_key, $related_post_id );
						}
					}
				}

				if ( $post_id && ! in_array( $post_id, $stored ) ) {
					add_post_meta( $related_post_id, $meta_key, $post_id, false );
				}

			}

			return $result;

		}

		/**
		 * Returns relation meta keys for passed post type
		 *
		 * @param  string $post_type Post type name
		 * @return array
		 */
		public function get_relation_fields_for_post_type( $post_type = null ) {

			$default = array();

			if ( ! $post_type ) {
				return $default;
			}

			if ( empty( $this->_relations_for_post_types ) ) {
				return $default;
			}

			if ( empty( $this->_relations_for_post_types[ $post_type ] ) ) {
				return $default;
			}

			return $this->_relations_for_post_types[ $post_type ];

		}

		/**
		 * Returns info about relationby hash
		 */
		public function get_relation_info( $key ) {
			return isset( $this->_active_relations[ $key ] ) ? $this->_active_relations[ $key ] : false;
		}

		/**
		 * Returns related posts
		 *
		 * @return void
		 */
		public function get_related_posts( $args = array() ) {

			$post_type_1 = isset( $args['post_type_1'] ) ? $args['post_type_1'] : false;
			$post_type_2 = isset( $args['post_type_2'] ) ? $args['post_type_2'] : false;
			$hash        = isset( $args['hash'] ) ? $args['hash'] : false;

			if ( $hash ) {
				$meta_key = $hash;
				$relation = isset( $this->_active_relations[ $meta_key ] ) ? $this->_active_relations[ $meta_key ] : false;

				if ( ! $relation ) {
					return false;
				}

				$post_type_1 = $relation['post_type_1'];
				$post_type_2 = $relation['post_type_2'];

				$current = ! empty( $args['current'] ) ? $args['current'] : false;

				if ( $current ) {
					$args['from'] = ( $post_type_1 === $current ) ? $post_type_2 : $post_type_1;
				}

			} else {

				if ( ! $post_type_1 || ! $post_type_2 ) {
					return false;
				}

				$meta_key = $this->get_relation_hash( $post_type_1, $post_type_2 );
				$relation = isset( $this->_active_relations[ $meta_key ] ) ? $this->_active_relations[ $meta_key ] : false;
			}

			if ( ! $relation ) {
				return false;
			}

			$post_id = isset( $args['post_id'] ) ? $args['post_id'] : get_the_ID();
			$type    = explode( '_to_', $relation['type'] );
			$from    = isset( $args['from'] ) ? $args['from'] : $post_type_1;

			if ( $post_type_1 === $from ) {
				$type = $type[0];
			} else {
				$type = $type[1];
			}

			if ( 'one' === $type ) {
				$single = true;
			} else {
				$single = false;
			}

			$meta = get_post_meta( $post_id, $meta_key, $single );
			$meta = apply_filters( 'jet-engine/relations/get_related_posts', $meta );

			return $meta;

		}

		/**
		 * Return admin pages for current instance
		 *
		 * @return array
		 */
		public function get_instance_pages() {

			$base_path = $this->component_path( 'pages/' );

			return array(
				'Jet_Engine_Relations_Page_List' => $base_path . 'list.php',
				'Jet_Engine_Relations_Page_Edit' => $base_path . 'edit.php',
			);
		}

		/**
		 * Returns current menu page title (for JetEngine submenu)
		 * @return [type] [description]
		 */
		public function get_page_title() {
			return __( 'Relations', 'jet-engine' );
		}

		/**
		 * Returns current instance slug
		 *
		 * @return [type] [description]
		 */
		public function instance_slug() {
			return 'relations';
		}

		/**
		 * Returns default config for add/edit page
		 *
		 * @param  array  $config [description]
		 * @return [type]         [description]
		 */
		public function get_admin_page_config( $config = array() ) {

			$default = array(
				'api_path_edit'       => '', // Should be set for apropriate page context
				'api_path_get'        => jet_engine()->api->get_route( 'get-relation' ),
				'edit_button_label'   => '', // Should be set for apropriate page context
				'item_id'             => false,
				'redirect'            => '', // Should be set for apropriate page context
				'general_settings'    => array(
					'name'        => '',
					'post_type_1' => 'post',
					'post_type_2' => 'page',
					'type'        => 'one_to_one',
				),
				'advanced_settings'   => array(
					'post_type_1_control' => true,
					'post_type_2_control' => true,
				),
				'post_types'          => Jet_Engine_Tools::get_post_types_for_js(),
				'relations_types'     => $this->get_relations_types_for_js(),
				'notices'             => array(
					'success' => __( 'Relationship updated', 'jet-engine' ),
				),
			);

			return array_merge( $default, $config );

		}

	}

}