I recently had almost the exact same use case: - On saving a custom post type, check for the existance of some meta data. - If it exists, geocode it using the Google Geocode API. - Save the result as a new meta field (this one hidden so the user can't screw it up). - *Note: What I do with the data on the front end of the site is handled in a template file using javascript and the Google Maps API.* It looks like you're assembling multiple fields to get the address (I stored it in one) and you're saving the resulting format differently, but hopefully this serves as a good example that you can borrow from. As I always try to do, I used the WordPress API functions for querying and saving to the database. It's mores secure and future-proof. Just as @OriginalEXE suggests, I used the [`save_post` hook][1]. I don't think you need `publish_post`: > save_post is an action triggered whenever a post or page is created or updated, which could be from an import, post/page edit form, xmlrpc, or post by email. A few more notes: - Note the lower priority of the action. I found that leaving it as the default priority left it looking at the previously saved data (which is saved using Advanced Custom Fields which it looks like you're using). - The geocoding class was not mine and saved me a huge amount of time. I modified what Sergiy published to use the `wp_remote_get()` function that has better server support than either `curl` or `file_get_contents`. It uses the JSON (Google-recommended) request rather than XML. I put this in a functionality plugin, but it would work the same in `functions.php`: /* function wc_add_latlong() * take address from post, geocode it, and save as a custom meta field * @parameter $post_id, id of the post being saved, passed by save_post hook * @returns nothing **************************************/ function wc_add_latlong( $post_id ) { // get the address from ACF field $address = get_field( 'wc_map_address', $post_id ); // Check to see if the post type is right, it's not a revision, and there is an address to geocode if( get_post_type( $post_id ) == 'wc_biz' && !wp_is_post_revision( $post_id ) && $address ) { // call the geocoder class below $coords = geocoder::getLocation( $address ); // split latLngObject with a comma and space $lat_long_string = $coords['lat'] . ', ' . $coords['lng']; // either add that value as a new post meta field OR update the existing one add_post_meta( $post_id, '_wc_lat_long', $lat_long_string, true ) || update_post_meta( $post_id, '_wc_lat_long', $lat_long_string ); } } // This runs on the save_post hook add_action( 'save_post', 'wc_add_latlong', 11 ); // Thank you Sergiy! // http://erlycoder.com/45/php-server-side-geocoding-with-google-maps-api-v3 // a class to get the lat and long of an address _server-side_ class geocoder{ // The base URL for a non-sensor json Google Geocode API request static private $url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address="; static public function getLocation($address){ // append URL-friendly address to base URL $url = self::$url.urlencode($address); // request the Geocode JSON object from Google $resp_json = wp_remote_get($url); // decode the body of the response $resp = json_decode( wp_remote_retrieve_body($resp_json), true ); // make sure the remove_get was successful and it geocoded the address if( !is_wp_error( $resp_json ) && $resp['status']='OK' ) { // success! return the lat and long return $resp['results'][0]['geometry']['location']; }else{ // we failed, return false return false; } } } UPDATE: I've commented all the code so you can understand what's going on. You'll have to adapt it from there. [1]: http://codex.wordpress.org/Plugin_API/Action_Reference/save_post