Przejdź do głównej zawartości

Mini CMS plikowy

Stworzycie Mini CMS plikowy - prosty system zarządzania treścią, który pozwala tworzyć, edytować i przeglądać artykuły lub strony. W przeciwieństwie do WordPress czy Joomla, wasz CMS nie używa bazy danych - wszystkie dane są zapisywane do plików JSON. To świetny sposób na zrozumienie podstaw działania systemów CMS.

Czego się nauczycie?

  • Projektowania systemów zarządzania treścią
  • Pracy z kategoriami i tagami
  • Tworzenia interfejsu dla redaktorów
  • Bezpiecznego wyświetlania treści użytkowników (XSS)
  • Praca zespołowa - podział zadań, współpraca, integracja kodu

W prawdziwej firmie...

Systemy CMS to podstawa większości stron internetowych. WordPress obsługuje ponad 40% wszystkich stron w internecie! Zrozumienie jak działa CMS “od środka” jest niezbędne dla każdego web developera - nawet jeśli później będziecie używać gotowych rozwiązań.

Umiejętności rynkowe

Nauczycie się bezpiecznego wyświetlania treści użytkowników - krytycznej umiejętności w każdej aplikacji webowej. Zrozumiecie też koncepcję separacji treści od prezentacji i zarządzania metadanymi (tagi, kategorie, daty).

  1. Formularz dodawania artykułu Redaktor wypełnia formularz z tytułem, treścią, kategorią i tagami. System automatycznie generuje ID, slug (URL-friendly tytuł) i timestamp. Treść może być formatowana (akapity).

  2. Walidacja i sanityzacja System sprawdza poprawność danych i sanityzuje treść przed zapisem. Szczególnie ważna jest ochrona przed XSS przy wyświetlaniu - nigdy nie ufaj danym od użytkownika!

  3. Lista artykułów z filtrami Strona główna wyświetla listę artykułów z możliwością filtrowania po kategorii lub tagu. Artykuły są posortowane od najnowszych.

  4. Podgląd artykułu Dedykowana strona z pełną treścią artykułu, metadanymi (autor, data, kategoria) i listą tagów.

Strona główna (lista)

  • Lista najnowszych artykułów
  • Miniaturki i zajawki
  • Filtry kategorii
  • Chmura tagów (B+)

Formularz artykułu

  • Tytuł artykułu
  • Treść (textarea)
  • Wybór kategorii
  • Tagi (comma-separated)
  • Przycisk “Opublikuj”

Podgląd artykułu

  • Pełna treść
  • Metadane (autor, data)
  • Kategoria i tagi
  • Nawigacja (poprzedni/następny)

Panel redaktora (B/C)

  • Lista moich artykułów
  • Edycja artykułu
  • Usuwanie (C)

Przykładowa struktura pliku JSON (wariant A/B):

{
"posts": [
{
"id": 1,
"slug": "wprowadzenie-do-php",
"title": "Wprowadzenie do PHP",
"content": "PHP to popularny język programowania server-side...\n\nW tym artykule poznasz podstawy...",
"category": "programowanie",
"tags": ["php", "backend", "podstawy"],
"author": "Jan Kowalski",
"created_at": "2026-02-13 10:30:00",
"updated_at": "2026-02-13 10:30:00"
},
{
"id": 2,
"slug": "css-flexbox-poradnik",
"title": "CSS Flexbox - kompletny poradnik",
"content": "Flexbox to potężne narzędzie do układania elementów...",
"category": "frontend",
"tags": ["css", "flexbox", "layout"],
"author": "Anna Nowak",
"created_at": "2026-02-14 09:15:00",
"updated_at": "2026-02-14 09:15:00"
}
]
}

Wariant C - plik per artykuł:

data/
posts/
post-1.json
post-2.json
post-3.json
index.json (lista wszystkich postów z metadanymi)

Wymagane funkcjonalności:

  • Formularz artykułu: tytuł, treść, kategoria, tagi
  • Walidacja PHP wszystkich pól
  • Minimum 1 walidacja JavaScript (np. długość tytułu)
  • Zapis wszystkich artykułów do jednego pliku JSON
  • Generowanie unikalnego ID i slug
  • Lista artykułów na stronie głównej
  • Podgląd pojedynczego artykułu
  • Wyświetlanie komunikatów o błędach
  • htmlspecialchars() na treści przy wyświetlaniu

Struktura plików:

  • Folderprojekt/
    • index.php (lista artykułów)
    • add.php (formularz dodawania)
    • post.php (podgląd artykułu)
    • README.md
    • Folderdata/
      • posts.json
    • Foldercss/
      • style.css
    • Folderjs/
      • validation.js
Ocena: 3.0
  1. Redaktor otwiera formularz dodawania artykułu
  2. Wpisuje tytuł “Wprowadzenie do CSS Grid”
  3. Pisze treść artykułu z podziałem na akapity
  4. Wybiera kategorię “Frontend”
  5. Dodaje tagi: “css, grid, layout”
  6. Klika “Opublikuj”
  7. System generuje slug “wprowadzenie-do-css-grid”
  8. Artykuł pojawia się na liście
  1. Czytelnik wchodzi na stronę główną
  2. Widzi listę najnowszych artykułów
  3. Klika w kategorię “Programowanie”
  4. Widzi tylko artykuły z tej kategorii
  5. Klika w wybrany artykuł
  6. Czyta pełną treść
  1. Redaktor loguje się do panelu
  2. Widzi listę swoich artykułów
  3. Klika “Edytuj” przy wybranym artykule
  4. Formularz wypełnia się obecnymi danymi
  5. Poprawia treść i dodaje nowy tag
  6. Klika “Zapisz zmiany”
  7. System aktualizuje artykuł i updated_at

Generowanie slug z tytułu:

<?php
function generateSlug(string $title): string {
// Zamień polskie znaki
$slug = strtr($title, [
'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l',
'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z', 'ż' => 'z',
'Ą' => 'a', 'Ć' => 'c', 'Ę' => 'e', 'Ł' => 'l',
'Ń' => 'n', 'Ó' => 'o', 'Ś' => 's', 'Ź' => 'z', 'Ż' => 'z'
]);
// Zamień na małe litery
$slug = strtolower($slug);
// Zamień spacje i znaki specjalne na myślniki
$slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
// Usuń myślniki z początku i końca
$slug = trim($slug, '-');
return $slug;
}
// Użycie:
$slug = generateSlug("Wprowadzenie do PHP - część 1");
// Wynik: "wprowadzenie-do-php-część-1"

Parsowanie tagów z tekstu:

<?php
function parseTags(string $tagsString): array {
// Rozdziel po przecinku
$tags = explode(',', $tagsString);
// Oczyść każdy tag
$tags = array_map(function($tag) {
return strtolower(trim($tag));
}, $tags);
// Usuń puste i duplikaty
$tags = array_filter($tags);
$tags = array_unique($tags);
return array_values($tags);
}
// Użycie:
$tags = parseTags("PHP, JavaScript, php, CSS ");
// Wynik: ["php", "javascript", "css"]

Bezpieczne wyświetlanie treści:

<?php
function renderContent(string $content): string {
// Escapuj HTML
$safe = htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
// Zamień podwójne entery na akapity
$paragraphs = explode("\n\n", $safe);
$html = '';
foreach ($paragraphs as $p) {
$p = trim($p);
if (!empty($p)) {
// Zamień pojedyncze entery na <br>
$p = nl2br($p);
$html .= "<p>$p</p>\n";
}
}
return $html;
}

Generowanie zajawki:

<?php
function getExcerpt(string $content, int $maxLength = 200): string {
// Usuń HTML i przytnij
$text = strip_tags($content);
if (strlen($text) <= $maxLength) {
return $text;
}
// Przytnij do ostatniego słowa
$excerpt = substr($text, 0, $maxLength);
$lastSpace = strrpos($excerpt, ' ');
if ($lastSpace !== false) {
$excerpt = substr($excerpt, 0, $lastSpace);
}
return $excerpt . '...';
}

Filtrowanie artykułów po tagu:

<?php
function filterByTag(array $posts, string $tag): array {
return array_filter($posts, function($post) use ($tag) {
return in_array($tag, $post['tags'], true);
});
}
function filterByCategory(array $posts, string $category): array {
return array_filter($posts, function($post) use ($category) {
return $post['category'] === $category;
});
}
// Generowanie chmury tagów
function getTagCloud(array $posts): array {
$tagCounts = [];
foreach ($posts as $post) {
foreach ($post['tags'] as $tag) {
if (!isset($tagCounts[$tag])) {
$tagCounts[$tag] = 0;
}
$tagCounts[$tag]++;
}
}
arsort($tagCounts);
return $tagCounts;
}

CSS dla tagów i kategorii:

.tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag {
display: inline-block;
padding: 4px 12px;
background-color: #e0f2fe;
color: #0369a1;
border-radius: 16px;
font-size: 0.85em;
text-decoration: none;
transition: background-color 0.2s;
}
.tag:hover {
background-color: #bae6fd;
}
.category-badge {
display: inline-block;
padding: 4px 12px;
background-color: #f3e8ff;
color: #7c3aed;
border-radius: 4px;
font-size: 0.85em;
font-weight: 500;
}
.post-meta {
color: #6b7280;
font-size: 0.9em;
margin-bottom: 1rem;
}
.post-excerpt {
color: #4b5563;
line-height: 1.6;
}

To prawdziwy projekt zespołowy!

Ten projekt to wasz własny mini-WordPress! Nauczycie się, jak działają systemy CMS “od kuchni” - wiedza, która przyda się przy pracy z każdym CMS-em.

Pracujcie iteracyjnie - lepiej mieć działający wariant A niż niedziałający C!