>, tiktok: array>} $config * @return array{ * head_html: string, * body_html: string, * track_lines: array, * track_jobs: array> * } */ public static function render(array $config): array { $fbRows = SplitPixelConfigService::getEnabledSorted($config, SplitPixelConfigService::PLATFORM_FACEBOOK); $tkRows = SplitPixelConfigService::getEnabledSorted($config, SplitPixelConfigService::PLATFORM_TIKTOK); $head = []; $initLines = []; $trackLines = []; $jobs = []; if ($fbRows !== []) { $head[] = self::facebookLoaderScript(); } if ($tkRows !== []) { $head[] = self::tiktokLoaderScript(); } foreach ($fbRows as $row) { $pixelId = self::escapeJsString((string) ($row['pixel_id'] ?? '')); $testCode = trim((string) ($row['test_code'] ?? '')); $event = self::escapeJsString((string) ($row['event'] ?? 'PageView')); if ($pixelId === '') { continue; } if ($testCode !== '') { $testEsc = self::escapeJsString($testCode); $initLines[] = "if(typeof fbq!=='undefined'){fbq('init','{$pixelId}',{},{test_event_code:'{$testEsc}'});}"; } else { $initLines[] = "if(typeof fbq!=='undefined'){fbq('init','{$pixelId}');}"; } $jobs[] = [ 'platform' => 'facebook', 'event' => (string) ($row['event'] ?? 'PageView'), 'pixel_id' => (string) ($row['pixel_id'] ?? ''), ]; $trackLines[] = "if(typeof fbq!=='undefined'){fbq('track','{$event}');}"; } foreach ($tkRows as $row) { $pixelId = self::escapeJsString((string) ($row['pixel_id'] ?? '')); $event = self::mapTikTokBrowserEvent((string) ($row['event'] ?? 'PageView')); $eventJs = self::escapeJsString($event); if ($pixelId === '') { continue; } $initLines[] = "if(typeof ttq!=='undefined'){ttq.load('{$pixelId}');ttq.page();}"; $jobs[] = [ 'platform' => 'tiktok', 'event' => $event, 'pixel_id' => (string) ($row['pixel_id'] ?? ''), ]; $trackLines[] = "if(typeof ttq!=='undefined'){ttq.track('{$eventJs}');}"; } return [ 'head_html' => implode("\n", $head), 'body_html' => self::wrapScriptBlock($initLines), 'track_lines' => $trackLines, 'track_jobs' => $jobs, ]; } /** * 跳转 orchestrator:在 setTimeout 回调内触发像素事件后再 replace * * @param array $trackLines */ public static function renderRedirectOrchestrator(string $redirectUrlJson, array $trackLines = [], int $maxWaitMs = 1500): string { $trackBlock = $trackLines !== [] ? implode("\n ", $trackLines) : ''; $script = self::renderRedirectOrchestratorScript(); return str_replace( ['{$redirectUrlJson}', '{$maxWaitMs}', '{$trackBlock}'], [$redirectUrlJson, (string) $maxWaitMs, $trackBlock], $script ); } private static function renderRedirectOrchestratorScript(): string { return <<<'JS' JS; } /** * @param array $lines */ private static function wrapScriptBlock(array $lines): string { if ($lines === []) { return ''; } return ''; } private static function facebookLoaderScript(): string { return <<<'HTML' HTML; } private static function tiktokLoaderScript(): string { return <<<'HTML' HTML; } private static function mapTikTokBrowserEvent(string $event): string { $map = [ 'PageView' => 'Pageview', 'Lead' => 'SubmitForm', 'Contact' => 'Contact', 'AddToCart' => 'AddToCart', 'Purchase' => 'CompletePayment', 'Subscribe' => 'Subscribe', ]; return $map[$event] ?? 'Pageview'; } private static function escapeJsString(string $value): string { return str_replace(['\\', "'"], ['\\\\', "\\'"], $value); } }