Skip to content

Latest commit

 

History

History
571 lines (432 loc) · 17.6 KB

USAGE.md

File metadata and controls

571 lines (432 loc) · 17.6 KB

Usage

Writing and Reading Data

Store GeoJSON strings as metadata like you would for any other metadata.

Add geometry to a post:

$single_feature = '{ "type": "Feature", "geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, "properties": {"prop0": "value0"} }';
add_post_meta(15,'singlegeom',$single_feature,false);

Update the post geometry:

$single_feature = '{ "type": "Feature", "geometry": {"type": "Point", "coordinates": [-93.5, 45]}, "properties": {"prop0": "value0"} }';
update_post_meta(15,'singlegeom',$single_feature,false);

Read GeoJSON back from the post;

$single_feature = get_post_meta(15, 'singlegeom'); 
print $singlegeom;
// '{ "type": "Feature", "geometry": {"type": "Point", "coordinates": [-93.5, 45]}, "properties": {"prop0": "value0"} }';

Querying

Querying is done through the WP_Query meta_query argument. See WP Spatial Capabilities Check to generate a list of supported spatial functions for your system.

There are three styles of queries supported, to cover three different classes of spatial functions

  1. Query comparing geometries

This style of query is for all spatial functions which accept two geometries as arguments and which return a boolean as a result. For example ST_INTERSECTS, CONTAINS or MBROverlaps.

The meta_query compare is the function to use, and the value should be a GeoJSON representation of the geometry to use for the second argument. The geometry meta field indicated by the key parameter will be used as the first argument to the compare function.

   $q = new WP_Query( array(
   	'meta_query' => array(
   		array(
   			'key' => 'singlegeom',
   			'compare' => 'ST_INTERSECTS',
   			'value' => '{"type":"Feature","geometry":{"type":"Point","coordinates":[-93.5,45]}}',
   		)
   	)
   ));
   
   while($q->have_posts() ) {
   	$q->the_post();
   	print "\t* " . get_the_title() . "\n";
   }
  1. Query geometry properties

This style of query is for all spatial functions which accept a single geometry as an argument and which return a boolean as a result. For example ST_IsSimple, IsClosed or ST_IsEmpty.

The compare argument should be the function just like above, but no value is needed.

   $q = new WP_Query(array( 
   	'meta_query' => array( 
   		array( 
   		'key' => 'wpgeometa_test',
   		'compare' => 'ST_IsEmpty'
   		)
   	)));
  1. Compare the results of geometry functions

This style of query is for spatial functions which accept a single geometry as an argument but return a non-boolean response. For example, GLength, ST_Area or ST_SRID.

In these queries you may want to use a normal meta_query comparison (=, >, BETWEEN, etc.) but against the result of a spatial function. To accomodate this type of case, you will need to add an additional parameter geom_op.

The key, compare and value are used in the regular WP_Query way, but the comparison will be made against the result of applying the geometry function to the spatial metadata specified.

   $q = new WP_Query(array(
   	'meta_query' => array(
   		array( 
   		'key' => 'wpgeometa_test',
   		'compare' => '>',
   		'value' => '100',
   		'geom_op' => 'NumPoints'
   	)
   	))); 

Support Comparison Operations

Any spatial operation that takes two geometries and returns a boolean, or which takes one geometry and returns a boolean or a value is supported, if your version of MySQL supports it.

The following function should work, if your install of MySQL supports them:

Area Contains Crosses Dimension
Disjoint Equals GLength GeometryType
Intersects IsClosed IsEmpty IsRing
IsSimple MBRContains MBRCoveredBy MBRDisjoint
MBREqual MBREquals MBRIntersects MBROverlaps
MBRTouches MBRWithin NumGeometries NumInteriorRings
NumPoints Overlaps SRID ST_Area
ST_Contains ST_Crosses ST_Difference ST_Dimension
ST_Disjoint ST_Distance ST_Distance_Sphere ST_Equals
ST_GeometryType ST_Intersects ST_IsClosed ST_IsEmpty
ST_IsRing ST_IsSimple ST_IsValid ST_Length
ST_NumPoints ST_Overlaps ST_SRID ST_Touches
ST_Within Touches Within

To see what your install of MySQL supports, install WP Spatial Capabilities Check. We recommend using MySQL 5.6.1 or higher since it included many important updates to spatial operators.

ORDER BY

orderby with named meta clauses should work.

  1. Single arg orderby (eg. Dimension, GLength, ST_Area)

    $wpq = new WP_Query(array( 'post_type' => 'geo_test', 'orderby' => ARRAY( 'dimensions' => 'ASC', 'titlemeta' => 'ASC' ), 'meta_query' => array( 'dimensions' => array( 'key' => 'wpgeometa_test', 'geom_op' => 'ST_Dimension' ) )));

  2. Two argument function that returns a value, eg. ST_Distance. Note that I use 'type' => 'FLOAT' so that sorting is done numerically, instead of alphabetically.

    $wpq = new WP_Query(array( 'post_type' => 'geo_test', 'orderby' => 'distance', 'order' => 'ASC', 'meta_query' => array( 'distance' => array( 'key' => 'wpgeometa_test', 'compare' => 'ST_Distance', 'value' => '{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-1.26,1.08],[-1.26,1.09],[-1.21,1.09],[-1.21,1.08],[-1.26,1.08]]]}}', 'type' => 'FLOAT' ) )));

WordPress Hooks

The power of WordPress come partly from its Hooks system. WP-GeoMeta-Lib tries to provide the neccessary hooks so that you can extend it to suit your needs. If there's a hook that you need send me a pull request or file an issue.

Filters

  • wpgm_pre_metaval_to_geom

This filter is called right before WP-GeoMeta tries to convert the incoming meta value to geometry. It is used internally to handle separate latitude and longitude values and could be used to support other unusual situations. If you just need to convert a non-geojson geometry to WKT, you should use wpgq_metaval_to_geom instead.

Usage:

   add_filter( 'wpgm_pre_metaval_to_geom', 'myplugin_handle_pre_metaval', 10, 2 );

   /*
    * @param array  $meta_args Array with the meta_id that was just saved, the object_id it was for, the meta_key and meta_values used.
    *  $meta_args[0] -- meta_id from insert.
    *  $meta_args[1] -- object_id which this applies to.
    *  $meta_args[2] -- meta key.
    *  $meta_args[3] -- the meta value.
    *
    * @param string $object_type Which WP type is it? (comment/user/post/term).
    */
   public static function handle_latlng_meta( $meta_args, $object_type ) {
   	// Return early if it's not the key we're looking for.
   	if ( 'special meta key' !== $meta_args[2] ) {
   		return $meta_args;
   	}

   	// Do some stuff, then return $meta_args.
   	return $meta_args;
   }
  • wpgm_pre_delete_geometa

This filter is called after a meta value has been deleted from the regular meta table, right before WP-GeoMeta deletes the corresponding value from the geometa table. Deletions are done based on the regular meta table's meta ID. This filter is used internally to delete the geo meta value when a latitude or longitude meta value is deleted from the non-geo meta tables.

Usage:

   add_filter( 'wpgm_pre_delete_geometa', 'special_delete_scenario', 10, 5 );

   /*
    * @param array  $meta_ids The Meta IDs that will be deleted.
    * @param string $type The type of object whose meta is being deleted.
    * @param int    $object_id The ID of the object whose meta is being deleted.
    * @param string $meta_key The name of the meta key which is being deleted.
    * @param string $meta_value The value which is being deleted.
    */
   public function special_delete_scenario( $meta_ids, $type, $object_id, $meta_key, $meta_value ) {

   	if ( 'special meta key' !== $meta_key ) {
   		return $meta_ids;
   	}

   	// Do some stuff, then return $meta_ids;
   	return $meta_ids;
   }
  • wpgm_geoquery_srid

This filter is called during plugins_loaded. It sets the SRID that will be used when storing values in the database. The default value is 4326 (for EPSG:4326), which is the standard for GeoJSON.

MySQL doesn't support ST_Transform, and will complain if two geometries being compared have different SRIDs. As such, this option is dangerous and should be left alone unless you know what you're doing.

  • wpgm_metaval_to_geom

This filter is called within WP_GeoUtil::metaval_to_geom. It offers an opportunity to support non-GeoJSON geometry types.

Functions implementing this filter should either return the incoming $metaval untouched or return WKT (best) or GeoJSON (will work).

Usage:

   add_filter( 'wpgm_metaval_to_geom', 'kml_to_geometry' );

   /**
     * @param string $metaval The metavalue that we're about to store.
     */
   function kml_to_geometry( $metaval ) {

   	if ( !is_kml( $metaval ) ) {
   		return $metaval;
   	}

   	$wkt = kml_to_wkt( $metaval );

   	return $wkt;
   }
  • wpgm_geom_to_geojson

This filter is called when converting a geometry from the database into GeoJSON so it can be displayed on a map (or whatever).

This could be used to do transformations or other alterations to geometries before displaying them.

Usage:

   add_filter( 'wpgm_geom_to_geojson', 'myplugin_geom_to_geojson' );

   /**
     * @param string $wkt The well known text representation of the geometry
     from the database.
     */
   function myplugin_geom_to_geojson( $wkt ) {
   	$geojson = myfunc_wkt_to_geojson( $wkt );

   	// Do something to the geojson
   	return $geojson;
   }
  • wpgm_known_capabilities

This filter is available so you can make your custom MySQL functions known to other users of WP-GeoMeta-Lib. Your function will be included in the list returned by WP_GeoUtil::get_capabilities(), if it is in fact available in MySQL.

You can also use it to detect if an optional library is installed.

NOTE: During your plugin activation you should run WP_GeoUtil::get_capabilities( true );, otherwise the cached list of capabilites will continue to be used.

Usage:

   add_filter( 'wpgm_known_capabilities', 'myplugin_add_support_for_my_func' );

   function myplugin_add_support_for_my_func( $all_funcs ) {
   	$all_funcs[] = 'my_custom_mysql_function';
   	return $all_funcs;
   }

   // ... later ...

   $all_caps = WP_GeoUtil::get_capabilities();
   if ( in_array( 'my_custom_mysql_function', $all_caps ) ) {
   	// Do my stuff
   } else {
   	// Notify the admin
   }
  • wpgm_extra_sql_functions

This filter allows you to add additional custom SQL functions to MySQL. Combined with wpgm_known_capabilites you can fully integrate your custom SQL into WP-GeoMeta-Lib.

This filter produces an array of file system paths to files containing SQL functions. The files should use $$ as the delimiter for the function. Please see any of the .sql files in this project for examples.

Usage:

   add_filter( 'wpgm_extra_sql_functions', 'myplugin_add_extra_sql' );

   function myplugin_add_extra_sql( $all_sql_files ) {

   	$my_sql_files = array(
   		'custom_func1.sql',
   		'custom_func2.sql'
   	);

   	foreach( $my_sql_files as $my_file ) {
   		$full_path = dirname( __FILE__ ) . '/sql/' . $my_file;

   		if ( !in_array( $full_path, $all_sql_files ) ) {
   			$all_sql_files[] = $full_path;
   		}
   	}

   	return $all_sql_files;
   }

Actions

  • wpgm_populate_geo_tables

This action is called at the end of WP_GeoMeta->populate_geo_tables() to give you an opportunity to populate the geo metatables with any non-GeoJSON types of geometry you are supporting. It is used internally to support populating the geo metatables with any latitude/longitude pairs added through WP_GeoMeta::add_latlng_field.

Usage:

   add_filter( 'wpgm_populate_geo_tables', 'myplugin_populate_kml' );

   function myplugin_populate_kml() {
   	global $wpdb;

   	$wpgeometa = WP_GeoMeta::get_instance();

   	$query = "SELECT post_id, meta_id, meta_key, meta_value 
   		FROM wp_postmeta 
   		WHERE meta_value LIKE '<?xml%/kml/2.2%'";

   	$res = $query->get_results( $query, ARRAY_A );
   	foreach( $res as $row ) {
   		// We don't have to convert KML to WKT because the filters we have set up will get called.
   		$wpgeometa->updated_post_meta( $row[ 'meta_id' ], $row[ 'post_id' ], $row[ 'meta_key' ], $row[ 'meta_value' ] );
   	}
   }

Calling Spatial Functions From PHP

Sometimes you might just need to run a spatial operation on a spatial value. WP-GeoMeta-Lib makes this easy!

You can call any spatial function your install of MySQL supports as a static method of WP_GeoUtil. These functions conveniently accept GeoJSON geometry so you don't have to convert your spatial data into Well Known Text (WKT) for MySQL.

Examples

Check if two GeoJSON shapes intersect

$do_they_intersect = WP_GeoUtil::ST_Intersects({PointGeoJSON},{PolygonGeoJSON});

Union (combine) two GeoJSON polygons

$spatial_union = WP_GeoUtil::ST_Union({PolygonGeoJSON_1},{PolygonGeoJSON_2});

Custom Auxiliary Functions

Besides the default spatial functions included with MySQL, WP-GeoMeta-Lib provides the filter wpgq_known_capabilities which lets you add support for your own spatial SQL functions. These can be UDF (User Defined Functions) or Stored Functions.

WP-GeoMeta-Lib includes several stored functions for your convenience.

The functions included are:

  • wp_buffer_point_m( p POINT, radius FLOAT, segments INT)

    Buffer a point by a number of meters. Returns a polygon approximating a circle.

    • p A single point geometry with coordinates in EPSG:4326 (the common latitude/longitude format, like 45.0,-93.3)
    • radius The distance to buffer the point, in meters.
    • segments The number of segments per quarter of a circle. Eg. If you set this to 4, then your resulting polygon will have 16 segments.
  • wp_buffer_point_mi( p POINT, radius FLOAT, segments INT)

    Buffer a point by a number of miles. Returns a polygon approximating a circle.

    • p A single point geometry with coordinates in EPSG:4326.
    • radius The distance to buffer the point, in miles.
    • segments The number of segments per quarter of a circle. Eg. If you set this to 4, then your resulting polygon will have 16 segments.
  • wp_buffer_point_real( p POINT, radius FLOAT, segments INT, eradius INTEGER)

    Buffer a point assuming an earth with a specified radius. Returns a polygon approximating a circle.

    • p A single point geometry with coordinates in EPSG:4326.
    • radius The distance to buffer the point, in any units.
    • segments The number of segments per quarter of a circle. Eg. If you set this to 4, then your resulting polygon will have 16 segments.
    • eradius The radius of the earth in the same units as radius
  • wp_distance_point_m( p1 POINT, p2 POINT)

    Get the distance between two points in meters.

    • p1 A single point geometry with coordinates in EPSG:4326.
    • p2 A single point geometry with coordinates in EPSG:4326.
  • wp_distance_point_mi( p1 POINT, p2 POINT)

    Get the distance between two points in miles.

    • p1 A single point geometry with coordinates in EPSG:4326.
    • p2 A single point geometry with coordinates in EPSG:4326.
  • wp_distance_point_real( p1 POINT, p2 POINT, radius FLOAT)

    Get the distance between two points for a given radius of the earth.

    • p1 A single point geometry with coordinates in EPSG:4326.
    • p2 A single point geometry with coordinates in EPSG:4326.
    • radius The radius of the earth in the units you want your results in.
  • wp_first_geom( p GEOMETRY )

    Get the first geometry from a multi-geometry. If p is not a multi-geometry, it will be returned unchanged.

    • p A geometry object.
  • wp_point_bearing_distance_to_line_m(p POINT, bearing FLOAT, distance FLOAT)

    Create a linestring given a starting point, a bearing and a distance in meters.

    p A single point geometry with coordinates in EPSG:4326. bearing The bearing to travel in degrees. 0 degrees is north. distance The number of meters to travel.

  • wp_point_bearing_distance_to_line_mi(p POINT, bearing FLOAT, distance FLOAT)

    Create a linestring given a starting point, a bearing and a distance in miles.

    p A single point geometry with coordinates in EPSG:4326. bearing The bearing to travel in degrees. 0 degrees is north. distance The number of miles to travel.

  • wp_point_bearing_distance_to_line(p POINT, bearing FLOAT, distance FLOAT, eradius INTEGER)

    Create a linestring given a starting point, a bearing, a distance and the radius of the earth.

    p A single point geometry with coordinates in EPSG:4326. bearing The bearing to travel in degrees. 0 degrees is north. distance The distance to travel. eradius The radius of the earth in the same units as distance.

  • wp_point_bearing_distance_coord_pair(p POINT, bearing FLOAT, distance FLOAT, eradius INTEGER)

    Get the point a given distance from a starting point on a given bearing for a given radius of the earth.

    p A single point geometry with coordinates in EPSG:4326. bearing The bearing to travel in degrees. 0 degrees is north. distance The distance to travel. eradius The radius of the earth in the same units as distance.