/**
 * Encode places array in geojson compliant format
 * (refer to http://leafletjs.com/examples/geojson.html)
 * Define geomap boundaries according to $places
 * Default boundaries are defined using PHP_INT_MAX value
 *
 * @param array $places An array of place posts.
 *
 * @return array An array of markers and boundaries for Leaflet.
 */
function wl_shortcode_geomap_prepare_map($places)
{
    // Prepare for min/max lat/long in case we need to define a view boundary for the client JavaScript.
    $min_latitude = PHP_INT_MAX;
    $min_longitude = PHP_INT_MAX;
    $max_latitude = ~PHP_INT_MAX;
    $max_longitude = ~PHP_INT_MAX;
    // Prepare an empty array of POIs in geoJSON format.
    $pois = array();
    // And store list of points to allow Leaflet compute the optimal bounding box.
    // The main reason for this is that geoJSON has swapped coordinates (lon. lat)
    $boundaries = array();
    // Add a POI for each entity that has coordinates.
    foreach ($places as $entity) {
        // Get the coordinates.
        $coordinates = wl_get_coordinates($entity->ID);
        // Don't show the widget if the coordinates aren't set.
        if ($coordinates['latitude'] == 0 || $coordinates['longitude'] == 0) {
            continue;
        }
        // TODO Map html rendering should be delegated to the wordlift js ui layer
        // This function should be focused on returning pure data instead
        // Get the title, URL and thumb of the entity.
        $title = esc_attr($entity->post_title);
        $link = esc_attr(get_permalink($entity->ID));
        if ('' !== ($thumbnail_id = get_post_thumbnail_id($entity->ID)) && false !== ($attachment = wp_get_attachment_image_src($thumbnail_id))) {
            $img_src = esc_attr($attachment[0]);
        }
        // Build HTML popup. TODO: move thumb width in css
        $content = "<a href={$link}><h6>{$title}</h6>";
        if (isset($img_src)) {
            $content = $content . "<img src={$img_src} style='width:100%'/>";
        }
        $content = $content . "</a><ul>";
        // Get the related posts (published) and print them in the popup.
        $related_posts = wl_core_get_related_post_ids($entity->ID, array('status' => 'publish'));
        foreach ($related_posts as $rp_id) {
            $rp = get_post($rp_id);
            $title = esc_attr($rp->post_title);
            $link = esc_attr(get_permalink($rp->ID));
            $content = $content . "<li><a href={$link}>{$title}</a></li>";
        }
        $content = $content . "</ul>";
        // Formatting POI in geoJSON.
        // http://leafletjs.com/examples/geojson.html
        $poi = array('type' => 'Feature', 'properties' => array('popupContent' => $content), 'geometry' => array('type' => 'Point', 'coordinates' => array($coordinates['longitude'], $coordinates['latitude'])));
        $pois[] = $poi;
        // Formatting boundaries in a Leaflet-like format (see LatLngBounds).
        // http://leafletjs.com/reference.html#latlngbounds
        $boundaries[] = array($coordinates['latitude'], $coordinates['longitude']);
    }
    $map_data = array();
    $map_data['features'] = $pois;
    $map_data['boundaries'] = $boundaries;
    return $map_data;
}
 /**
  * Create:
  *  * 1 Post
  *  * 3 Place entities referenced by the Post
  *  * 1 Person entity reference by the Post
  *
  * Check that only the first 2 entities are returned when calling *wl_core_get_related_entity_ids*.
  */
 function testGetPlaces()
 {
     $post_id = wl_create_post('', 'post-1', 'Post 1', 'publish', 'post');
     $entity_1_id = wl_create_post("Entity 1 Text", 'entity-1', "Entity 1 Title", 'publish', 'entity');
     wl_set_entity_main_type($entity_1_id, 'http://schema.org/Place');
     add_post_meta($entity_1_id, WL_CUSTOM_FIELD_GEO_LATITUDE, 40.12, true);
     add_post_meta($entity_1_id, WL_CUSTOM_FIELD_GEO_LONGITUDE, 72.3, true);
     $entity_2_id = wl_create_post("Entity 2 Text", 'entity-2', "Entity 2 Title", 'publish', 'entity');
     wl_set_entity_main_type($entity_2_id, 'http://schema.org/Place');
     add_post_meta($entity_2_id, WL_CUSTOM_FIELD_GEO_LATITUDE, 41.2, true);
     add_post_meta($entity_2_id, WL_CUSTOM_FIELD_GEO_LONGITUDE, 78.2, true);
     $entity_3_id = wl_create_post('Entity 3 Text', 'entity-3', 'Entity 3 Title', 'publish', 'entity');
     wl_set_entity_main_type($entity_2_id, 'http://schema.org/Place');
     add_post_meta($entity_3_id, WL_CUSTOM_FIELD_GEO_LATITUDE, 45.12, true);
     add_post_meta($entity_3_id, WL_CUSTOM_FIELD_GEO_LONGITUDE, 90.3, true);
     $entity_4_id = wl_create_post('', 'entity-4', 'Entity 4', 'publish', 'entity');
     wl_set_entity_main_type($entity_4_id, 'http://schema.org/Person');
     wl_core_add_relation_instance($post_id, WL_WHERE_RELATION, $entity_1_id);
     wl_core_add_relation_instance($post_id, WL_WHERE_RELATION, $entity_2_id);
     wl_core_add_relation_instance($post_id, WL_WHO_RELATION, $entity_4_id);
     $places = wl_shortcode_geomap_get_places($post_id);
     $this->assertCount(2, $places);
     $places_ids = array_map(function ($item) {
         return $item->ID;
     }, $places);
     $this->assertContains($entity_1_id, $places_ids);
     $this->assertContains($entity_2_id, $places_ids);
     // From here onwards we check that the JSON response matches the places data.
     $response = wl_shortcode_geomap_prepare_map($places);
     // Check retrieved boundaries
     $this->assertTrue(isset($response['boundaries']));
     $this->assertCount(2, $response['boundaries']);
     // Should contain two set of coordinates.
     $this->assertCount(2, $response['boundaries'][0]);
     // [minLat, minLon]
     $this->assertCount(2, $response['boundaries'][1]);
     // [maxLat, maxLon]
     // Check if coordinates are actually numbers
     $this->assertTrue(is_numeric($response['boundaries'][0][0]));
     $this->assertTrue(is_numeric($response['boundaries'][0][1]));
     $this->assertTrue(is_numeric($response['boundaries'][1][0]));
     $this->assertTrue(is_numeric($response['boundaries'][1][1]));
     // Check retrieved places
     $this->assertTrue(isset($response['features']));
     $i = 0;
     foreach ($places as $place) {
         // Check object attributes
         $poi = $response['features'][$i];
         $this->assertTrue(isset($poi));
         $this->assertTrue(isset($poi['type']));
         $this->assertTrue(isset($poi['properties']));
         $this->assertNotEmpty(isset($poi['properties']['popupContent']));
         $this->assertTrue(isset($poi['geometry']));
         $this->assertTrue(isset($poi['geometry']['coordinates']));
         $this->assertCount(2, $poi['geometry']['coordinates']);
         $this->assertTrue(is_numeric($poi['geometry']['coordinates'][0]));
         $this->assertTrue(is_numeric($poi['geometry']['coordinates'][1]));
         // Check consistency with declared places
         $coords = wl_get_coordinates($place->ID);
         $coords = array($coords['longitude'], $coords['latitude']);
         // Leaflet geoJSON wants them swapped
         $this->assertEquals($coords, $poi['geometry']['coordinates']);
         $i++;
     }
 }
/**
 * Displays the coordinates meta box contents (called by *add_meta_box* callback).
 *
 * @param WP_Post $post The current post.
 */
function wl_entities_coordinates_box_content($post)
{
    // Add leaflet css and library.
    wp_enqueue_style('leaflet_css', plugins_url('bower_components/leaflet/dist/leaflet.css', __FILE__));
    wp_enqueue_script('leaflet_js', plugins_url('bower_components/leaflet/dist/leaflet.js', __FILE__));
    // Set nonce for both meta (latitude and longitude)
    wl_echo_nonce(WL_CUSTOM_FIELD_GEO_LATITUDE);
    wl_echo_nonce(WL_CUSTOM_FIELD_GEO_LONGITUDE);
    // Get coordinates
    $coords = wl_get_coordinates($post->ID);
    // Print input fields
    echo '<label for="wl_place_lat">' . __('Latitude', 'wordlift') . '</label>';
    echo '<input type="text" id="wl_place_lat" name="wl_metaboxes[' . WL_CUSTOM_FIELD_GEO_LATITUDE . ']" value="' . $coords['latitude'] . '" style="width:100%" />';
    echo '<label for="wl_place_lon">' . __('Longitude', 'wordlift') . '</label>';
    echo '<input type="text" id="wl_place_lon" name="wl_metaboxes[' . WL_CUSTOM_FIELD_GEO_LONGITUDE . ']" value="' . $coords['longitude'] . '" style="width:100%" />';
    // Show Leaflet map to pick coordinates
    echo "<div id='wl_place_coords_map'></div>";
    echo "<script type='text/javascript'>\n    \$ = jQuery;\n    \$(document).ready(function(){\n        \$('#wl_place_coords_map').width('100%').height('200px');\n        var wlMap = L.map('wl_place_coords_map').setView([" . $coords['latitude'] . "," . $coords['longitude'] . "], 9);\n    \n        L.tileLayer( 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',\n            { attribution: '&copy; <a href=http://osm.org/copyright>OpenStreetMap</a> contributors'}\n        ).addTo( wlMap );\n        \n        var marker = L.marker([" . $coords['latitude'] . "," . $coords['longitude'] . "]).addTo( wlMap );\n    \n        function refreshCoords(e) {\n            \$('#wl_place_lat').val( e.latlng.lat );\n            \$('#wl_place_lon').val( e.latlng.lng );\n            marker.setLatLng( e.latlng )\n        }\n\n        wlMap.on('click', refreshCoords);\n    });\n    </script>";
}
 public function get_data()
 {
     $entity_id = get_the_ID();
     $this->data = wl_get_coordinates($entity_id);
 }