failure, P2P_Directed_Connection_Type instance or direction on success.
*/
public function find_direction( $arg, $instantiate = true, $object_type = null ) {
if ( $object_type ) {
$direction = $this->direction_from_object_type( $object_type );
if ( !$direction )
return false;
if ( in_array( $direction, array( 'from', 'to' ) ) )
return $this->set_direction( $direction, $instantiate );
}
$r = $this->direction_from_item( $arg );
if ( !$r )
return false;
list( $direction, $item ) = $r;
return $this->set_direction( $direction, $instantiate );
}
protected function direction_from_item( $arg ) {
if ( is_array( $arg ) )
$arg = reset( $arg );
foreach ( array( 'from', 'to' ) as $direction ) {
$item = $this->side[ $direction ]->item_recognize( $arg );
if ( !$item )
continue;
return array( $this->strategy->choose_direction( $direction ), $item );
}
return false;
}
protected function direction_from_object_type( $current ) {
$from = $this->side['from']->get_object_type();
$to = $this->side['to']->get_object_type();
if ( $from == $to && $current == $from )
return 'any';
if ( $current == $from )
return 'to';
if ( $current == $to )
return 'from';
return false;
}
public function direction_from_types( $object_type, $post_types = null ) {
foreach ( array( 'from', 'to' ) as $direction ) {
if ( !$this->_type_check( $direction, $object_type, $post_types ) )
continue;
return $this->strategy->choose_direction( $direction );
}
return false;
}
private function _type_check( $direction, $object_type, $post_types ) {
if ( $object_type != $this->side[ $direction ]->get_object_type() )
return false;
$side = $this->side[ $direction ];
if ( !method_exists( $side, 'recognize_post_type' ) )
return true;
foreach ( (array) $post_types as $post_type ) {
if ( $side->recognize_post_type( $post_type ) ) {
return true;
}
}
return false;
}
/** Alias for get_prev() */
public function get_previous( $from, $to ) {
return $this->get_prev( $from, $to );
}
/**
* Get the previous post in an ordered connection.
*
* @param int The first end of the connection.
* @param int The second end of the connection.
*
* @return bool|object False on failure, post object on success
*/
public function get_prev( $from, $to ) {
return $this->get_adjacent( $from, $to, -1 );
}
/**
* Get the next post in an ordered connection.
*
* @param int The first end of the connection.
* @param int The second end of the connection.
*
* @return bool|object False on failure, post object on success
*/
public function get_next( $from, $to ) {
return $this->get_adjacent( $from, $to, +1 );
}
/**
* Get another post in an ordered connection.
*
* @param int The first end of the connection.
* @param int The second end of the connection.
* @param int The position relative to the first parameter
*
* @return bool|object False on failure, post object on success
*/
public function get_adjacent( $from, $to, $which ) {
// The direction needs to be based on the second parameter,
// so that it's consistent with $this->connect( $from, $to ) etc.
$r = $this->direction_from_item( $to );
if ( !$r )
return false;
list( $direction, $to ) = $r;
$directed = $this->set_direction( $direction );
$key = $directed->get_orderby_key();
if ( !$key )
return false;
$p2p_id = $directed->get_p2p_id( $to, $from );
if ( !$p2p_id )
return false;
$order = (int) p2p_get_meta( $p2p_id, $key, true );
$adjacent = $directed->get_connected( $to, array(
'connected_meta' => array(
array(
'key' => $key,
'value' => $order + $which
)
)
), 'abstract' );
if ( empty( $adjacent->items ) )
return false;
$item = reset( $adjacent->items );
return $item->get_object();
}
/**
* Get the previous, next and parent items, in an ordered connection type.
*
* @param mixed The current item
*
* @return bool|array False if the connections aren't sortable,
* associative array otherwise:
* array(
* 'parent' => bool|object
* 'previous' => bool|object
* 'next' => bool|object
* )
*/
public function get_adjacent_items( $item ) {
$result = array(
'parent' => false,
'previous' => false,
'next' => false,
);
$r = $this->direction_from_item( $item );
if ( !$r )
return false;
list( $direction, $item ) = $r;
$connected_series = $this->set_direction( $direction )->get_connected( $item,
array(), 'abstract' )->items;
if ( empty( $connected_series ) )
return $r;
if ( count( $connected_series ) > 1 ) {
trigger_error( 'More than one connected parents found.', E_USER_WARNING );
}
$parent = $connected_series[0];
$result['parent'] = $parent->get_object();
$result['previous'] = $this->get_previous( $item->ID, $parent->ID );
$result['next'] = $this->get_next( $item, $parent );
return $result;
}
/**
* Optimized inner query, after the outer query was executed.
*
* Populates each of the outer querie's $post objects with a 'connected' property, containing a list of connected posts
*
* @param object|array $items WP_Query instance or list of post objects
* @param string|array $extra_qv Additional query vars for the inner query.
* @param string $prop_name The name of the property used to store the list of connected items on each post object.
*/
public function each_connected( $items, $extra_qv = array(), $prop_name = 'connected' ) {
if ( is_a( $items, 'WP_Query' ) )
$items =& $items->posts;
if ( empty( $items ) || !is_object( $items[0] ) )
return;
$post_types = array_unique( wp_list_pluck( $items, 'post_type' ) );
if ( count( $post_types ) > 1 ) {
$extra_qv['post_type'] = 'any';
}
$possible_directions = array();
foreach ( array( 'from', 'to' ) as $direction ) {
$side = $this->side[ $direction ];
if ( 'post' == $side->get_object_type() ) {
foreach ( $post_types as $post_type ) {
if ( $side->recognize_post_type( $post_type ) ) {
$possible_directions[] = $direction;
}
}
}
}
$direction = _p2p_compress_direction( $possible_directions );
if ( !$direction )
return false;
$directed = $this->set_direction( $direction );
// ignore pagination
foreach ( array( 'showposts', 'posts_per_page', 'posts_per_archive_page' ) as $disabled_qv ) {
if ( isset( $extra_qv[ $disabled_qv ] ) ) {
trigger_error( "Can't use '$disabled_qv' in an inner query", E_USER_WARNING );
}
}
$extra_qv['nopaging'] = true;
$q = $directed->get_connected( $items, $extra_qv, 'abstract' );
$raw_connected = array();
foreach ( $q->items as $item )
$raw_connected[] = $item->get_object();
p2p_distribute_connected( $items, $raw_connected, $prop_name );
}
public function get_desc() {
$desc = array();
foreach ( array( 'from', 'to' ) as $key ) {
$desc[ $key ] = $this->side[ $key ]->get_desc();
}
$label = sprintf( '%s %s %s', $desc['from'], $this->strategy->get_arrow(), $desc['to'] );
$title = $this->get_field( 'title', 'from' );
if ( $title )
$label .= " ($title)";
return $label;
}
}