Contento

Integrarea WordPress Self-Hosted

Cum publică Contento articolele direct pe site-ul tău WordPress prin REST API, ce cereri trimite și cum poți reproduce manual cu curl pentru debugging.

1. Cum funcționează

Pentru a publica un articol, Contento face două cereri HTTP către WordPress REST API:

  1. Încarcă imaginea principală către /wp-json/wp/v2/media și salvează ID-ul returnat.
  2. Creează articolul printr-un POST către /wp-json/wp/v2/posts, folosind ID-ul imaginii ca featured_media.

Dacă ai nevoie să confirmi că integrarea trimite cererile corect, poți reproduce manual exact aceste apeluri folosind exemplele de mai jos.

2. Autentificare

Toate cererile folosesc Basic Auth peste HTTPS, cu o Application Password generată din WordPress (Utilizatori → Profil → Application Passwords). Nu se folosește parola obișnuită a contului.

Authorization: Basic <base64(username:app_password)>

Pentru exemplele care urmează, configurează două variabile în shell:

SITE="https://example.com"
AUTH=$(printf '%s' 'WP_USERNAME:APP_PASSWORD' | base64)

3. Pasul 1 — Încarcă imaginea principală

Imaginea se urcă pe WordPress ca atașament. WordPress răspunde cu un JSON care conține câmpul id — îl vei folosi în pasul următor.

curl -i -X POST "$SITE/wp-json/wp/v2/media" \
  -H "Authorization: Basic $AUTH" \
  -H "Content-Type: image/jpeg" \
  -H 'Content-Disposition: attachment; filename="test.jpg"' \
  -H "User-Agent: Contento/1.0" \
  --data-binary "@$HOME/test.jpg"

Atenție la câteva detalii ușor de greșit:

  • Content-Type trebuie să corespundă cu tipul real al fișierului (image/png pentru PNG, etc.). Verifică cu file image.jpg.
  • Argumentul --data-binary trebuie să înceapă cu @ — altfel curl trimite literalmente șirul de caractere, nu conținutul fișierului.
  • Tilde-ul (~) nu este expandat în interiorul argumentului @ — folosește $HOME sau o cale absolută.

Răspuns de succes (HTTP 201):

{
  "id": 5738,
  "source_url": "https://example.com/wp-content/uploads/2026/05/test.jpg",
  "media_type": "image",
  ...
}

4. Pasul 2 — Creează articolul cu imagine principală

Înlocuiește MEDIA_ID cu id-ul obținut la pasul anterior:

curl -i -X POST "$SITE/wp-json/wp/v2/posts" \
  -H "Authorization: Basic $AUTH" \
  -H "Content-Type: application/json" \
  -H "User-Agent: Contento/1.0" \
  -d '{
    "title": "Test featured image",
    "content": "<p>Body</p>",
    "status": "publish",
    "slug": "test-featured-image",
    "featured_media": MEDIA_ID
  }'

Un răspuns HTTP 201 cu "featured_media": <același id> și clasa has-post-thumbnail în class_list confirmă că WordPress a legat corect imaginea de articol.

5. Câmpurile pe care le trimite Contento

Pentru fiecare articol publicat, Contento construiește un body de forma:

{
  "title": "Titlul articolului",
  "content": "<html-ul articolului>",
  "status": "publish",
  "excerpt": "Meta description",
  "slug": "slug-articol",
  "categories": [123],
  "tags": [456, 789],
  "featured_media": 999,
  "meta": {
    "_yoast_wpseo_focuskw": "cuvânt cheie",
    "rank_math_focus_keyword": "cuvânt cheie",
    "_aioseo_keywords": "cuvânt cheie"
  }
}

Câmpul featured_media apare doar dacă încărcarea imaginii a reușit. Câmpul meta conține cuvântul cheie focus pentru cele trei plugin-uri SEO populare (Yoast, Rank Math, All in One SEO).

6. Probleme comune

Imaginea nu apare pe pagina articolului

Dacă răspunsul pasului 2 conține "featured_media" și clasa has-post-thumbnail, dar imaginea tot nu se vede în browser, problema este la tema WordPress, nu la integrare. Template-ul temei trebuie să apeleze funcția the_post_thumbnail() în layout-ul single post — multe teme custom sau cele construite cu page builder-e nu o apelează implicit, sau ascund imaginea în spatele unui toggle din Customizer.

Un semn revelator: imaginea apare în share-urile pe social media (OG / Twitter Card) și în structured data Yoast, dar nu pe pagină — pentru că plugin-urile SEO citesc featured_media direct, fără să depindă de template.

HTTP 400 rest_upload_no_data

Curl a trimis un body gol — fișierul nu există la calea specificată sau ai uitat prefixul @ înainte de cale. Verifică cu ls -la că fișierul există și are dimensiune nenulă.

HTTP 500 rest_upload_sideload_error

WordPress nu poate detecta tipul fișierului — fie Content-Type nu corespunde conținutului real (ex: trimiți un PNG cu image/jpeg), fie body-ul este o secvență de caractere arbitrară (uitat prefixul @ la --data-binary).

Răspuns HTML în loc de JSON

Dacă răspunsul începe cu <!doctype html> sau <html>, un firewall sau plugin de securitate (Wordfence, iThemes Security, etc.) blochează /wp-json/. Verifică regulile firewall-ului și whitelist-ul pluginului de securitate.

HTTP 401 sau 403

Application Password greșit sau dezactivat. Generează una nouă din Utilizatori → Profil → Application Passwords și actualizează integrarea în dashboard. Atenție: spațiile dintre grupurile de caractere fac parte din parolă.

7. Contact

Dacă întâmpini probleme cu integrarea WordPress Self-Hosted, scrie-ne la [email protected] cu URL-ul site-ului și pașii pe care i-ai încercat.