public function html_input($default_entity_identifier)
    {
        // The entity can be referenced as URI or ID.
        if (is_numeric($default_entity_identifier)) {
            $entity = get_post($default_entity_identifier);
        } else {
            // It is an URI
            $entity = wl_get_entity_post_by_uri($default_entity_identifier);
        }
        if (!is_null($entity)) {
            $label = $entity->post_title;
            $value = $entity->ID;
        } else {
            // No ID and no internal uri. Just leave as is.
            $label = $default_entity_identifier;
            $value = $default_entity_identifier;
        }
        /*
         * Write saved value in page
         * The <input> tags host the meta value.
         * The visible <input> has the human readable value (i.e. entity name or uri)
         * and is accompained by an hidden <input> tag, passed to the server,
         * that contains the raw value (i.e. the uri or entity id).
         */
        $html = <<<EOF
\t\t\t<div class="wl-input-wrapper wl-autocomplete-wrapper">
\t\t\t\t<input type="text" class="{$this->meta_name} wl-autocomplete" value="{$label}" style="width:88%" />
\t\t\t\t<input type="hidden" class="{$this->meta_name}" name="wl_metaboxes[{$this->meta_name}][]" value="{$value}" />
\t\t\t\t<button class="button wl-remove-input wl-button" type="button" style="width:10%">Remove</button>
\t\t\t\t<div class="wl-input-notice"></div>
\t\t\t</div>
EOF;
        return $html;
    }
 function testFindByURI()
 {
     $entity_post_id = wl_create_post('', 'test_entity', 'Test Entity', 'draft', 'entity');
     $entity_uri = wl_get_entity_uri($entity_post_id);
     wl_schema_set_value($entity_post_id, 'sameAs', 'http://example.org/entity/test_entity');
     $same_as_array = wl_schema_get_value($entity_post_id, 'sameAs');
     $this->assertTrue(is_array($same_as_array));
     $this->assertEquals('http://example.org/entity/test_entity', $same_as_array[0]);
     wl_schema_set_value($entity_post_id, 'sameAs', array('http://example.org/entity/test_entity', 'http://data.example.org/entity/test_entity'));
     $same_as_array = wl_schema_get_value($entity_post_id, 'sameAs');
     $this->assertTrue(is_array($same_as_array));
     $this->assertEquals('http://example.org/entity/test_entity', $same_as_array[0]);
     $this->assertEquals('http://data.example.org/entity/test_entity', $same_as_array[1]);
     $post = wl_get_entity_post_by_uri('http://example.org/entity/test_entity');
     $this->assertNotNull($post);
     $post = wl_get_entity_post_by_uri('http://data.example.org/entity/test_entity');
     $this->assertNotNull($post);
     $same_as_uri = 'http://example.org/entity/test_entity2';
     $entity_post_id = wl_create_post('', 'test_entity_2', 'Test Entity 2', 'draft', 'entity');
     $entity_uri = wl_get_entity_uri($entity_post_id);
     wl_schema_set_value($entity_post_id, 'sameAs', $same_as_uri);
     $same_as_array = wl_schema_get_value($entity_post_id, 'sameAs');
     $this->assertTrue(is_array($same_as_array));
     $this->assertEquals($same_as_uri, $same_as_array[0]);
     $post = wl_get_entity_post_by_uri('http://example.org/entity/test_entity');
     $this->assertNotNull($post);
 }
 function testContentParsing()
 {
     // Create the sample entity for testing.
     $this->createSampleEntity();
     $content = '<span class="textannotation highlight organization disambiguated" id="urn:enhancement-16e9b0f6-e792-5b75-ffb7-ec40916d8753" itemid="http://dbpedia.org/resource/Honda" itemscope="itemscope" itemtype="organization">Honda</span> is recalling nearly 900,000 minivans for a defect that could increase fire risk.';
     $matches = array();
     if (0 < preg_match_all('/ itemid="([^"]+)"/im', $content, $matches, PREG_SET_ORDER)) {
         foreach ($matches as $match) {
             $item_id = $match[1];
             $post = wl_get_entity_post_by_uri($item_id);
             $this->assertNotNull($post);
             $uri = wl_get_entity_uri($post->ID);
             $this->assertNotNull($uri);
             $this->assertNotEquals($item_id, $uri);
         }
     }
     $this->assertTrue(0 < count($matches));
 }
    function testEntityMetadataAreProperlyUpdated()
    {
        $fake = $this->prepareFakeGlobalPostArrayFromFile('/assets/fake_global_post_array_with_one_entity_linked_as_what.json');
        $_POST = $fake;
        // Retrieve the entity uri (the first key in wl_entities associative aray)
        $original_entity_uri = current(array_keys($fake['wl_entities']));
        // Reference the entity to the post content
        $content = <<<EOF
    <span itemid="{$original_entity_uri}">My entity</span>
EOF;
        // Create a post referincing to the created entity
        $post_id = wl_create_post($content, 'my-post', 'A post', 'draft');
        // Here the entity should have been created
        $original_entity = wl_get_entity_post_by_uri($original_entity_uri);
        $this->assertNotNull($original_entity);
        // Store entity type, images and sameAs (needed later)
        $original_type = wl_schema_get_types($original_entity->ID);
        $original_thumbnails = $this->getThumbs($original_entity->ID);
        $original_sameAs = wl_schema_get_value($original_entity->ID, 'sameAs');
        // Query the same entity using the Redlink URI
        $entity_uri = wl_get_entity_uri($original_entity->ID);
        $e = wl_get_entity_post_by_uri($entity_uri);
        $this->assertEquals($original_entity, $e);
        // The entity description should be the same we expect
        $raw_entity = current(array_values($fake['wl_entities']));
        $this->assertEquals($raw_entity['description'], $original_entity->post_content);
        // The entity is related as what predicate
        $related_entity_ids = wl_core_get_related_entity_ids($post_id, array("predicate" => "what"));
        $this->assertCount(1, $related_entity_ids);
        // Ensure there are no other relation instances
        $relation_instances = wl_tests_get_relation_instances_for($post_id);
        $this->assertCount(1, $relation_instances);
        /* Now Post is saved again with the same mentioned entity:
         * - with different type
         * - with different description
         * - with one more image
         * - with one modified sameAs
         * - as WHO instead fo WHAT
         */
        $fake = $this->prepareFakeGlobalPostArrayFromFile('/assets/fake_global_post_array_with_one_entity_linked_as_who_and_modified_data.json');
        $_POST = $fake;
        // The entity url should be the same we expect
        $raw_entity = current(array_values($fake['wl_entities']));
        $raw_entity_uri = $raw_entity['uri'];
        $new_content = <<<EOF
    <span itemid="{$raw_entity_uri}">My entity</span>
EOF;
        // Update the post content (to force existing entities update)
        wp_update_post(array('ID' => $post_id, 'post_content' => $new_content));
        // Verify the mentioned entity was already into DB...
        $updated_entity = wl_get_entity_post_by_uri($raw_entity_uri);
        $this->assertEquals($original_entity->ID, $updated_entity->ID);
        $this->assertEquals($original_entity->post_title, $updated_entity->post_title);
        // ... but some properties changed!
        $this->assertNotEquals($original_entity, $updated_entity);
        // Verify entity type has been updated
        $updated_type = wl_schema_get_types($updated_entity->ID);
        $this->assertNotEquals($original_type, $updated_type);
        $this->assertEquals(array('http://schema.org/Organization'), $updated_type);
        // Verify entity description has been updated
        $this->assertEquals($raw_entity['description'], $updated_entity->post_content);
        // Verify entity images have been updated (one was added)
        $updated_thumbnails = $this->getThumbs($updated_entity->ID);
        $this->assertNotEquals($original_thumbnails, $updated_thumbnails);
        $this->assertContains($original_thumbnails[0], $updated_thumbnails);
        $this->assertCount(2, $updated_thumbnails);
        // There is one more
        $this->assertContains('Netherlands_vs_Ivory_Coast', $updated_thumbnails[1]);
        // ... about soccer
        // Verify entity sameAs have been updated
        $updated_sameAs = wl_schema_get_value($updated_entity->ID, 'sameAs');
        $this->assertNotEquals($original_sameAs, $updated_sameAs);
        $this->assertContains($original_sameAs[1], $updated_sameAs);
        $this->assertNotContains($original_sameAs[0], $updated_sameAs);
        $this->assertContains('http://sv.dbpedia.org/page/Reason', $updated_sameAs);
        // Verify the entity is now related as who predicate
        $related_entity_ids = wl_core_get_related_entity_ids($post_id, array("predicate" => "who"));
        $this->assertCount(1, $related_entity_ids);
        // Ensure there are no other relation instances
        $relation_instances = wl_tests_get_relation_instances_for($post_id);
        $this->assertCount(1, $relation_instances);
    }
/**
 * Saves the values of wordlift metaboxes set in the entity editor page
 */
function wl_entity_metabox_save($post_id)
{
    if (!isset($_POST['wl_metaboxes'])) {
        return;
    }
    // Loop over the wl_metaboxes array and save metaboxes values
    foreach ($_POST['wl_metaboxes'] as $meta_name => $meta_values) {
        // First, verify nonce is set for this meta
        $nonce_name = 'wordlift_' . $meta_name . '_entity_box_nonce';
        $nonce_verify = 'wordlift_' . $meta_name . '_entity_box';
        if (!isset($_POST[$nonce_name])) {
            return $post_id;
        }
        // Verify that the nonce is valid.
        if (!wp_verify_nonce($_POST[$nonce_name], $nonce_verify)) {
            return $post_id;
        }
        // Delete values before updating
        delete_post_meta($post_id, $meta_name);
        // Save the property value(s)
        if (isset($meta_name) && isset($meta_values) && $meta_values !== '') {
            // There can be one or more property values, so we force to array:
            if (!is_array($meta_values)) {
                $meta_values = array($meta_values);
            }
            foreach ($meta_values as $meta_value) {
                // If the meta expects an entity...
                $expecting_uri = wl_get_meta_type($meta_name) === WL_DATA_TYPE_URI;
                // ...and the user inputs an entity that is not present in the db...
                $absent_from_db = is_null(wl_get_entity_post_by_uri($meta_value));
                // ...and that is not a external uri
                $name_is_uri = strpos($meta_value, 'http') === 0;
                if ($expecting_uri && $absent_from_db && !$name_is_uri) {
                    // ...we create a new entity!
                    $new_entity = wl_save_entity('', $meta_value, WL_ENTITY_TYPE_NAME, '');
                    // Assign type
                    $constraints = wl_get_meta_constraints($meta_name);
                    $type = 'http://schema.org/' . $constraints['uri_type'];
                    wl_set_entity_main_type($new_entity->ID, $type);
                    // TODO: directly publish the new entity
                    // Update the value that will be saved as meta
                    $meta_value = wl_get_entity_uri($new_entity->ID);
                }
                // TODO: use WL methods
                add_post_meta($post_id, $meta_name, $meta_value);
            }
        }
    }
    // Push changes on RedLink
    wl_linked_data_push_to_redlink($post_id);
}
/**
 * Get an array of entities from the *itemid* attributes embedded in the provided content.
 *
 * @since 3.0.0
 *
 * @param string $content The content with itemid attributes.
 *
 * @return array An array of entity posts.
 */
function wl_linked_data_content_get_embedded_entities($content)
{
    // Remove quote escapes.
    $content = str_replace('\\"', '"', $content);
    // Match all itemid attributes.
    $pattern = '/<\\w+[^>]*\\sitemid="([^"]+)"[^>]*>/im';
    wl_write_log("Getting entities embedded into content [ pattern :: {$pattern} ]");
    // Remove the pattern while it is found (match nested annotations).
    $matches = array();
    // In case of errors, return an empty array.
    if (false === preg_match_all($pattern, $content, $matches)) {
        wl_write_log("Found no entities embedded in content");
        return array();
    }
    //    wl_write_log("wl_update_related_entities [ content :: $content ][ data :: " . var_export($data, true). " ][ matches :: " . var_export($matches, true) . " ]");
    // Collect the entities.
    $entities = array();
    foreach ($matches[1] as $uri) {
        $uri_d = html_entity_decode($uri);
        $entity = wl_get_entity_post_by_uri($uri_d);
        if (null !== $entity) {
            array_push($entities, $entity->ID);
        }
    }
    $count = sizeof($entities);
    wl_write_log("Found {$count} entities embedded in content");
    return $entities;
}
    function testEntityAdditionalPropertiesAreSaved()
    {
        $fake = $this->prepareFakeGlobalPostArrayFromFile('/assets/fake_global_post_array_with_a_new_entity_linked_as_where_with_coordinates.json');
        $_POST = $fake;
        // Retrieve the entity uri (the first key in wl_entities associative aray)
        $entity_uri = current(array_keys($fake['wl_entities']));
        // Retrieve the label and compose expected uri
        $raw_entity = current(array_values($fake['wl_entities']));
        $expected_entity_uri = $this->buildEntityUriForLabel($raw_entity['label']);
        // Reference the entity to the post content
        $content = <<<EOF
    <span itemid="{$entity_uri}">My entity</span>
EOF;
        // Create a post referincing to the created entity
        $post_id = wl_create_post($content, 'my-post', 'A post', 'draft');
        // Here the entity should have been created
        $entity = wl_get_entity_post_by_uri($expected_entity_uri);
        $this->assertNotNull($entity);
        // Verify association to post as where
        $related_entity_ids = wl_core_get_related_entity_ids($post_id, array("predicate" => "where"));
        $this->assertEquals(array($entity->ID), $related_entity_ids);
        // Verify schema type
        $this->assertEquals(array('http://schema.org/Place'), wl_schema_get_types($entity->ID));
        // Verify coordinates
        $this->assertEquals(array(43.21), wl_schema_get_value($entity->ID, 'latitude'));
        $this->assertEquals(array(12.34), wl_schema_get_value($entity->ID, 'longitude'));
    }
Esempio n. 8
0
/**
 * Replaces the *itemid* attributes URIs with the WordLift URIs.
 *
 * @param string $content The post content.
 *
 * @return string The updated post content.
 */
function wl_replace_item_id_with_uri($content)
{
    // wl_write_log( "wl_replace_item_id_with_uri" );
    // Strip slashes, see https://core.trac.wordpress.org/ticket/21767
    $content = stripslashes($content);
    // If any match are found.
    $matches = array();
    if (0 < preg_match_all('/ itemid="([^"]+)"/i', $content, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            // Get the item ID.
            $item_id = $match[1];
            // Get the post bound to that item ID (looking both in the 'official' URI and in the 'same-as' .
            $post = wl_get_entity_post_by_uri($item_id);
            // If no entity is found, continue to the next one.
            if (null === $post) {
                continue;
            }
            // Get the URI for that post.
            $uri = wl_get_entity_uri($post->ID);
            // wl_write_log( "wl_replace_item_id_with_uri [ item id :: $item_id ][ uri :: $uri ]" );
            // If the item ID and the URI differ, replace the item ID with the URI saved in WordPress.
            if ($item_id !== $uri) {
                $uri_e = esc_html($uri);
                $content = str_replace(" itemid=\"{$item_id}\"", " itemid=\"{$uri_e}\"", $content);
            }
        }
    }
    // Reapply slashes.
    $content = addslashes($content);
    return $content;
}
/**
 * Fills up the microdata_template with entity's values.
 *
 * @param string $entity_id An entity ID.
 * @param string $entity_type Entity type stracture.
 * @param integer $recursion_level Recursion depth level in microdata compiling. Recursion depth limit is defined by WL_MAX_NUM_RECURSIONS_WHEN_PRINTING_MICRODATA constant.
 *
 * @return string The content with embedded microdata.
 */
function wl_content_embed_compile_microdata_template($entity_id, $entity_type, $recursion_level = 0)
{
    wl_write_log("[ entity id :: {$entity_id} ][ entity type :: " . var_export($entity_type, true) . " ][ recursion level :: {$recursion_level} ]");
    $regex = '/{{(.*?)}}/';
    $matches = array();
    if (null === $entity_type) {
        return '';
    }
    $template = $entity_type['microdata_template'];
    // Return empty string if template fields have not been found.
    if (false === preg_match_all($regex, $template, $matches, PREG_SET_ORDER)) {
        return '';
    }
    foreach ($matches as $match) {
        $placeholder = $match[0];
        $field_name = $match[1];
        // Get property value.
        $meta_collection = wl_schema_get_value($entity_id, $field_name);
        // If no value is given, just remove the placeholder from the template
        if (null == $meta_collection) {
            $template = str_replace($placeholder, '', $template);
            continue;
        }
        // What kind of value is it?
        // TODO: Performance issue here: meta type retrieving should be centralized
        $expected_type = wl_get_meta_type($field_name);
        foreach ($meta_collection as $field_value) {
            if (WL_DATA_TYPE_URI == $expected_type) {
                // If is a numeric value we assume it is an ID referencing for an internal entity.
                if (is_numeric($field_value)) {
                    // Found id, get uri.
                    $field_value = wl_get_entity_uri($field_value);
                }
                // Just if the linked entity does exist I can go further with template compiling
                $nested_entity = wl_get_entity_post_by_uri($field_value);
                if (!is_null($nested_entity)) {
                    $content = '<span itemid="' . esc_attr($field_value) . '">' . $nested_entity->post_title . '</span>';
                    $compiled_template = wl_content_embed_item_microdata($content, $field_value, $field_name, ++$recursion_level);
                    $template = str_replace($placeholder, $compiled_template, $template);
                } else {
                    $template = str_replace($placeholder, '', $template);
                }
                continue;
            }
            // Standard condition: field containing a raw value
            $value = '<span itemprop="' . esc_attr($field_name) . '" content="' . esc_attr($field_value) . '"></span>';
            $template = str_replace($placeholder, $value, $template);
        }
    }
    return $template;
}
/**
 * Fills up the microdata_template with entity's values.
 *
 * @param string $entity_id An entity ID.
 * @param string $entity_type Entity type structure.
 * @param integer $recursion_level Recursion depth level in microdata compiling. Recursion depth limit is defined by WL_MAX_NUM_RECURSIONS_WHEN_PRINTING_MICRODATA constant.
 *
 * @return string The content with embedded microdata.
 */
function wl_content_embed_compile_microdata_template($entity_id, $entity_type, $recursion_level = 0)
{
    global $wl_logger;
    if (WP_DEBUG) {
        $wl_logger->trace("Embedding microdata [ entity id :: {$entity_id} ][ entity type :: " . var_export($entity_type, true) . " ][ recursion level :: {$recursion_level} ]");
    }
    $regex = '/{{(.*?)}}/';
    $matches = array();
    if (null === $entity_type) {
        return '';
    }
    $template = $entity_type['microdata_template'];
    // Return empty string if template fields have not been found.
    if (false === preg_match_all($regex, $template, $matches, PREG_SET_ORDER)) {
        return '';
    }
    foreach ($matches as $match) {
        $placeholder = $match[0];
        $field_name = $match[1];
        // Get property value.
        $meta_collection = wl_schema_get_value($entity_id, $field_name);
        // If no value is given, just remove the placeholder from the template
        if (null == $meta_collection) {
            $template = str_replace($placeholder, '', $template);
            continue;
        }
        // What kind of value is it?
        // TODO: Performance issue here: meta type retrieving should be centralized
        $expected_type = wl_get_meta_type($field_name);
        if (WP_DEBUG) {
            $wl_logger->trace("Embedding microdata [ placeholder :: {$placeholder} ][ field name :: {$field_name} ][ meta collection :: " . (is_array($meta_collection) ? var_export($meta_collection, true) : $meta_collection) . " ][ expected type :: {$expected_type} ]");
        }
        foreach ($meta_collection as $field_value) {
            // Quick and dirty patch for #163:
            //  - only apply to URIs, i.e. to properties pointing to another post ( $field_value should be a post ID ),
            //  - check that $field_value is actually a number,
            //  - check that the referenced post is published.
            //  OR
            //  - if the value is empty then we don't display it.
            if (Wordlift_Schema_Service::DATA_TYPE_URI === $expected_type && is_numeric($field_value) && 'publish' !== ($post_status = get_post_status($field_value)) || empty($field_value)) {
                if (WP_DEBUG) {
                    $wl_logger->trace("Microdata refers to a non-published post [ field value :: {$field_value} ][ post status :: {$post_status} ]");
                }
                // Remove the placeholder.
                $template = str_replace($placeholder, '', $template);
                continue;
            }
            if (Wordlift_Schema_Service::DATA_TYPE_URI == $expected_type) {
                // If is a numeric value we assume it is an ID referencing for an internal entity.
                if (is_numeric($field_value)) {
                    // Found id, get uri.
                    $field_value = wl_get_entity_uri($field_value);
                }
                // Just if the linked entity does exist I can go further with template compiling
                $nested_entity = wl_get_entity_post_by_uri($field_value);
                if (!is_null($nested_entity)) {
                    $content = '<span itemid="' . esc_attr($field_value) . '">' . $nested_entity->post_title . '</span>';
                    $compiled_template = wl_content_embed_item_microdata($content, $field_value, $field_name, ++$recursion_level);
                    $template = str_replace($placeholder, $compiled_template, $template);
                } else {
                    $template = str_replace($placeholder, '', $template);
                }
                continue;
            }
            // Standard condition: field containing a raw value
            // For non visible test, schema.org dictates to use the *meta* tag.
            // see http://schema.org/docs/gs.html#advanced_missing
            $value = '<meta itemprop="' . esc_attr($field_name) . '" content="' . esc_attr($field_value) . '" />';
            $template = str_replace($placeholder, $value, $template);
        }
    }
    return $template;
}