Drupal 8: jak jsem migroval články ze sedmičky pomocí drush

Po delší době jsem se pustil do aktualizací svých projektů a potřeboval jsem vyřešit migraci menšího článkového webu z Drupalu 7 na Drupal 8. Po předchozích zkušenostech s výchozí migrací jsem z ní nebyl zrovna nadšený, takže jsem hledal (a našel) pro mě lépe vyhovující řešení.

Reklama

Mám za sebou již několik migrací webů ze staršího Drupalu na Drupal 8. Ze sedmičky i ze šestky. V případě klientů to byly spíše malé weby, byť někdy s velkým počtem článků, ale většinou se značně napjatým rozpočtem. Jeden z mála webů, kde jsem měl prostor se migraci věnovat více, byla Bakalka.cz.

Mám i několik vlastních projektů, které už běží na Drupalu 8, ale migrace byla spíše otázkou ručního překopírování obsahu do nově postaveného webu.

Klasická migrace v Drupalu 8 jakž takž funguje. Nainstalujete nový web, dáte mu přístup k databázi a souborům toho starého, spustíte migračního průvodce a nějak to dopadne. Já bych to přirovnal k upgradu starých Windows na nové. Většinou se to podaří, ale veškeré neduhy staré instalace si nesete dál. Stejně tak při migraci ze starého Drupalu.

Pro svůj cestovatelský blog Crikvenica-Chorvatsko.cz jsem ale chtěl něco lepšího. Značně jsem upravil design, který nyní stojí na fotkách, přidal fotogalerie do článků i na samostatnou stránku, vylepšil řadu dalších věcí. Znamenalo to postavit celý web od začátku, doprogramovat doplňkové moduly (tahání teploty moře a kurzu měny) pro Drupal 8 a nějakým způsobem importovat články ze starého webu.

  Nový web na Drupalu 8

Pro ukázku původní podoba webu:

  Starý web na Drupalu 7

Co mi vadí na klasické migraci v Drupalu 8

Zabudovaný migrační mechanismus v Drupalu 8 mi nevyhovuje z řady důvodů. Obvykle nadělá nepořádek v menu, ve filtrech, pokud se něco nezměnilo, tak stejně neumí migrovat Views a hlavně importuje vše sakumprásk. A já potřeboval importovat jenom články, potažmo obsah do nového webu. Pokud možno s tím, že při importu obsahu upravím nějaké věci před jeho uložením.

Navíc mi tvorba vlastního migračního skriptu, který by používal klasickou migraci a její API přijde poněkud složitá a nechtělo se mi si s ní hrát.

Export ze starého webu

Prvním krokem tedy bylo dostat data ze starého webu v nějaké rozumné podobě ven. Vzhledem k tomu, že počet článků se pohybuje v desítkách, šlo na to rozumně použít modul Views data export, ve kterém si naklikáte jednotlivá políčka z článků coby uzly výstupního XML. Včetně třeba cest k obrázkům nahraným přes obrázkové pole.

Import do Drupalu 8 a drush

Když jsem dělal podobné importy v době Drupalu 7, zapojoval jsem do hry buď modul Feeds, nebo lépe, vlastní modul využívající Batch API a napsaný víceméně na míru pro každý takto zpracovávaný případ. Feeds nejsou pro Drupal 8 připravené a používat dávkovou operaci ve frontendu mi vždy přišlo docela pomalé. Nedávno jsem navíc viděl šikovný návod pro vytvoření nového příkazu spouštěného přes drush, který právě řeší import obsahu.

Tip: Mrkněte na článek, který mi byl isnpirací A custom drush command to import nodes from RSS/XML to Drupal 8.

Musím se přiznat, že vlastní příkaz pro drush jsem programoval poprvé. A přitom je to velmi jednoduché, dokonce více, než zapojovat do hry Batch API. Výhoda příkazového řádku je také v tom, že tu nejsem omezen nějakým timeoutem jako v prohlížeči.

Celý návod tu nebudu přepisovat, zájemce odkazuji na výše uvedený článek. Co mi však v této předloze chybělo pro moje potřeby, to bylo ukládání obrázků do nově vytvářených obsahových uzlů.

Vytvoření příkazu pro drush znamená vlastně přípravu jednoduchého modulu s konfiguračním souborem a souborem modul.drush.inc. V něm definujete samotný příkaz a funkci, která jej provede. Příkaz může zobrazovat aktuální stav operací výpisem do příkazového řádku přes drush_print().

V samotném zpracování sestaveného XML ze starého webu vyrobeného postupem uvedeným výše, jsem použil nahrazení nějakých položek v těle článku. Co se stažení a uložení souboru týče, zde je konkrétní ukázka. Předpokládá, že v nějakém elementu exportního XML máte uvedenou plnou URL adresu k obrázku:

$ikonka =  $objEntry->ikonka;
$data = file_get_contents($ikonka);
$cesta = explode('ikonky',$ikonka);
$file = file_save_data($data, 'public://ikonky'.$cesta[1], FILE_EXISTS_REPLACE);

Objekt $file pak přiřadíte do pole nového uzlu. V případě více obrázků z galerie, které Views data export zařadí do jednoho uzlu v XML jako data oddělená čárkou, je stačí rozparsovat přes PHP funkcí explode(), výše uvedeným postupem si připravit pole s jednotlivými soubory a to teprve přidat do uzlu.

$fotky[] = ['target_id' => $file->id(),'alt' => $strNodeTitle];

Výsledné uložení by bylo nějak takto. V ukázce mám také naznačené přiřazení aliasu, což je jednoduchý řetězec textu.

$newNode = [
  …
  'body' => [
    'value' => $textContent,
    'format' => 'full_html'
  ],
  'field_image' => [
    'target_id' => $file->id(),
    'alt' => $strNodeTitle,
  ],
  'field_fotogalerie' => $fotky,
  'created' => $strDatum,
  'path' =>  ['alias' => $alias]
];
$node = Node::create($newNode);
$node->save();

Pro detailní ukázku vás nasměruji do zmíněného návodu pro import přes drush.

Další zádrhely

Protože jsem měl pomocí modulu Insert vložené nějaké obrázky přímo do textu, nechtěl jsem o ně přijít. Jak jistě víte, Drupal dává do cesty k obrázkům vygenerovaným přes styly obrázků ještě kontrolní token zajišťující, že se web nepřetíží zbytečným generováním derivátů jiných fotek. Bohužel token z Drupalu 7 by byl jiný než v osmičce. Vyřešil jsem to tedy prostým překopírováním složky public://styles ze starého webu a doplněním příkazu pro ignorování tokenů do settings.php:

$config['image.settings']['suppress_itok_output'] = TRUE;
$config['image.settings']['allow_insecure_derivatives'] = TRUE;

Postupně obrázky předělám a toto nastavení dám opět pryč.

U bloků jsem chvíli tápal, jak pracovat s jejich nastavením cache, neb definice je zde opět trochu jiná, než v Drupalu 7. U osmičky by mělo stačit do pluginu generujícího blok přidat tuto funkci:

public function getCacheMaxAge() {
  return 3600;
}

Hodnota 3600 určuje nastavení cache bloku na jednu hodinu.

Trochu odlišné je také zpracování ajaxu ve formulářích, ale o tom zase někdy příště. Co mě potrápilo více, byla absence pomocného modulu SimpleHTMLDOM Parser ve verzi pro Drupal 8. Už mě tlačil čas, nechtěl jsem řešit použití dané knihovny svou vlastní cestou a osmičkový modul, který jsem nakonec někde našel, způsoboval pády Drupalu.

Ve finále jsem si řekl, proč zapojovat do hry nějakou knihovnu, na kterou jsem byl dříve zvyklý, když máme potřebné věci přímo v jádře Drupalu 8. Pokud byste tedy někdy potřebovali načíst HTML z jiného webu a parsovat z něj obsah, lze to řešit následovně:

Do modulu přidáte následující use:

use Drupal\Component\Utility\Html;

Samotné stažení a zpracování HTML vypadá takto:

$client = \Drupal::httpClient();
$response = $client->request('GET','http://www……');
$data = $response->getBody()->getContents();
$html_dom = Html::load($data);

S $html_dom pak můžete pracovat klasicky jako s DOMDocumentem z PHP.

Slider a galerie obrázků

Na závěr jen dvě drobnosti. Slider na titulní straně řeším pomocí javascriptové knihovny Vegas 2. Funguje s jQuery i Zepto a na rozdíl od mnoha jiných klasických sliderů, tato rotuje obrázky na pozadí zvoleného elementu. Vyhovuje mi v tom, že se mi pak lépe připraví celostránkové prolínání fotografií.

Pro galerii obrázků v článcích i v oddělené fotogalerii (obojí tahá přes Views obrázková políčka z článků) jsem použil placený plugin iLightBox. Dobře si rozumí s dotekovými zařízeními, pěkně vypadá a má řadu možností nastavení.

Tagy: 

Reklama

Přidat komentář