'; $html .= ''; $html .= '

' . esc_html( $text ) . '

'; $html .= ''; $html .= '
'; return $html; } } if ( ! function_exists( 'airowp_render_map' ) ) { /** * Renders the Map block on the front end. * * @param array $attributes Block attributes. * @param string $content Block content (unused). * @param WP_Block $block Block instance. */ function airowp_render_map( $attributes, $content, $block ) { $provider = isset( $attributes['dsgoProvider'] ) ? (string) $attributes['dsgoProvider'] : 'openstreetmap'; $latitude = isset( $attributes['dsgoLatitude'] ) ? (float) $attributes['dsgoLatitude'] : 40.7128; $longitude = isset( $attributes['dsgoLongitude'] ) ? (float) $attributes['dsgoLongitude'] : -74.006; $zoom = isset( $attributes['dsgoZoom'] ) ? (int) $attributes['dsgoZoom'] : 13; $address = isset( $attributes['dsgoAddress'] ) ? (string) $attributes['dsgoAddress'] : ''; $marker_icon = isset( $attributes['dsgoMarkerIcon'] ) && '' !== $attributes['dsgoMarkerIcon'] ? (string) $attributes['dsgoMarkerIcon'] : '📍'; $height = isset( $attributes['dsgoHeight'] ) ? (string) $attributes['dsgoHeight'] : '400px'; $aspect_ratio = isset( $attributes['dsgoAspectRatio'] ) ? (string) $attributes['dsgoAspectRatio'] : 'custom'; $privacy_mode = ! empty( $attributes['dsgoPrivacyMode'] ); $privacy_note = isset( $attributes['dsgoPrivacyNotice'] ) ? (string) $attributes['dsgoPrivacyNotice'] : ''; $map_style = isset( $attributes['dsgoMapStyle'] ) ? (string) $attributes['dsgoMapStyle'] : 'standard'; // Marker colour: explicit attribute → kit theme.json custom → default, then filter. $marker_color = ''; if ( isset( $attributes['dsgoMarkerColor'] ) && '' !== $attributes['dsgoMarkerColor'] ) { $marker_color = (string) $attributes['dsgoMarkerColor']; } elseif ( function_exists( 'wp_get_global_settings' ) ) { $kit_color = wp_get_global_settings( array( 'custom', 'airo-wp', 'map', 'markerColor' ) ); if ( is_string( $kit_color ) && '' !== $kit_color ) { $marker_color = $kit_color; } } if ( '' === $marker_color ) { $marker_color = '#e74c3c'; } /** * Filter the resolved map marker colour before it is written to the wrapper. * * @param string $marker_color Resolved colour (CSS colour string). * @param array $attributes Block attributes. * @param WP_Block $block Block instance. */ $marker_color = (string) apply_filters( 'airowp_map_marker_color', $marker_color, $attributes, $block ); // The color control stores theme palette selections as the preset shorthand // "var:preset|color|{slug}" so the block tracks theme changes. Resolve it to a // concrete value here: the marker is drawn by view.js, which cannot inherit the // page's CSS custom properties. Fall back to the block default when the preset // slug is missing from the active palette. $marker_color = airowp_resolve_preset_color( $marker_color, '#e74c3c' ); // No location yet (a freshly inserted map starts at 0,0 with no // address, see index.js): render nothing rather than a map of the // ocean off West Africa. Mirrors hasNoLocation() in MapPlaceholder.js. if ( 0.0 === $latitude && 0.0 === $longitude && '' === trim( $address ) ) { return; } // Clamp coordinates / zoom to valid ranges (mirrors save.js). $safe_lat = max( -90, min( 90, $latitude ) ); $safe_lng = max( -180, min( 180, $longitude ) ); $safe_zoom = max( 1, min( 20, $zoom ) ); // Wrapper classes — must mirror edit.js / the prior save(). $classes = 'airo-wp-map'; if ( $privacy_mode ) { $classes .= ' airo-wp-map--privacy-mode'; } if ( 'custom' !== $aspect_ratio ) { $classes .= ' airo-wp-map--aspect-' . str_replace( ':', '-', $aspect_ratio ); } // Height is only inline when the author picked a custom aspect ratio. $wrapper_args = array( 'class' => $classes ); if ( 'custom' === $aspect_ratio ) { $wrapper_args['style'] = 'height:' . $height; } $wrapper_attributes = get_block_wrapper_attributes( $wrapper_args ); // Config consumed by view.js (kept identical to the prior static output). $data_attributes = array( 'data-airo-wp-provider' => $provider, 'data-airo-wp-lat' => (string) $safe_lat, 'data-airo-wp-lng' => (string) $safe_lng, 'data-airo-wp-zoom' => (string) $safe_zoom, 'data-airo-wp-address' => $address, 'data-airo-wp-marker-icon' => $marker_icon, 'data-airo-wp-marker-color' => $marker_color, 'data-airo-wp-privacy-mode' => $privacy_mode ? 'true' : 'false', 'data-airo-wp-map-style' => $map_style, ); $aria_label = '' !== $address /* translators: %s: The address being shown on the map */ ? sprintf( __( 'Map showing %s', 'airo-wp' ), $address ) : __( 'Interactive map', 'airo-wp' ); // In privacy mode view.js builds the map container itself, after // consent, so it needs the localized label handed over. if ( $privacy_mode ) { $data_attributes['data-airo-wp-map-label'] = $aria_label; } $data_attr_html = ''; foreach ( $data_attributes as $key => $value ) { $data_attr_html .= ' ' . $key . '="' . esc_attr( $value ) . '"'; } // The keyless Google provider is a plain iframe built server-side: no // Maps JS API, no Leaflet, and no geocoding round-trip, so outside of // privacy mode the block needs no JavaScript at all. The marker icon / // colour and map style attributes have no effect here — Google owns the // rendering — which is why the inspector hides those controls. if ( 'googlemaps-embed' === $provider ) { $embed_url = airowp_map_embed_url( $address, $safe_lat, $safe_lng, $safe_zoom ); // In privacy mode the URL is parked until the visitor asks for it, // so no request reaches Google on page load. $src_attribute = $privacy_mode ? 'data-airo-wp-src="' . esc_url( $embed_url ) . '"' : 'src="' . esc_url( $embed_url ) . '"'; $inner = ''; if ( $privacy_mode ) { $inner .= airowp_map_privacy_overlay( $privacy_note ); } echo '
' . $inner . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped return; } if ( $privacy_mode ) { $inner = airowp_map_privacy_overlay( $privacy_note ); } else { $inner = '
'; } echo '
' . $inner . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } airowp_render_map( $attributes, $content, $block );