1 ) { $args = array(); @list( $args['from'], $args['to'], $args['reciprocal'] ) = $argv; } $defaults = array( 'from' => '', 'to' => '', 'fields' => array(), 'prevent_duplicates' => true, 'reciprocal' => false, 'title' => '', 'context' => 'side', 'box' => 'P2P_Box_Multiple', ); $args = wp_parse_args( $args, $defaults ); P2P_Connection_Types::register( $args ); } /** * Connect a post to one or more other posts. * * @param int|array $from The first end of the connection * @param int|array $to The second end of the connection * @param array $data additional data about the connection */ function p2p_connect( $from, $to, $data = array() ) { foreach ( (array) $from as $from ) { foreach ( (array) $to as $to ) { P2P_Connections::connect( $from, $to, $data ); } } } /** * Disconnect a post from or more other posts. * * @param int|array $from The first end of the connection * @param int|array|string $to The second end of the connection * @param array $data additional data about the connection to filter against */ function p2p_disconnect( $from, $to, $data = array() ) { foreach ( (array) $from as $from ) { foreach ( (array) $to as $to ) { P2P_Connections::disconnect( $from, $to, $data ); } } } /** * Get a list of connected posts. * * Low-level function. Use new WP_Query( array( 'connected' => $post_id ) ) instead. * * @param int $post_id One end of the connection * @param string $direction The direction of the connection. Can be 'to', 'from' or 'any' * @param array $data additional data about the connection to filter against * * @return array( p2p_id => post_id ) */ function p2p_get_connected( $post_id, $direction = 'any', $data = array() ) { return P2P_Connections::get( $post_id, $direction, $data ); } /** * See if a certain post is connected to another one * * @param int $from The first end of the connection * @param int $to The second end of the connection * @param array $data additional data about the connection to filter against * * @return bool True if the connection exists, false otherwise */ function p2p_is_connected( $from, $to, $data = array() ) { $ids = p2p_get_connected( $from, $to, $data ); return !empty( $ids ); } /** * Delete one or more connections * * @param int|array $p2p_id Connection ids * * @return int Number of connections deleted */ function p2p_delete_connection( $p2p_id ) { return P2P_Connections::delete( $p2p_id ); } /** * Optimized inner query, after the outer query was executed. * * Populates each of the outer querie's $post objects with a property containing a list of connected posts * * @param string $direction The direction of the connection. Can be 'to', 'from' or 'any' * @param string $prop_name The property name; will be prefixed with 'connected_' * @param string|array $args The query vars for the inner query * @param object $query (optional) The outer query. Defaults to the global $wp_query */ function p2p_each_connected( $direction, $prop_name, $search, $query = null ) { if ( is_null( $query ) ) $query = $GLOBALS['wp_query']; if ( empty( $query->posts ) ) return; if ( empty( $prop_name ) ) $prop_name = 'connected'; else $prop_name = 'connected_' . $prop_name; // re-index by ID $posts = array(); foreach ( $query->posts as $post ) { $post->$prop_name = array(); $posts[ $post->ID ] = $post; } // ignore other 'connected' query vars for the inner query foreach ( array_keys( P2P_Query::$qv_map ) as $qv ) unset( $search[ $qv ] ); if ( 'any' == $direction ) $key = 'connected'; else $key = 'connected_' . $direction; $search[ $key ] = array_keys( $posts ); $search[ 'suppress_filters' ] = false; foreach ( get_posts( $search ) as $inner_post ) { if ( $inner_post->ID == $inner_post->p2p_from ) $outer_post_id = $inner_post->p2p_to; elseif ( $inner_post->ID == $inner_post->p2p_to ) $outer_post_id = $inner_post->p2p_from; else throw new Exception( 'Corrupted data.' ); if ( $outer_post_id == $inner_post->ID ) throw new Exception( 'Post connected to itself.' ); array_push( $posts[ $outer_post_id ]->$prop_name, $inner_post ); } } // Allows you to write query_posts( array( 'connected' => 123 ) ); class P2P_Query { static $qv_map = array( 'connected' => 'any', 'connected_to' => 'to', 'connected_from' => 'from', ); function init() { new scbQueryManipulation( array( __CLASS__, 'query' ), false ); // 'posts_clauses' add_filter( 'the_posts', array( __CLASS__, 'the_posts' ), 11, 2 ); } function query( $clauses, $wp_query ) { global $wpdb; $found = self::find_qv( $wp_query ); if ( !$found ) return $clauses; list( $search, $key, $direction ) = $found; $clauses['fields'] .= ", $wpdb->p2p.*"; $clauses['join'] .= " INNER JOIN $wpdb->p2p"; if ( 'any' == $search ) { $search = false; } else { $search = implode( ',', array_map( 'absint', (array) $search ) ); } switch ( $direction ) { case 'from': $clauses['where'] .= " AND $wpdb->posts.ID = $wpdb->p2p.p2p_to"; if ( $search ) { $clauses['where'] .= " AND $wpdb->p2p.p2p_from IN ($search)"; } break; case 'to': $clauses['where'] .= " AND $wpdb->posts.ID = $wpdb->p2p.p2p_from"; if ( $search ) { $clauses['where'] .= " AND $wpdb->p2p.p2p_to IN ($search)"; } break; case 'any': if ( $search ) { $clauses['where'] .= " AND ( ($wpdb->posts.ID = $wpdb->p2p.p2p_to AND $wpdb->p2p.p2p_from IN ($search) ) OR ($wpdb->posts.ID = $wpdb->p2p.p2p_from AND $wpdb->p2p.p2p_to IN ($search) ) )"; } else { $clauses['where'] .= " AND ($wpdb->posts.ID = $wpdb->p2p.p2p_to OR $wpdb->posts.ID = $wpdb->p2p.p2p_from)"; } break; } $connected_meta = $wp_query->get( 'connected_meta' ); if ( !empty( $connected_meta ) ) { $meta_clauses = _p2p_meta_sql_helper( $connected_meta ); foreach ( $meta_clauses as $key => $value ) { $clauses[ $key ] .= $value; } } return $clauses; } function the_posts( $the_posts, $wp_query ) { if ( empty( $the_posts ) ) return $the_posts; $found = self::find_qv( $wp_query, 'each_' ); if ( !$found ) return $the_posts; list( $search, $qv, $direction ) = $found; $qv = explode('_', $qv); $key = isset( $qv[1] ) ? $qv[1] : ''; p2p_each_connected( $direction, $key, $search, $wp_query ); return $the_posts; } private function find_qv( $wp_query, $prefix = '' ) { foreach ( self::$qv_map as $qv => $direction ) { $search = $wp_query->get( $prefix . $qv ); if ( !empty( $search ) ) break; } if ( empty( $search ) ) return false; return array( $search, $qv, $direction ); } }