settings = $settings; } public function get_id(): string { return 'LocalBusiness'; } public function applies_to( \WP_Post $post ): bool { $settings = $this->settings->get(); if ( ! (bool) $settings['local_business_enabled'] ) { return false; } // Scope: Google reads LocalBusiness on pages describing the business // (front page, contact page) — 'site' (default, backward-compatible) // still emits it everywhere as the site's brand identity. $scope = (string) ( $settings['local_business_scope'] ?? 'site' ); if ( 'site' === $scope ) { return true; } $is_front = $post->ID === (int) get_option( 'page_on_front' ) || is_front_page(); if ( 'front_page' === $scope ) { return $is_front; } return $is_front || in_array( $post->ID, array_map( 'intval', (array) ( $settings['local_business_page_ids'] ?? array() ) ), true ); } public function build( \WP_Post $post ): array { $settings = $this->settings->get(); $data = array( '@type' => $settings['local_business_type'], '@id' => SchemaIds::local_business(), 'name' => '' !== $settings['organization_name'] ? $settings['organization_name'] : get_bloginfo( 'name' ), 'url' => home_url( '/' ), ); $address = array_filter( array( 'streetAddress' => (string) $settings['local_business_street'], 'addressLocality' => (string) $settings['local_business_locality'], 'addressRegion' => (string) $settings['local_business_region'], 'postalCode' => (string) $settings['local_business_postal'], 'addressCountry' => (string) $settings['local_business_country'], ) ); if ( array() !== $address ) { $data['address'] = array_merge( array( '@type' => 'PostalAddress' ), $address ); } if ( '' !== $settings['local_business_phone'] ) { $data['telephone'] = $settings['local_business_phone']; } if ( '' !== $settings['local_business_lat'] && '' !== $settings['local_business_lng'] ) { $data['geo'] = array( '@type' => 'GeoCoordinates', 'latitude' => $settings['local_business_lat'], 'longitude' => $settings['local_business_lng'], ); } $hours = $this->opening_hours( (string) $settings['local_business_hours'] ); if ( array() !== $hours ) { $data['openingHoursSpecification'] = $hours; } /** * Filters the LocalBusiness schema node. * * @param array $data * @param \WP_Post $post */ return (array) apply_filters( 'acez_seo_local_business', $data, $post ); } /** * Parses simple lines like "Mo-Fr 09:00-17:00" or "Sa 10:00-14:00" into * OpeningHoursSpecification entries. Unparseable lines are skipped rather * than breaking the whole node. * * @return array> */ private function opening_hours( string $raw ): array { $days = array( 'mo' => 'Monday', 'tu' => 'Tuesday', 'we' => 'Wednesday', 'th' => 'Thursday', 'fr' => 'Friday', 'sa' => 'Saturday', 'su' => 'Sunday', ); $specs = array(); foreach ( preg_split( '/\r\n|\r|\n/', $raw ) as $line ) { $line = trim( (string) $line ); if ( '' === $line ) { continue; } if ( ! preg_match( '/^([A-Za-z]{2})(?:-([A-Za-z]{2}))?\s+(\d{1,2}:\d{2})-(\d{1,2}:\d{2})$/', $line, $matches ) ) { continue; } $start_key = strtolower( $matches[1] ); $end_key = '' !== $matches[2] ? strtolower( $matches[2] ) : $start_key; if ( ! isset( $days[ $start_key ], $days[ $end_key ] ) ) { continue; } $day_keys = array_keys( $days ); $start_index = array_search( $start_key, $day_keys, true ); $end_index = array_search( $end_key, $day_keys, true ); $day_of_week = array(); if ( false !== $start_index && false !== $end_index && $start_index <= $end_index ) { for ( $i = $start_index; $i <= $end_index; $i++ ) { $day_of_week[] = 'https://schema.org/' . $days[ $day_keys[ $i ] ]; } } if ( array() === $day_of_week ) { continue; } $specs[] = array( '@type' => 'OpeningHoursSpecification', 'dayOfWeek' => $day_of_week, 'opens' => $matches[3], 'closes' => $matches[4], ); } return $specs; } }