/**
  * Tests the *wl_get_meta_type* function
  */
 function testEntityGetMetaType()
 {
     $type = wl_get_meta_type(Wordlift_Schema_Service::FIELD_GEO_LATITUDE);
     $this->assertEquals('double', $type);
     $type = wl_get_meta_type('latitude');
     $this->assertEquals('double', $type);
     $this->assertEquals(Wordlift_Schema_Service::DATA_TYPE_DOUBLE, $type);
     $type = wl_get_meta_type(Wordlift_Schema_Service::FIELD_DATE_START);
     $this->assertEquals('date', $type);
     $type = wl_get_meta_type('startDate');
     $this->assertEquals('date', $type);
     $this->assertEquals(Wordlift_Schema_Service::DATA_TYPE_DATE, $type);
     $type = wl_get_meta_type(Wordlift_Schema_Service::FIELD_LOCATION);
     $this->assertEquals('uri', $type);
     $type = wl_get_meta_type('location');
     $this->assertEquals('uri', $type);
     $this->assertEquals(Wordlift_Schema_Service::DATA_TYPE_URI, $type);
     $type = wl_get_meta_type('random_silly_name');
     $this->assertEquals(null, $type);
 }
/**
 * 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);
}
/**
 * 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;
}