PHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum

4,331 views

Published on

Im Workshop wird eine PHP-Applikation entwickelt und 2 SEO- Szenarien mit PHP-Beispielen besprochen. Szenario 1 übertragt einen bestehenden Blog in einen Unterordner einer anderen Domain (PHP-Proxy), Szenario 2 zeigt die Möglichkeiten einer Kampagnen-Speicherung mit CSV-Export der Conversions für Shops & Blogs auf, ohne die Shop- & Blogsoftware anzupassen (PHP-App für Kampagnen-Tracking).

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,331
On SlideShare
0
From Embeds
0
Number of Embeds
1,301
Actions
Shares
0
Downloads
70
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

PHP-SEO Vortrag SEOCampixx 2013 von Sebastian Blum

  1. 1. PHP-SEOVortrag online unterwww.sblum.de/#!seocampixx2013Quelltext online untergithub.com/sebastianblum/seocampixx2013 Sebastian Blumsebastian blum www.sblum.de 13.03.2013 1
  2. 2. Agendaa) PHP-Proxy blogger.com Free-Blog in einem Unterverzeichnis hostenb) Conversion-Tracking genaue Conversion-Messung mit eigener Applikationsebastian blum www.sblum.de 13.03.2013 2
  3. 3. PHP-Proxy BLOGGER.COM IN UNTERVERZEICHNIS HOSTENsebastian blum www.sblum.de 13.03.2013 3
  4. 4. blogger.com in Unterverzeichnis hosten Grundidee Ein 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 notwendigsebastian blum www.sblum.de 13.03.2013 4
  5. 5. blogger.com in Unterverzeichnis hosten Grundidee Ein 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 Netzwerkeffektsebastian blum www.sblum.de 13.03.2013 5
  6. 6. Blogs in Unterverzeichnis hostensebastian blum www.sblum.de 13.03.2013 6
  7. 7. blogger.com in Unterverzeichnis hosten Anpassungen im Blog 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/blogsebastian blum www.sblum.de 13.03.2013 7
  8. 8. blogger.com in Unterverzeichnis hosten Blogsebastian blum www.sblum.de 13.03.2013 8
  9. 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);}); (Mit Micro-Framework Silex)return $blog;sebastian blum www.sblum.de 13.03.2013 9
  10. 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.03.2013 10
  11. 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 newResponse($htmlResponse, $httpStatusCode, array(Content-Type => $contentType));})->value(year, null)->value(month, null)->value(slug, null) (Mit Micro-Framework Silex)->bind(blog);sebastian blum www.sblum.de 13.03.2013 11
  12. 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.03.2013 12
  13. 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, Nameserversebastian blum www.sblum.de 13.03.2013 13
  14. 14. Blogs in Unterverzeichnis hostensebastian blum www.sblum.de 13.03.2013 14
  15. 15. Blogs in Unterverzeichnis hosten Erweiterte Einsatzmöglichkeiten Landing-Pages Bestimmte 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.03.2013 15
  16. 16. PHP-Tracking CONVERSION-TRACKING FÜR ONLINE-SHOPSsebastian blum www.sblum.de 13.03.2013 16
  17. 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 messensebastian blum www.sblum.de 13.03.2013 17
  18. 18. Conversion Tracking für Online-Shopssebastian blum www.sblum.de 13.03.2013 18
  19. 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 notwendigsebastian blum www.sblum.de 13.03.2013 19
  20. 20. Conversion Tracking für Online-Shops Ausgangssituation Shopbetreiber 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 Keywordsebastian blum www.sblum.de 13.03.2013 20
  21. 21. Conversion Tracking für Online-Shops Die Tracking-Schrittesebastian blum www.sblum.de 13.03.2013 21
  22. 22. Conversion Tracking für Online-Shops Die Tracking-Schritte in einer Beispiel- Programmierung seocampixx.sebastianblum.com/shop/ googlesebastian blum www.sblum.de 13.03.2013 22
  23. 23. 1.sebastian blum www.sblum.de 13.03.2013 23
  24. 24. Conversion Tracking - Parameter Statische Parameter campaign = Kampagnenname der AdWords-Gruppe Dynamische Value-Track AdWords Parameter Im 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 Anzeigesebastian blum www.sblum.de 13.03.2013 24
  25. 25. 2.sebastian blum www.sblum.de 13.03.2013 25
  26. 26. Conversion Tracking – Firebugsebastian blum www.sblum.de 13.03.2013 26
  27. 27. Conversion Tracking – Javascript /1var 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.03.2013 27
  28. 28. 3.sebastian blum www.sblum.de 13.03.2013 28
  29. 29. Conversion Tracking – Firebugsebastian blum www.sblum.de 13.03.2013 29
  30. 30. Conversion Tracking – Firebug / JSONsebastian blum www.sblum.de 13.03.2013 30
  31. 31. Conversion Tracking – Javascript /2if ( $( "#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.03.2013 31
  32. 32. 4.sebastian blum www.sblum.de 13.03.2013 32
  33. 33. Conversion Tracking – Firebugsebastian blum www.sblum.de 13.03.2013 33
  34. 34. Conversion Tracking – Javascript /3if ( $( "#conversion-tracking-successfull" ).size() === 1 ) { trackingData.successfull = $( "#conversion-tracking- successfull" ).data(); }sebastian blum www.sblum.de 13.03.2013 34
  35. 35. Conversion Tracking für Online-Shops Eine Conversion als JSON-Datei gespeichertsebastian blum www.sblum.de 13.03.2013 35
  36. 36. Conversion Tracking für Online-Shops 5.sebastian blum www.sblum.de 13.03.2013 36
  37. 37. Conversion Tracking für Online-Shops 5.params. params. params. items.0. items.0.campaign matchtype keyword count titleAmazon- exakt Amazon 1 Beispiel-Brand Online-Shop Artikel des Shopsitems.0. items.1. items.1. items.1. successfull.price count title price profit49,99 1 zweiter 19,99 10 Artikelsebastian blum www.sblum.de 13.03.2013 37
  38. 38. Conversion Tracking für Online-Shops Das PHP-Skript• 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 gespeichertsebastian blum www.sblum.de 13.03.2013 38
  39. 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.03.2013 39
  40. 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 beinhaltensebastian blum www.sblum.de 13.03.2013 40
  41. 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.03.2013 41
  42. 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.03.2013 42
  43. 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.03.2013 43
  44. 44. Fazit PHP Conversion-Tracking• Genaues Tracking mit Gewinnberechnung möglich• Genaue Verfolgung der Conversion• Rückschlüsse auf Kaufverhalten• Leichte Optimierung der Keywordssebastian blum www.sblum.de 13.03.2013 44
  45. 45. KontaktSebastian BlumE-Mail: sb@sblum.deTelefon: +49 8167 / 696 608Vortrag online unterwww.sblum.de/#!seocampixx2013sebastian blum www.sblum.de 13.03.2013 45

×