Add Google Business Profile as a supported social platform - #270
Draft
paulocastellano wants to merge 49 commits into
Draft
Add Google Business Profile as a supported social platform#270paulocastellano wants to merge 49 commits into
paulocastellano wants to merge 49 commits into
Conversation
Implements GoogleBusinessAnalytics service to fetch five Google Business Profile performance metrics (website clicks, call clicks, direction requests, desktop map impressions, mobile map impressions) via the Performance API. Adds i18n keys to all 16 locale files. TDD: Red test passing, 3 assertions validated.
Replace English translations in 15 non-English locale files with proper translations matching each locale's existing terminology and style: - Arabic: Arabic translations - German: German translations - Greek: Greek translations - Spanish: Spanish translations - French: French translations - Italian: Italian translations - Japanese: Japanese translations - Korean: Korean translations - Dutch: Dutch translations - Polish: Polish translations - Portuguese-BR: Portuguese translations - Russian: Russian translations - Turkish: Turkish translations - Ukrainian: Ukrainian translations - Chinese: Chinese (Simplified) translations Verified by: LocalizationParityTest (18 passed) + GoogleBusinessAnalytics (2 passed)
Adds GoogleBusinessController with connect/callback/select-location/select routes, mirroring FacebookController's auto-connect-on-single-location and picker-on-multiple pattern. Registers the 'google-business' Socialite driver (separate from 'google-auth' and YouTube's 'google') and adds the required i18n keys across all 16 locales.
…form's post update platforms.*.meta.call_to_action.url used required_unless, an implicit Laravel validation rule that still runs when the field (and its whole call_to_action block) is absent. Since no other platform sends call_to_action at all, the missing action_type was treated as "not NONE/CALL" and made the URL required on every post update (Pinterest, Discord, TikTok, etc.) across web, the REST API, and MCP. Follow the existing board_id/channel_id pattern: keep the rules() entry unconditional and enforce the CTA-required-unless-NONE/CALL check only in requiredMetaViolation(), scoped to Platform::GoogleBusiness. Adds the cta_url_required translation key (all 16 locales) and test coverage for both the regression and the still-enforced Google Business requirement.
…ry points Closes the CLAUDE.md-mandated round-trip coverage gap for PostPlatformMetaRules' topic_type/call_to_action/event/offer fields, proving they survive the full validate-then-persist path through all three post entry points, plus a token-refresh-window regression test for the Google Business rotating refresh_token model.
…sTest The file has no namespace declaration, so ReflectionMethod is already in the global namespace. Importing it via 'use' is a no-op and raises an error under the test environment's error-reporting configuration.
…nd OAuth popup routes Platform.GoogleBusiness was undefined, so the composer settings card never mounted and the Connect button silently no-opped.
…s API
The v1 Business Information API returns Location.name in its short
locations/{id} form, but the v4 localPosts endpoint requires the full
accounts/*/locations/* parent. fetchLocationsForAccount now composes the
full name for meta.location_id and keeps the short name in
meta.location_name, which is what the v1 verify call expects.
…ller The controller had no SUPPORTED_PLATFORMS entry or match arm, so the service was unreachable. The Performance API call also used the full location resource name (it wants the short one) and encoded dailyMetrics as bracket-indexed array params instead of repeated scalars.
…-side Mirrors PostPlatformMetaRules::requiredMetaViolation() so the composer shows an inline tooltip instead of letting the user hit a raw 422.
Google's v4 Local Posts API requires the `event` field for both the EVENT and OFFER topic types, so Offer posts were being rejected with INVALID_ARGUMENT because no `event` object was ever attached. Both topic types now reuse the same `meta.event.*` fields (title + date range), matching the API shape and Google's own Business Profile app flow, where creating an Offer also asks for a title and date range before the coupon details. The backend publish requirement, the editor sub-form, and the frontend compliance gate are all gated on the shared topic-type list.
…ation
findError() matched backend error keys by suffix only, so a post targeting
two Google Business Profile locations showed one location's error under
both settings panels.
ChannelConfigurator now passes each settings panel its position in the
selected-channel list, and GoogleBusinessSettings matches the full
`platforms.{index}.meta.*` key. That position is the submitted index: the
editor builds the `platforms` payload by filtering the same post_platforms
list by the same selection, which is the mapping ScheduleTab already relies
on for content-type errors.
Pinterest and Discord share the same suffix-match limitation; fixing them
is left to a separate change.
callback() never read session('social_reconnect_id'), so the reconnect
branch in select() could never fire even once a reconnect trigger exists.
Captures it and stores it in the google_business_oauth session payload, the
same way InstagramFacebookController already does.
…or and preview The settings panel's option list and the preview's label lookup each hand-wrote the same action types, so adding or renaming one meant editing both. Both now read resources/js/lib/googleBusiness.ts.
It had no callers: the connect flow has no SocialAccount yet, so the controller always calls fetchLocations() with the raw access token.
- selectLocation() now checks manageAccounts like callback()/select() do - the locations fetched during callback() are cached in the OAuth session payload, so a multi-location connect hits Google once instead of three times - select()'s inline validation moves to a dedicated FormRequest
Also disables the topic-type pills in preview-only mode, like every other input in the panel.
… analytics services
… model and publisher
…type The connect grid had no google_business entry in its platform theme map, so the tile fell back to an empty image, and the automation Generate node had no case for the platform, leaving its content type blank.
data_get()'s default only applies when the key is missing, so a stored 'topic_type' => null published an empty topicType. Same bug class as the CTA action type fixed earlier. Also hoists the repeated EVENT/OFFER guard out of the match(true) arms and points the publisher at the shared topic-type constant instead of a literal copy of the list.
…oday
CarbonImmutable::parse('') resolves to now(), so a blank start or end date
reaching publish() silently sent today's date to Google. buildEvent() now
throws the same way the missing-location guard does.
…path The location-not-found exit left live access and refresh tokens in the session, unlike every other exit in select(). Also extracts the shared location attribute builder so the reconnect branch stops duplicating connectLocation().
…nd MCP entry points
…atform meta validation Captures two gotchas discovered while building the Google Business Profile integration, so the next platform addition finds them instead of re-deriving the same bugs.
paulocastellano
marked this pull request as draft
August 11, 2026 14:59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Google Business Profile as a supported social platform:
Test plan before merging