function testWL_Metabox_group_properties_by_input_field() { // Create an entity of type Place $business_id = wl_create_post('', 'p', 'A place', 'publish', Wordlift_Entity_Service::TYPE_NAME); wl_set_entity_main_type($business_id, 'http://schema.org/LocalBusiness'); // Create Metabox and its Fields $metabox = new WL_Metabox(); $entity_type = wl_entity_taxonomy_get_custom_fields($business_id); $simple_and_grouped_fields = $metabox->group_properties_by_input_field($entity_type); // Verify properties have been distinguished (single vs special/grouped) $this->assertArrayHasKey(Wordlift_Schema_Service::FIELD_FOUNDER, $simple_and_grouped_fields[0]); // Simple Field $this->assertArrayHasKey('address', $simple_and_grouped_fields[1]); // Special/grouped Field $this->assertArrayHasKey('coordinates', $simple_and_grouped_fields[1]); // Special/grouped Field $this->assertArrayHasKey('sameas', $simple_and_grouped_fields[1]); // Special/grouped Field }
/** * Push the provided entity post to Redlink. * * @param object $entity_post An entity post instance. */ function wl_push_entity_post_to_redlink($entity_post) { // Get the Entity service instance to perform actions related to entities. $entity_service = Wordlift_Entity_Service::get_instance(); // Only handle published entities. if (!$entity_service->is_entity($entity_post->ID) || 'publish' !== $entity_post->post_status) { wl_write_log("wl_push_entity_post_to_redlink : not an entity or not published [ post type :: {$entity_post->post_type} ][ post status :: {$entity_post->post_status} ]"); return; } // get the entity URI and the SPARQL escaped version. $uri = wl_get_entity_uri($entity_post->ID); $uri_e = wl_sparql_escape_uri($uri); // If the URI ends with a trailing slash, then we have a problem. if ('/' === substr($uri, -1, 1)) { wl_write_log("wl_push_entity_post_to_redlink : the URI is invalid [ post ID :: {$entity_post->ID} ][ URI :: {$uri} ]"); return; } // Get the site language in order to define the literals language. $site_language = wl_configuration_get_site_language(); // get the title and content as label and description. $label = wordlift_esc_sparql($entity_post->post_title); $descr = wordlift_esc_sparql(wp_strip_all_tags(strip_shortcodes($entity_post->post_content))); $permalink = wl_sparql_escape_uri(get_permalink($entity_post->ID)); // wl_write_log( "wl_push_entity_post_to_redlink [ entity post id :: $entity_post->ID ][ uri :: $uri ][ label :: $label ]" ); // create a new empty statement. $delete_stmt = ''; $sparql = ''; // delete on RL all statements regarding properties set from WL (necessary when changing entity type) $all_custom_fields = wl_entity_taxonomy_get_custom_fields(); $predicates_to_be_deleted = array(); foreach ($all_custom_fields as $type => $fields) { foreach ($fields as $cf) { $predicate = $cf['predicate']; if (!in_array($predicate, $predicates_to_be_deleted)) { $predicates_to_be_deleted[] = $predicate; $delete_stmt .= "DELETE { <{$uri_e}> <{$predicate}> ?o } WHERE { <{$uri_e}> <{$predicate}> ?o };\n"; } } } // set the same as. $same_as = wl_schema_get_value($entity_post->ID, 'sameAs'); foreach ($same_as as $same_as_uri) { $same_as_uri_esc = wl_sparql_escape_uri($same_as_uri); $sparql .= "<{$uri_e}> owl:sameAs <{$same_as_uri_esc}> . \n"; } // set the label $sparql .= "<{$uri_e}> rdfs:label \"{$label}\"@{$site_language} . \n"; // Set the alternative labels. $alt_labels = $entity_service->get_alternative_labels($entity_post->ID); foreach ($alt_labels as $alt_label) { $sparql .= sprintf('<%s> rdfs:label "%s"@%s . ', $uri_e, Wordlift_Query_Builder::escape_value($alt_label), $site_language); } // set the URL $sparql .= "<{$uri_e}> schema:url <{$permalink}> . \n"; // set the description. if (!empty($descr)) { $sparql .= "<{$uri_e}> schema:description \"{$descr}\"@{$site_language} . \n"; } $main_type = wl_entity_type_taxonomy_get_type($entity_post->ID); if (null != $main_type) { $main_type_uri = wl_sparql_escape_uri($main_type['uri']); $sparql .= " <{$uri_e}> a <{$main_type_uri}> . \n"; // The type define custom fields that hold additional data about the entity. // For example Events may have start/end dates, Places may have coordinates. // The value in the export fields must be rewritten as triple predicates, this // is what we're going to do here. // wl_write_log( 'wl_push_entity_post_to_redlink : checking if entity has export fields [ type :: ' . var_export( $main_type, true ) . ' ]' ); if (isset($main_type['custom_fields'])) { foreach ($main_type['custom_fields'] as $field => $settings) { // wl_write_log( "wl_push_entity_post_to_redlink : entity has export fields" ); $predicate = wordlift_esc_sparql($settings['predicate']); if (!isset($settings['export_type']) || empty($settings['export_type'])) { $type = null; } else { $type = $settings['export_type']; } foreach (get_post_meta($entity_post->ID, $field) as $value) { $sparql .= " <{$uri_e}> <{$predicate}> "; if (!is_null($type) && substr($type, 0, 4) == 'http') { // Type is defined by a raw uri (es. http://schema.org/PostalAddress) // Extract uri if the value is numeric if (is_numeric($value)) { $value = wl_get_entity_uri($value); } $sparql .= '<' . wl_sparql_escape_uri($value) . '>'; } else { // Type is defined in another way (es. xsd:double) $sparql .= '"' . wordlift_esc_sparql($value) . '"^^' . wordlift_esc_sparql($type); } $sparql .= " . \n"; } } } } // Get the entity types. $type_uris = wl_get_entity_rdf_types($entity_post->ID); // Support type are only schema.org ones: it could be null foreach ($type_uris as $type_uri) { $type_uri = wl_sparql_escape_uri($type_uri); $sparql .= "<{$uri_e}> a <{$type_uri}> . \n"; } // get related entities. $related_entities_ids = wl_core_get_related_entity_ids($entity_post->ID); if (is_array($related_entities_ids)) { foreach ($related_entities_ids as $entity_post_id) { $related_entity_uri = wl_sparql_escape_uri(wl_get_entity_uri($entity_post_id)); // create a two-way relationship. $sparql .= " <{$uri_e}> dct:relation <{$related_entity_uri}> . \n"; $sparql .= " <{$related_entity_uri}> dct:relation <{$uri_e}> . \n"; } } // Add SPARQL stmts to write the schema:image. $sparql .= wl_get_sparql_images($uri, $entity_post->ID); $query = rl_sparql_prefixes() . <<<EOF {$delete_stmt} DELETE { <{$uri_e}> rdfs:label ?o } WHERE { <{$uri_e}> rdfs:label ?o }; DELETE { <{$uri_e}> owl:sameAs ?o . } WHERE { <{$uri_e}> owl:sameAs ?o . }; DELETE { <{$uri_e}> schema:description ?o . } WHERE { <{$uri_e}> schema:description ?o . }; DELETE { <{$uri_e}> schema:url ?o . } WHERE { <{$uri_e}> schema:url ?o . }; DELETE { <{$uri_e}> a ?o . } WHERE { <{$uri_e}> a ?o . }; DELETE { <{$uri_e}> dct:relation ?o . } WHERE { <{$uri_e}> dct:relation ?o . }; DELETE { <{$uri_e}> schema:image ?o . } WHERE { <{$uri_e}> schema:image ?o . }; INSERT DATA { {$sparql} }; EOF; rl_execute_sparql_update_query($query); }
/** * Retrieve entity property constraints, starting from the schema.org's property name * or from the WL_CUSTOM_FIELD_xxx name. * * @param $property_name as defined by schema.org or WL internal constants * * @return array containing constraint(s) or null (in case of error or no constraint). */ function wl_get_meta_constraints($property_name) { // Property name must be defined. if (!isset($property_name) || is_null($property_name)) { return null; } // store eventual schema name in different variable $property_schema_name = wl_build_full_schema_uri_from_schema_slug($property_name); // Get WL taxonomy mapping. $types = wl_entity_taxonomy_get_custom_fields(); // Loop over types foreach ($types as $type) { // Loop over custom fields of this type foreach ($type as $property => $field) { if (isset($field['constraints']) && !empty($field['constraints'])) { // Is this the property we are searhing for? if ($property == $property_name || $field['predicate'] == $property_schema_name) { return $field['constraints']; } } } } return null; }
/** * Retrieves the list of supported properties for the specified type. * @uses wl_entity_taxonomy_get_custom_fields() to retrieve all custom fields (type properties) * @uses wl_build_full_schema_uri_from_schema_slug() to convert a schema slug to full uri * * @param $type_name string Name of the type (e.g. Type, for the http://schema.org/Type) * * @return array The method returns an array of supported properties for the type, e.g. (‘startDate’, ‘endDate’) for an Event. * You can call wl_schema_get_property_expected_type on each to know which data type they expect. */ function wl_schema_get_type_properties($type_name) { // Build full schema uri if necessary $type_name = wl_build_full_schema_uri_from_schema_slug($type_name); // Get all custom fields $all_types_and_fields = wl_entity_taxonomy_get_custom_fields(); $schema_root_address = 'http://schema.org/'; $type_properties = array(); // Search for the entity type which has the requested name as uri if (isset($all_types_and_fields[$type_name])) { foreach ($all_types_and_fields[$type_name] as $field) { // Convert to schema slug and store in array $type_properties[] = str_replace($schema_root_address, '', $field['predicate']); } } return $type_properties; }
/** * Retrieves the property expected type, according to the schema.org specifications, where: * * @param $property_name string Name of the property (e.g. name, for the http://schema.org/name property) * * @return array of allowed types or NULL in case of property not found. * * The following types are supported (defined as constants): * - WL_DATA_TYPE_URI * - WL_DATA_TYPE_DATE * - WL_DATA_TYPE_INTEGER * - WL_DATA_TYPE_DOUBLE * - WL_DATA_TYPE_BOOLEAN * - WL_DATA_TYPE_STRING * - a schema.org URI when the property type supports a schema.org entity (e.g. http://schema.org/Place) */ function wl_schema_get_property_expected_type($property_name) { // This is the actual structure of a custom_field. /* * WL_CUSTOM_FIELD_LOCATION => array( * 'predicate' => 'http://schema.org/location', * 'type' => WL_DATA_TYPE_URI, * 'export_type' => 'http://schema.org/PostalAddress', * 'constraints' => array( * 'uri_type' => 'Place' * ) * ) */ // Build full schema uri if necessary $property_name = wl_build_full_schema_uri_from_schema_slug($property_name); // Get all custom fields $all_types_and_fields = wl_entity_taxonomy_get_custom_fields(); $expected_types = null; // Search for the entity type which has the requested name as uri $found = false; foreach ($all_types_and_fields as $type_fields) { foreach ($type_fields as $field) { if ($field['predicate'] == $property_name) { $expected_types = array(); // Does the property accept a specific schema type? if (isset($field['constraints']) && isset($field['constraints']['uri_type'])) { // Take note of expected schema type $expected_types[] = wl_build_full_schema_uri_from_schema_slug($field['constraints']['uri_type']); } else { // Take note of expected type $expected_types[] = $field['type']; } // We found the property, we can exit the cycles $found = true; } if ($found) { break; } } if ($found) { break; } } return $expected_types; }
/** * Tests the *wl_get_meta_constraints* function */ function testEntityGetMetaConstraints() { // TODO: complete this test $fields = wl_entity_taxonomy_get_custom_fields(); }
/** * Read the WL <-> Schema mapping and build the Fields for the entity being edited. * * Note: the first function that calls this method will instantiate the fields. * Why it isn't called from the constructor? Because we need to hook this process as late as possible. * * @since 3.1.0 * * @param int $post_id The post id. */ public function instantiate_fields($post_id) { // This function must be called only once. Not called from the constructor because WP hooks have a rococo ordering if (isset($this->fields)) { return; } $entity_type = wl_entity_taxonomy_get_custom_fields($post_id); if (isset($entity_type)) { /** * In some special case, properties must be grouped in one field (e.g. coordinates) or dealed with custom methods. * We must divide fields in two groups: * - simple: accept values for one property * - grouped: accept values for more properties, or for one property that needs a specific metabox. */ $metaboxes = $this->group_properties_by_input_field($entity_type); $simple_metaboxes = $metaboxes[0]; $grouped_metaboxes = $metaboxes[1]; // Loop over simple entity properties foreach ($simple_metaboxes as $key => $property) { // Info passed to the metabox $info = array(); $info[$key] = $property; // Build the requested field as WL_Metabox_Field_ object $this->add_field($info); } // Loop over grouped properties foreach ($grouped_metaboxes as $key => $property) { // Info passed to the metabox $info = array(); $info[$key] = $property; // Build the requested field group as WL_Metabox_Field_ object $this->add_field($info, true); } } }