true ), 'objects' ) as $type ) { if ( ! in_array( $type->name, array( 'attachment', 'deltabreen_location' ), true ) ) { $out[ $type->name ] = $type->labels->name; } } return $out; } /** The meta key that says a post has a place, for the source the site chose. */ function deltabreen_maps_place_key() { $o = deltabreen_maps_options(); if ( 'acf' === $o['place_source'] ) { return sanitize_key( $o['place_acf'] ); } return 'meta' === $o['place_source'] ? (string) $o['place_meta_lat'] : '_deltabreen_place_lat'; } /** * A post's place: its point and the address to show, from the source the site chose; null when it has none. * * @param WP_Post $post The post. * @return array{lng: float, lat: float, address: string}|null */ function deltabreen_maps_post_place( $post ) { $o = deltabreen_maps_options(); $lat = null; $lng = null; $address = ''; if ( 'acf' === $o['place_source'] ) { $field = function_exists( 'get_field' ) && '' !== $o['place_acf'] ? get_field( $o['place_acf'], $post->ID, false ) : null; if ( is_array( $field ) ) { // A Google Map field holds lat, lng and address; an OpenStreetMap field may hold its point as markers. $at = ! empty( $field['markers'][0] ) && is_array( $field['markers'][0] ) ? $field['markers'][0] : $field; $lat = $at['lat'] ?? null; $lng = $at['lng'] ?? null; $address = (string) ( $field['address'] ?? ( $at['label'] ?? '' ) ); } } elseif ( 'meta' === $o['place_source'] ) { $lat = '' !== $o['place_meta_lat'] ? get_post_meta( $post->ID, $o['place_meta_lat'], true ) : null; $lng = '' !== $o['place_meta_lng'] ? get_post_meta( $post->ID, $o['place_meta_lng'], true ) : null; } else { $lat = get_post_meta( $post->ID, '_deltabreen_place_lat', true ); $lng = get_post_meta( $post->ID, '_deltabreen_place_lng', true ); $address = (string) get_post_meta( $post->ID, '_deltabreen_place_address', true ); } if ( ! is_numeric( $lat ) || ! is_numeric( $lng ) || abs( (float) $lat ) > 90 || abs( (float) $lng ) > 180 ) { return null; } return array( 'lng' => (float) $lng, 'lat' => (float) $lat, 'address' => $address, ); } /** * The published posts of a type that have a place, as the embed's pins, in one category or tag when asked; each pin * links to its post. Cached until such a post or the settings change. * * @param string $type A post type the site chose to carry places. * @param string $term A category or tag slug of that type, or empty for all. * @return array */ function deltabreen_maps_post_pins( $type, $term = '' ) { $type = sanitize_key( $type ); $term = sanitize_title( $term ); if ( '' === $type || ! in_array( $type, deltabreen_maps_place_types(), true ) ) { return array(); } $o = deltabreen_maps_options(); $key = 'deltabreen_maps_posts_' . md5( DELTABREEN_MAPS_VERSION . '|' . get_option( 'deltabreen_maps_posts_version', 1 ) . '|' . determine_locale() . '|' . $type . '|' . $term . '|' . wp_json_encode( array( $o['place_source'], $o['place_acf'], $o['place_meta_lat'], $o['place_meta_lng'] ) ) ); $cached = get_transient( $key ); if ( is_array( $cached ) ) { return $cached; } $args = array( 'post_type' => $type, 'post_status' => 'publish', 'posts_per_page' => DELTABREEN_MAPS_MAX_PINS, 'orderby' => 'title', 'order' => 'ASC', 'no_found_rows' => true, 'suppress_filters' => false, ); $has = deltabreen_maps_place_key(); if ( '' !== $has ) { // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- one cached query per change, not per view. $args['meta_query'] = array( array( 'key' => $has, 'compare' => 'EXISTS', ), ); } if ( '' !== $term ) { $any = array( 'relation' => 'OR' ); foreach ( get_object_taxonomies( $type, 'names' ) as $tax ) { $any[] = array( 'taxonomy' => $tax, 'field' => 'slug', 'terms' => array( $term ), ); } // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- one cached query per change, not per view. $args['tax_query'] = $any; } $pins = array(); foreach ( get_posts( $args ) as $post ) { $at = deltabreen_maps_post_place( $post ); if ( ! $at ) { continue; } // The post's own excerpt, or its words with shortcodes and blocks taken out, so no map draws inside another. $text = has_excerpt( $post ) ? $post->post_excerpt : wp_trim_words( wp_strip_all_tags( strip_shortcodes( excerpt_remove_blocks( $post->post_content ) ) ), 30, '…' ); $pin = deltabreen_maps_clean_pin( array( 'id' => 'post-' . $post->ID, 'lng' => $at['lng'], 'lat' => $at['lat'], 'title' => html_entity_decode( get_the_title( $post ), ENT_QUOTES, 'UTF-8' ), 'address' => $at['address'], 'text' => html_entity_decode( $text, ENT_QUOTES, 'UTF-8' ), 'photo' => (string) get_the_post_thumbnail_url( $post, 'medium' ), 'button' => __( 'Read more', 'maps-by-deltabreen' ), 'buttonUrl' => get_permalink( $post ), ) ); /** * One post's pin, before maps get it: change any field, or return null to leave it off every map. * * @param array|null $pin The pin as the embed takes it. * @param WP_Post $post The post. */ $pin = apply_filters( 'deltabreen_maps_post_pin', $pin, $post ); $pin = is_array( $pin ) ? deltabreen_maps_clean_pin( $pin ) : null; if ( $pin ) { $pins[] = $pin; } } set_transient( $key, $pins, DAY_IN_SECONDS ); return $pins; } /** Invalidate every cached list of post pins. */ function deltabreen_maps_bump_posts() { update_option( 'deltabreen_maps_posts_version', (int) get_option( 'deltabreen_maps_posts_version', 1 ) + 1, false ); } foreach ( array( 'save_post', 'deleted_post', 'trashed_post', 'untrashed_post' ) as $deltabreen_hook ) { add_action( $deltabreen_hook, function ( $post_id ) { if ( in_array( get_post_type( $post_id ), deltabreen_maps_place_types(), true ) ) { deltabreen_maps_bump_posts(); } } ); } add_action( 'add_meta_boxes', function ( $post_type ) { if ( 'box' === deltabreen_maps_options()['place_source'] && in_array( $post_type, deltabreen_maps_place_types(), true ) ) { add_meta_box( 'deltabreen-place', __( 'Place on the map', 'maps-by-deltabreen' ), 'deltabreen_maps_place_box', $post_type, 'side' ); } } ); /** The place box: an address to find, and the point a map shows the post at. */ function deltabreen_maps_place_box( $post ) { $get = function ( $field ) use ( $post ) { return (string) get_post_meta( $post->ID, '_deltabreen_place_' . $field, true ); }; wp_nonce_field( 'deltabreen_place_save', 'deltabreen_place_nonce' ); ?>


post_type, deltabreen_maps_place_types(), true ) || ! isset( $_POST['deltabreen_place_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['deltabreen_place_nonce'] ) ), 'deltabreen_place_save' ) ) { return; } if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! current_user_can( 'edit_post', $post_id ) || ! isset( $_POST['deltabreen_place'] ) || ! is_array( $_POST['deltabreen_place'] ) ) { return; } $in = array_map( 'sanitize_text_field', wp_unslash( $_POST['deltabreen_place'] ) ); $lng = $in['lng'] ?? ''; $lat = $in['lat'] ?? ''; update_post_meta( $post_id, '_deltabreen_place_address', deltabreen_maps_clean_text( $in['address'] ?? '', 200 ) ); if ( is_numeric( $lng ) && is_numeric( $lat ) && abs( (float) $lng ) <= 180 && abs( (float) $lat ) <= 90 ) { update_post_meta( $post_id, '_deltabreen_place_lng', (float) $lng ); update_post_meta( $post_id, '_deltabreen_place_lat', (float) $lat ); } else { delete_post_meta( $post_id, '_deltabreen_place_lng' ); delete_post_meta( $post_id, '_deltabreen_place_lat' ); } deltabreen_maps_bump_posts(); }, 10, 2 ); add_action( 'admin_enqueue_scripts', function ( $hook ) { $screen = get_current_screen(); if ( $screen && in_array( $hook, array( 'post.php', 'post-new.php' ), true ) && 'box' === deltabreen_maps_options()['place_source'] && in_array( $screen->post_type, deltabreen_maps_place_types(), true ) ) { deltabreen_maps_enqueue_admin(); wp_enqueue_script( 'deltabreen-maps-location', plugins_url( 'admin/location.js', __FILE__ ), array( 'deltabreen-maps-admin', 'wp-i18n' ), DELTABREEN_MAPS_VERSION, true ); deltabreen_maps_script_translations( 'deltabreen-maps-location' ); } } );