sebastian blum www.sblum.de 13.04.2023 1
PHP-SEO
Sebastian Blum
Vortrag online unterwww.sblum.de/#!seocampixx2013
Quelltext online untergithub.com/sebastianblum/seocampixx2013
sebastian blum www.sblum.de 13.04.2023 2
Agenda
a) PHP-Proxyblogger.com Free-Blog in einem Unterverzeichnis hosten
b) Conversion-Trackinggenaue Conversion-Messung mit eigener Applikation
sebastian blum www.sblum.de 13.04.2023 3
BLOGGER.COM IN UNTERVERZEICHNIS HOSTEN
PHP-Proxy
sebastian blum www.sblum.de 13.04.2023 4
blogger.com in Unterverzeichnis hosten
GrundideeEin einfacher Blog wird bei blogger.com erstellt und anschließend komplett als Unterseite in eine bestehende Domain eingebunden.
Vorteile• Kein Hosting der Seite => Beim Hoster einfachstes
Grundmodell möglich (PHP ohne Datenbank), ab 1,90 Euro im Monat bei hetzner.de
• Keine Installation des Blog-Systems notwendig• Keine Datenbank-Installation notwendig• Keine Sicherheitupdates notwendig
sebastian blum www.sblum.de 13.04.2023 5
blogger.com in Unterverzeichnis hosten
GrundideeEin einfacher Blog wird bei blogger.com erstellt und anschließend komplett als Unterseite in eine bestehende Domain eingebunden.
Einsatzszenarien• Eigene Seite um einfachen Blog / Newsfeed
ergänzen• Domain-Parking: Seiten vor-projektieren• Verschiedene IPs und Provider• Kein Netzwerkeffekt
sebastian blum www.sblum.de 13.04.2023 6
Blogs in Unterverzeichnis hosten
sebastian blum www.sblum.de 13.04.2023 7
blogger.com in Unterverzeichnis hosten
Damit kein Duplicate Content entsteht, muss der Free-Blog entweder auf noindex gesetzt werden oder der Canonical-Tag auf das richtige Ziel zeigen.
Beispiel: http://seo-campixx-13.blogspot.de/ => http
://seocampixx.sebastianblum.com/blog
Anpassungen im Blog
sebastian blum www.sblum.de 13.04.2023 8
blogger.com in Unterverzeichnis hosten
Blog
sebastian blum www.sblum.de 13.04.2023 9
blogger.com hosten - PHP-Skript (Übersicht)$blog = $app['controllers_factory']; $blog->get('/{year}/{month}/{slug}', function ($year, $month, $slug) use ($app) { $originUrl = rtrim(implode('/', array('http://seo-campixx-13.blogspot.de', $year, $month, $slug)), '/'); // Request from blogger.com $ch = curl_init($originUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $htmlResponse = curl_exec($ch); $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); // Change Url $htmlResponse = preg_replace('#http://seo-campixx-13.blogspot.(:?com|de)/#', 'http://' . $app['request']->getHttpHost() . '/blog/', $htmlResponse); // Change Meta-Tag Robots $htmlResponse = str_replace("'noindex,nofollow'", "'index,follow'", $htmlResponse); return new Response($htmlResponse, $httpStatusCode, array('Content-Type' => $contentType));})->value('year', null)->value('month', null)->value('slug', null)->bind('blog'); $blog->get('/', function () use ($app) { return $app->redirect('/blog');}); return $blog;
(Mit Micro-Framework Silex)
sebastian blum www.sblum.de 13.04.2023 10
blogger.com hosten - PHP-Skript /1
$blog = $app['controllers_factory']; $blog->get('/{year}/{month}/{slug}', function ($year, $month, $slug) use ($app) { $originUrl = rtrim(implode('/', array('http://seo-campixx-
13.blogspot.de', $year, $month, $slug)), '/'); // Request from blogger.com $ch = curl_init($originUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $htmlResponse = curl_exec($ch); $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
(Mit Micro-Framework Silex)
sebastian blum www.sblum.de 13.04.2023 11
blogger.com hosten - PHP-Skript /2
// Change Url $htmlResponse = preg_replace('#http://seo-campixx-
13.blogspot.(:?com|de)/#', 'http://' . $app['request']->getHttpHost() . '/blog/', $htmlResponse);
// Change Meta-Tag Robots $htmlResponse = str_replace("'noindex,nofollow'",
"'index,follow'", $htmlResponse); return new Response($htmlResponse, $httpStatusCode,
array('Content-Type' => $contentType));})->value('year', null)->value('month', null)->value('slug', null)->bind('blog');
(Mit Micro-Framework Silex)
sebastian blum www.sblum.de 13.04.2023 12
blogger.com hosten - PHP-Skript /3
Controller aktivieren:
$app->mount('/blog', include 'blog.php');
(Mit Micro-Framework Silex)
sebastian blum www.sblum.de 13.04.2023 13
Blogs in Unterverzeichnis hosten
Erweiterte Einsatzmöglichkeiten
Eine Wordpress-Multisite-Installation kann bequem auf einem eigenem Server installiert werden.Auf die Satelliten-Seiten wird lediglich ein einfaches PHP-Proxy-Skript kopiert:
• Ein zentraler Login• Wordpress-Aktualisierungen aller Blogs
gleichzeitig• Verschiedene Anbieter, IPs, Nameserver
sebastian blum www.sblum.de 13.04.2023 14
Blogs in Unterverzeichnis hosten
sebastian blum www.sblum.de 13.04.2023 15
Blogs in Unterverzeichnis hosten
Erweiterte Einsatzmöglichkeiten
Landing-PagesBestimmte Seiten aus einem CMS als Single-Site auf einer eigenen Domain bereitstellen, um z.B. einen anderen AdWords-Account verwenden zu können.
sebastian blum www.sblum.de 13.04.2023 16
CONVERSION-TRACKING FÜR ONLINE-SHOPS
PHP-Tracking
sebastian blum www.sblum.de 13.04.2023 17
Conversion Tracking für Online-Shops
Warum nicht per Google Analytics?
• GA bietet lediglich Conversions pro Kampagne oder Quelle
• Diese Conversions pro Kampagnen reichen nicht aus, um den genauen Erfolg und Wert der einzelnen Keywords & Anzeigen zu messen
sebastian blum www.sblum.de 13.04.2023 18
Conversion Tracking für Online-Shops
sebastian blum www.sblum.de 13.04.2023 19
Conversion Tracking für Online-Shops
Offene Fragen
• Welches Keyword hat genau welchen Erfolg?• Welche Keywords führen zu Transaktionen, welche
nicht?
individuelle Lösung notwendig
sebastian blum www.sblum.de 13.04.2023 20
Conversion Tracking für Online-Shops
AusgangssituationShopbetreiber schalten Google AdWords Anzeigen und wollen verfolgen, welche Keywords zu welchem erfolgreich verkauften Produkt geführt haben.
Vorteile des PHP-basierten Trackings• Die Shopsoftware wird nicht angepasst, stattdessen
wird eine zusätzliche Applikation gebaut• Die gezielte Werbeschaltung kann durch einfachen
CSV-Export analysiert werden• Genaue Gewinnermittlung für jedes Keyword
sebastian blum www.sblum.de 13.04.2023 21
Conversion Tracking für Online-Shops
Die Tracking-Schritte
sebastian blum www.sblum.de 13.04.2023 22
Conversion Tracking für Online-Shops
Die Tracking-Schritte in einer Beispiel-Programmierung
seocampixx.sebastianblum.com/shop/google
sebastian blum www.sblum.de 13.04.2023 23
1.
sebastian blum www.sblum.de 13.04.2023 24
Conversion Tracking - Parameter
Statische Parametercampaign = Kampagnenname der AdWords-Gruppe
Dynamische Value-Track AdWords ParameterIm Beispiel sind es {matchtype} und {keyword}
Weitere Beispiele{creative} eindeutige ID der Anzeige{device} Mobil, Tablet, Desktop oder Laptop
Google ersetzt die Platzhalter bei der Anzeige
sebastian blum www.sblum.de 13.04.2023 25
2.
sebastian blum www.sblum.de 13.04.2023 26
Conversion Tracking – Firebug
sebastian blum www.sblum.de 13.04.2023 27
Conversion Tracking – Javascript /1
var urlQueryString = window.location.search.substring(1),
queryParameters = urlQueryString.split('&'),
trackingParameters = [ "campaign", "keyword", "matchtype" ];
if (urlQueryString.length && queryParameters.length) {
trackingData.params = {};
for (var i = 0; i < queryParameters.length; i++)
var queryParameter = queryParameters[i].split('=');
if (queryParameter[0].substr(0,4) == 'utm_' ||
$.inArray( queryParameter[0], trackingParameters ) >= 0 ) {
trackingData.params[ queryParameter[0] ] =
decodeURIComponent(
( queryParameter[1] + "“ ).replace(/\+/g, '%20')
);
}
sebastian blum www.sblum.de 13.04.2023 28
3.
sebastian blum www.sblum.de 13.04.2023 29
Conversion Tracking – Firebug
sebastian blum www.sblum.de 13.04.2023 30
Conversion Tracking – Firebug / JSON
sebastian blum www.sblum.de 13.04.2023 31
Conversion Tracking – Javascript /2
if ( $( "#shoppingcart" ).size() === 1 ) {
trackingData.items = [];
$( "#shoppingcart tr.item" ).each(function() {
var $this = $( this );
trackingData.items.push({ count: $this.find( "td:eq(0)"
).text(), title: $this.find( "td:eq(1)" ).text(), price:
$this.find( "td:eq(2)").text() });
});
}
sebastian blum www.sblum.de 13.04.2023 32
4.
sebastian blum www.sblum.de 13.04.2023 33
Conversion Tracking – Firebug
sebastian blum www.sblum.de 13.04.2023 34
Conversion Tracking – Javascript /3
if ( $( "#conversion-tracking-successfull" ).size() === 1 ) {
trackingData.successfull = $( "#conversion-tracking-
successfull" ).data(); }
sebastian blum www.sblum.de 13.04.2023 35
Conversion Tracking für Online-Shops
Eine Conversion als JSON-Datei gespeichert
sebastian blum www.sblum.de 13.04.2023 36
Conversion Tracking für Online-Shops
5.
sebastian blum www.sblum.de 13.04.2023 37
Conversion Tracking für Online-Shops
5.params. campaign
params. matchtype
params. keyword
items.0. count
items.0.title
Amazon-Brand
exakt Amazon Online-Shop
1 Beispiel-Artikel des Shops
items.0.price
items.1.count
items.1.title
items.1.price
successfull.profit
49,99 1 zweiter Artikel
19,99 10
sebastian blum www.sblum.de 13.04.2023 38
Conversion Tracking für Online-Shops
• Daten aus den drei Schritten werden in der Session gespeichert
• Wenn Kauf erfolgreich abgeschlossen wurde, wird die Conversion mit den Session-Daten in eine JSON-Datei gespeichert
Das PHP-Skript
sebastian blum www.sblum.de 13.04.2023 39
PHP Skript conversion.php$conversion = $app['controllers_factory'];
$conversion->post('/track', function (Request $request) use ($app) { foreach (array('params', 'items', 'successfull') as $key) { if (null !== $data = $request->get($key)) { $app['session']->set($key, $data); } }
if (null !== $request->get('successfull')) { $json = $app['serializer']->serialize($app['session']->all(), 'json');
$path = __DIR__ . '/../export/' . ($app['debug'] ? 'dev' : 'prod') . '/'; if (!file_exists($path)) { mkdir($path, 0777); }
file_put_contents($path . $app['session']->getId() . '.json', $json); }
return new Response();})->bind('conversion');
return $conversion;
sebastian blum www.sblum.de 13.04.2023 40
Conversion Tracking - Export
• JSON-Daten der gespeicherten Conversion können für die Auswertung als CSV-Datei exportiert werden
• Die gespeicherten JSON-Objekte müssen hierfür normalisiert werden: Keine Verschachtelung
und Alle Zeilen müssen die gleichen Spalten beinhalten
sebastian blum www.sblum.de 13.04.2023 41
PHP Skript export.php$export = $app['controllers_factory'];
$export->get('/', function () use ($app) { $path = __DIR__ . '/../export/' . ($app['debug'] ? 'dev' : 'prod') . '/'; $jsonFiles = glob($path . '*.json');
$csvResponse = $app['export']($jsonFiles);
return new Response($csvResponse, 201, array('Content-Type' => 'text/csv', 'Content-Disposition' => 'attachment; filename="export.'.date("Ymd-Hi").'.csv"'));})->bind('export');
return $export;
sebastian blum www.sblum.de 13.04.2023 42
PHP Skript ExportServiceProvider.phpclass ExportServiceProvider implements ServiceProviderInterface{ public function register(Application $app) { $app['export'] = $app->protect(function (array $jsonFiles) use ($app) {
$exportModel = new ExportModel(); foreach ($jsonFiles as $jsonFile) { $data = json_decode(file_get_contents($jsonFile), true); $exportModel->add($data); }
return $exportModel; }); }
public function boot(Application $app) { }}
sebastian blum www.sblum.de 13.04.2023 43
PHP Skript ExportModel.phppublic function __toString() { $fp = fopen("php://memory", 'r+'); $first = true;
foreach ($this->data as $data) { if (true === $first) { $keys = array_keys($data); sort($keys); fputcsv($fp, $keys, ';'); $first = false; }
ksort($data); fputcsv($fp, $data, ';'); }
rewind($fp);
return stream_get_contents($fp); }
sebastian blum www.sblum.de 13.04.2023 44
Fazit PHP Conversion-Tracking
• Genaues Tracking mit Gewinnberechnung möglich• Genaue Verfolgung der Conversion• Rückschlüsse auf Kaufverhalten• Leichte Optimierung der Keywords
sebastian blum www.sblum.de 13.04.2023 45
Kontakt
Sebastian Blum
E-Mail: [email protected]: +49 8167 / 696 608
Vortrag online unterwww.sblum.de/#!seocampixx2013