De Markdown al WordPress sen doloro: jen kiel funkcias mia blogsistemo en Python
Dum longa tempo mi verkis artikolojn en Markdown kaj, kiam venis la momento publikigi ilin en WordPress, ĉiam aperis la sama frikcio: la diagramoj (precipe Mermaid) ne enmetiĝis bone, la bildojn oni devis prepari mane, kaj la fluo finiĝis kiel miksaĵo de ripetaj paŝoj facile rompeblaj.
La komenca instigo estis tre simpla: mi volis ilon kiu, donita Markdown-dokumenton kun diagramoj, generus la bildojn kaj preparus enhavon pretan por enkorpigo en WordPress. Sen senfina kopi-algluado, sen disaj skriptoj kaj sen dependo de la memoro pri ĉiuj paŝoj.
Kun la tempo, tiu komenca skripto evoluis al io pli ambicia: kompleta sistemo por mastrumi plurajn blogojn el la terminalo, ĉiu kun siaj artikoloj versiitaj en pluraj lingvoj, regata publikigo al unu aŭ pluraj WordPress-serviloj, asistata tradukado, statkontroloj kaj sekurkopioj.
La rezulto estas Python-CLI nomata blog.py.
Kiun problemon ĝi solvas
En mia kazo, la bremsilo ne estis la verkado, sed la operaciado:
- konverti Mermaid-diagramojn al bildoj,
- generi version kongruan kun WordPress,
- teni sinkronaj la diversajn lingvoversiojn,
- publikigi aŭ teni malneton sekure,
- scii ĉu WordPress ŝanĝiĝis ekde mia lasta
publish, - publikigi la saman blogon en pluraj serviloj (speguloj),
- kaj povi restarigi ĉion el sekurkopioj.
blog.py unuigas ĉion ĉi sub unu sola komando.
La kerna ideo: disigi programon de datumoj
La parto kiu plej kreskigis la sistemon estas simpla sed potenca distingo: la programo estas unuflanke, la datumoj aliflanke.
- La programo (la
.py-dosieroj kaj laMakefile) loĝas ĉe la radiko de la deponejo. - La datumoj loĝas po site: ĉiu sendependa enhavoblogo pendas de
sites/<site>/.
templates/post.md # komuna ŝablono por 'new'
siteconfig.py # ŝargas sites/<site>/site.toml + .env
sites/
raulsa8/ # persona site (raulsa8.blogs.uv.es)
site.toml # lingvoj, [[servers]], Telegram
.env # sekretoj (ekster git): pasvortoj, ĵetono
posts/<post>/
<base>-eo.md # Esperanta versio
<base>-es.md # Hispana versio …
<base>-<lang>.<servilo>.state.json
build/ backup/ # generitaj (gitignored)
veg/ # alia site, alia blogo
Tio klare disigas du specojn de agordo:
- Kio dependas de la blogo (site): la enhavo, la frontmatter, la diagramoj kaj la subtenataj lingvoj. Difinita en
site.toml. - Kio dependas de la servilo: la WordPress-URL, la uzanto, la pasvorto kaj la tuta stato (
post_id, aŭdvidaĵoj, ligilo). Tial la stato konserviĝas po servilo.
Multi-site kaj multi-servila
Unu sola programo mastrumas plurajn blogojn, kaj ĉiu blogo povas publikiĝi al pluraj WordPress-serviloj samtempe (speguloj):
./blog.py -s raulsa8 publish mia-artikolo eo # eksplicita site
./blog.py publish mia-artikolo eo # defaŭlta site, al ĈIUJ ĝiaj serviloj
./blog.py -S mirror publish mia-artikolo eo # al konkreta servilo-s/--siteelektas la blogon. Se vi ne indikas ĝin, oni uzas tiun kundefault = true, aŭ$BLOG_SITE, aŭ la solan disponeblan.-S/--serverelektas la servilon. Por legado (diff,status,tg-check) oni uzas la unuaranga; por skribado (publish,unpublish) oni iras al ĉiuj serviloj krom se vi nomas unu.
La po-servila stato (<base>-<lang>.<servilo>.state.json) tenas la post_id-on, la alŝutitajn aŭdvidaĵojn (kun ilia sha256) kaj la ligilon en tiu servilo. Se la dosiero ne ekzistas, tiu artikolo neniam publikiĝis tie.
Teknika filozofio: Python orkestras, Make plenumas
La ideo estas jena: Python kiel afabla orkestra tavolo, Make kiel plenuma motoro.
La plimulto de subkomandoj delegas al make, do nenia antaŭa funkcio perdiĝas nek refariĝas partoj kiuj jam bone funkciis. Sed la plej implikita logiko (tradukado, diff, status, tg-check, where, edit) loĝas rekte en Python por simpligi la prizorgadon.
Alivorte:
makerestas la teknika bazo,blog.pyaldonas ergonomion, aŭtomatan kompletigon kaj koheran interfacon.
Lingvo ĉiam eksplicita
Intenca dezajna decido: ne ekzistas defaŭlta lingvo. Ĉiu komando postulas la lingvon eksplicite (aŭ --all-lang por ĉiuj versioj). Tiel oni neniam publikigas malĝustan version pro malatento.
Kutima laborfluo
Tipa reala fluo povus esti:
./blog.py new mia-artikolo eo
./blog.py edit mia-artikolo eo
./blog.py render mia-artikolo eo
./blog.py publish-draft mia-artikolo eoKaj kiam vi volas etendi ĝin al pluraj lingvoj:
./blog.py translate mia-artikolo es --from eo
./blog.py translate mia-artikolo ca --from eo
./blog.py publish-allLa avantaĝo estas ke vi ne devas memori disajn komandojn nek internajn vojojn: la CLI koncentras la mensan modelon.
Aŭtomata kompletigo per TAB
Unu el la detaloj kiuj plej produktivigas la ĉiutagan laboron estas la aŭtomata kompletigo de sitoj, serviloj, artikolnomoj kaj lingvoj.
Ĉar blog.py baziĝas sur argparse, la aŭtomatan kompletigon provizas argcomplete: en ĉi tiu sistemo ĝia tutmonda hoko jam estas instalita, do sufiĉas malfermi novan ŝelon kaj uzi:
./blog.py <TAB>Se en via sesio ĝi ne aktivas, vi povas ŝalti ĝin tiel:
eval "$(register-python-argcomplete ./blog.py)"Ŝajnas eta detalo, sed ĝi reduktas stultajn erarojn kaj multe rapidigas la ĉiutagan operaciadon.
Ĉefaj subkomandoj (kaj por kio ili servas)
blog.py elmontras aron da komandoj kiuj kovras la tutan vivociklon de la enhavo:
list: listigas disponeblajn artikolojn kaj lingvojn.new: kreas malplenan artikolon el la ŝablono.render: generas diagramojn kaj konstruaswordpress.md.extract: ekstraktas Mermaid kaj generaswordpress.md.diagrams: bildigas nur la Mermaid-diagramojn.publish: kreas aŭ ĝisdatigas kaj publikigas viva.publish-draft: kreas aŭ ĝisdatigas kiel malneton.publish-all: publikigas ĉiujn versiojn de ĉiuj artikoloj.unpublish: reigas enhavon al malneta stato.translate: tradukas per Claude kaj alŝutas kiel malneton.master: montras aŭ fiksas la mastran lingvon de artikolo (fonto de la tradukoj).diff: montras diferencojn inter loka kaj WordPress.status: kontrolas (paralele) ĉu WordPress ŝanĝiĝis ekde nia lastapublish.pull: montras (sen integri) la ŝanĝojn faritajn permane en WordPress.bad-slugs: detektas koliziintajn slugojn (sufikso -2/-3) por ligi tradukojn.lang-check: kontrolas la realan lingvon de la publikigitaj artikoloj.tg-check: kontrolas ke la ĵetono de la Telegram-roboto funkcias.backup: elŝutas la tutan blogon albackup/.export-static: generas statikan HTML-blogon enstatic/.clean/distclean: purigas labuild/-on de unu versio aŭ tutan.where: presas la ĝustan vojon de la dosiero (ekz. por malfermi ĝin pervim).edit: malfermas la dosieron en via$EDITOR.
Ne ĉiu komando uziĝas ĉiutage, sed havi ilin unuigitaj evitas improvizajn solvojn.
Plurlingveco kaj versiado: la parto kiu plej valoras
Dum teknika blogo kreskas, teni versiojn en pluraj lingvoj fariĝas malfacile sen strukturo.
Ĉi tiu sistemo solvas tion apogante sin sur du kolonoj:
- artikoldosieroj mastrumataj eksplicite po lingvo,
- versiado per Git por konservi spureblecon, kontroleblon kaj malfaron.
Tio ebligas labori pliige: vi verkas en baza lingvo, tradukas kiam konvenas, kontrolas diferencojn kaj publikigas ĉiun version regate.
Ĉar mi uzas la senpagan Polylang, la atribuon de lingvo kaj la ligadon inter tradukoj oni faras nur unufoje, mane en wp-admin. De tiam, publish ĝisdatigas la enhavon sen perdi tiun ligon.
Publikigi kun sekurreto
En publikigado, la demando ne estas ĉu io misos, sed kiam. La sistemo konsideras tion dumaniere.
Unue, publish ĉesas se WordPress estis modifita ekde la lasta publikigo, por ne surtreti manajn ŝanĝojn (vi povas devigi per --force se vi scias kion vi faras). La komando status avertas vin pri tiuj modifoj antaŭ ol tuŝi ion ajn, kaj pull montras ilin kiel diferencon (sen integri ilin). Krome, publish estas idempotenta: ĝi konservas subskribon de la enhavo kaj alŝutas nur tion, kio ŝanĝiĝis, do du sinsekvaj publish-all ne refaras laboron. Kaj publish-all publikigas la artikolojn paralele (defaŭlte po 4).
Due, la komando backup ne estas akcesoraĵo: elŝuti la kompletan staton de la blogo al loka dosierujo (backup/) aldonas veran sekurreton por migradoj, rapidaj reviziadoj aŭ restarigo post eraroj.
Eksporti al statika HTML
Krom publikigi al WordPress, la sistemo povas generi kompletan statikan HTML-version de la blogo per export-static.
Ĝi bildigas ĉiujn artikolojn kaj produktas statikan retejon en sites/<site>/static/: unu paĝo po artikolo kaj lingvo, indeksoj po lingvo, lingvelektilo kaj sen komentoj. La serĉo apogas sin sur Google per la site:-operatoro, kie base_url estas la publika URL kie vi gastigos la statikan version (agordebla en site.toml).
Ĝi estas ideala por teni traserĉeblan kaj sendependan kopion de la blogo, sen dependi de WordPress por legi ĝin.
Integriĝo kun Telegram
Krom la publikiga fluo, la sistemo konsideras la operacian flankon de Telegram: dum publikigo ĝi povas sciigi kanalon, kun babilejo agordebla po lingvo.
La subkomando tg-check kontrolas ke la ĵetono de la roboto funkcias ĝuste, kio estas tre utila kiam vi havas sciigajn aŭtomatigojn ĉirkaŭ la redakta procezo. Praktike ĝi ŝparas al vi malkovri legitimilan problemon tro malfrue: vi povas kontroli la integriĝon antaŭ ol publikigi kaj teni la ilaron sana.
Kial ĉi tiu aliro funkcias por mi
Ĝi ne estas giganta framo nek fermita platformo. Ĝi estas eta, praktika sistemo farita el konataj partoj:
- Markdown kiel fonto de vero,
- Mermaid por diagramoj,
- Python por orkestri,
- Make por plenumi,
- WordPress (unu aŭ pluraj) kiel celo,
- kaj statika HTML kiel traserĉebla kopio.
Tiu kombino havas gravan virton: ĝi reduktas frikcion sen oferi teknikan regon.
Fino
La ilo naskiĝis por solvi konkretan problemon (transformi Markdown kun diagramoj al WordPress-publikigebla formato) kaj finfine fariĝis kompleta ĉeno de redakta produktado el la terminalo: pluraj blogoj, pluraj lingvoj, pluraj serviloj kaj statika eksporto, ĉio sub unu sola komando.
Se al vi plaĉas verki loke, versii ĉion kaj publikigi memfide, tia aliro faras la diferencon: malpli da mekanika laboro, malpli da eraroj kaj pli da fokuso sur tio kio vere gravas, nome la enhavo.

Figura 1