function wordlift_ajax_related_posts($http_raw_data = null)
{
    // Extract filtering conditions
    if (!isset($_GET["post_id"]) || !is_numeric($_GET["post_id"])) {
        wp_die('Post id missing or invalid!');
        return;
    }
    $post_id = $_GET["post_id"];
    // Get the current post
    $post = get_post($post_id);
    wl_write_log("Going to find posts related to current with post id: {$post_id} ...");
    // Extract filtering conditions
    $filtering_entity_uris = null == $http_raw_data ? file_get_contents("php://input") : $http_raw_data;
    $filtering_entity_uris = json_decode($filtering_entity_uris);
    $filtering_entity_ids = wl_get_entity_post_ids_by_uris($filtering_entity_uris);
    $related_posts = array();
    // If the current post is an antity
    // related posts to the current entity are returned
    if (Wordlift_Entity_Service::TYPE_NAME == $post->post_type) {
        $filtering_entity_ids = array($post_id);
    }
    if (!empty($filtering_entity_ids)) {
        $related_posts = wl_core_get_posts(array('get' => 'posts', 'related_to__in' => $filtering_entity_ids, 'post__not_in' => array($post_id), 'post_type' => 'post', 'post_status' => 'publish', 'as' => 'subject'));
        foreach ($related_posts as $post_obj) {
            $thumbnail = wp_get_attachment_url(get_post_thumbnail_id($post_obj->ID, 'thumbnail'));
            $post_obj->thumbnail = $thumbnail ? $thumbnail : WL_DEFAULT_THUMBNAIL_PATH;
            $post_obj->link = get_edit_post_link($post_obj->ID, 'none');
            $post_obj->permalink = get_post_permalink($post_obj->ID);
        }
    }
    wl_core_send_json($related_posts);
}
/**
* Find all posts related to a given $object_id
* If $predicate is omitted, $predicate filter is not applied 
* Not use it directly. Use wl_core_get_related_posts or wl_core_get_related_posts_ids instead.
*
* @param int $object_id The entity ID or the post ID.
* @param string $predicate Name of the relation: null | 'what' | 'where' | 'when' | 'who'
* @param string $post_status Filter by post status null | 'publish' | 'draft' | 'pending' | 'trash'. null means *any* post status
*
* @return (array) Array of objects.
*/
function wl_core_inner_get_related_posts($get, $item_id, $predicate = null, $post_status = null)
{
    // Retrieve the post object
    $post = get_post($item_id);
    if (null === $post) {
        return array();
    }
    if ("entity" === $post->post_type) {
        if ($results = wl_core_get_posts(array('get' => $get, 'post_type' => 'post', 'post_status' => $post_status, 'related_to' => $item_id, 'as' => 'subject', 'with_predicate' => $predicate))) {
            return $results;
        }
    } else {
        if ($results = wl_core_get_posts(array('get' => $get, 'post_type' => 'post', 'post_status' => $post_status, 'post__not_in' => array($item_id), 'related_to__in' => wl_core_get_related_entity_ids($post->ID), 'as' => 'subject', 'with_predicate' => $predicate))) {
            return $results;
        }
    }
    // If wl_core_get_posts return false then an empty array is returned
    return array();
}
function wl_shortcode_faceted_search_ajax($http_raw_data = null)
{
    // Entity ID must be defined
    if (!isset($_GET['entity_id'])) {
        wp_die('No entity_id given');
        return;
    }
    $entity_id = $_GET['entity_id'];
    // If the current post is not an entity post an exception needs to be raised
    $entity = get_post($entity_id);
    if (Wordlift_Entity_Service::TYPE_NAME !== $entity->post_type) {
        wp_die('Faceted search supports only entity posts');
        return;
    }
    // Which type was requested?
    if (isset($_GET['type'])) {
        $required_type = $_GET['type'];
    } else {
        $required_type = null;
    }
    // Extract filtering conditions
    $filtering_entity_uris = null == $http_raw_data ? file_get_contents("php://input") : $http_raw_data;
    $filtering_entity_uris = json_decode($filtering_entity_uris);
    // Set up data structures
    $referencing_post_ids = wl_core_get_related_post_ids($entity_id, array('status' => 'publish'));
    $results = array();
    if ('posts' == $required_type) {
        // Required filtered posts.
        wl_write_log("Going to find related posts for the current entity [ entity ID :: {$entity_id} ]");
        if (empty($filtering_entity_uris)) {
            // No filter, just get referencing posts
            foreach ($referencing_post_ids as $post_obj_id) {
                $post_obj = get_post($post_obj_id);
                $thumbnail = wp_get_attachment_url(get_post_thumbnail_id($post_obj->ID, 'thumbnail'));
                $post_obj->thumbnail = $thumbnail ? $thumbnail : WL_DEFAULT_THUMBNAIL_PATH;
                $post_obj->permalink = get_post_permalink($post_obj->ID);
                $results[] = $post_obj;
            }
        } else {
            $filtering_entity_ids = wl_get_entity_post_ids_by_uris($filtering_entity_uris);
            // Search posts that reference all the filtering entities.
            $filtered_posts = wl_core_get_posts(array('get' => 'posts', 'post__in' => $referencing_post_ids, 'related_to__in' => $filtering_entity_ids, 'post_type' => 'post', 'as' => 'subject'));
            foreach ($filtered_posts as $post_obj) {
                $thumbnail = wp_get_attachment_url(get_post_thumbnail_id($post_obj->ID, 'thumbnail'));
                $post_obj->thumbnail = $thumbnail ? $thumbnail : WL_DEFAULT_THUMBNAIL_PATH;
                $post_obj->permalink = get_post_permalink($post_obj->ID);
                $results[] = $post_obj;
            }
            $results = $filtered_posts;
        }
    } else {
        global $wpdb;
        wl_write_log("Going to find related entities for the current entity [ entity ID :: {$entity_id} ]");
        // Retrieve Wordlift relation instances table name
        $table_name = wl_core_get_relation_instances_table_name();
        $ids = implode(',', $referencing_post_ids);
        // TODO - if an entity is related with different predicates each predicate impacts on counter
        $query = <<<EOF
            SELECT object_id as ID, count( object_id ) as counter 
            FROM {$table_name} 
            WHERE subject_id IN ({$ids}) and object_id != {$entity_id}
            GROUP BY object_id;
EOF;
        wl_write_log("Going to find related entities for the current entity [ entity ID :: {$entity_id} ] [ query :: {$query} ]");
        $entities = $wpdb->get_results($query, OBJECT);
        wl_write_log("Entities found " . count($entities));
        foreach ($entities as $obj) {
            $entity = get_post($obj->ID);
            $entity = wl_serialize_entity($entity);
            $entity['counter'] = $obj->counter;
            $results[] = $entity;
        }
    }
    wl_core_send_json($results);
}
 function testWlCoreGetPosts()
 {
     // Prepare interaction with db
     global $wpdb;
     $wl_table_name = wl_core_get_relation_instances_table_name();
     // Case 1 - :related_to missing
     $args = array();
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 2a - :related_to not numeric
     $args = array('get' => 'posts', 'related_to' => 'not-a-numeric-value', 'as' => 'subject', 'post_type' => 'post');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 2b - :related_to string representing a number
     $args = array('get' => 'post_ids', 'related_to' => '23', 'as' => 'subject', 'post_type' => 'post');
     $result = wl_core_get_posts($args);
     $this->assertInternalType('array', $result);
     // Case 3 - invalid :get
     $args = array('get' => 'pippo', 'related_to' => 3, 'as' => 'subject', 'post_type' => 'post');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 4 - invalid :as
     $args = array('get' => 'posts', 'related_to' => 3, 'as' => 'pippo', 'post_type' => 'post');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 5 - invalid :post_type
     $args = array('get' => 'posts', 'related_to' => 3, 'as' => 'subject', 'post_type' => 'pippo');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 6 - invalid :with_predicate
     $args = array('get' => 'posts', 'related_to' => 3, 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'pippo');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 7 - invalid :related_to__in -> empty array
     $args = array('get' => 'posts', 'related_to' => 6, 'related_to__in' => array(), 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'what');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 8 - invalid :related_to__in
     $args = array('get' => 'posts', 'related_to' => 5, 'related_to__in' => array('not-numeric-value'), 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'what');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 9 - invalid :related_to__in
     $args = array('get' => 'posts', 'related_to' => 4, 'related_to__in' => array('not-numeric-value', '13'), 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'what');
     $result = wl_core_get_posts($args);
     $this->assertInternalType("array", $result);
     // Case 10 - missing both :related_to and :related_to__in
     $args = array('get' => 'posts', 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'what');
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
     // Case 11 - just :related_to is set: it should be valid
     $args = array('get' => 'posts', 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'what', 'related_to' => 4);
     $result = wl_core_get_posts($args);
     $this->assertInternalType("array", $result);
     // Case 12 - just :related_to__in is set: it should be valid
     $args = array('get' => 'posts', 'as' => 'subject', 'post_type' => 'post', 'with_predicate' => 'what', 'related_to__in' => array(1, 2));
     $result = wl_core_get_posts($args);
     $this->assertInternalType("array", $result);
     // Case 13 - Ask a valid post status
     $args = array('get' => 'posts', 'as' => 'subject', 'post_type' => 'post', 'post_status' => 'draft', 'related_to' => 4);
     $result = wl_core_get_posts($args);
     $this->assertInternalType("array", $result);
     // Case 14 - Ask an invalid post status
     $args = array('get' => 'posts', 'as' => 'subject', 'post_type' => 'post', 'post_status' => 'pippo', 'related_to' => 4);
     $result = wl_core_get_posts($args);
     $this->assertFalse($result);
 }