WPKit
Biblioteka kliencka Android do komunikacji z API REST WordPressa.
Posty, strony, kategorie, tagi, autorzy, menu — z paginacją, cache i gotowymi widokami UI.
Integracja z Parse Server: uwierzytelnianie, profil użytkownika, push notyfikacje, dane.
Android client library for the WordPress REST API.
Posts, pages, categories, tags, authors, menus — with pagination, offline cache & ready-made UI views.
Parse Server integration: authentication, user profiles, push notifications, data queries.
v1.1.0 · Kotlin · KitsuneNET · KitsuneDB · Paging 3 · Jetpack Compose · Parse SDK
Przegląd
Overview
WPKit to biblioteka Android umożliwiająca łatwe pobieranie treści WordPress przez REST API. Obsługuje dwa tryby pracy: standardowe WP REST API (bez tokenu) oraz niestandardowe API pluginu WPKit Workspace (z uwierzytelnianiem tokenem). Gdy token workspace jest skonfigurowany, biblioteka używa wyłącznie pluginu — dane są filtrowane do bieżącego workspace'u.
WPKit is an Android library for easy consumption of WordPress content via REST API. It supports two modes: standard WP REST API (no token) and the custom WPKit Workspace plugin API (token auth). When a workspace token is configured, the library exclusively uses the plugin — data is scoped to the current workspace.
core rip.nerd.wpkit.core
- WPKit — singleton inicjalizujący klientów HTTP
- WPKit — singleton initializing HTTP clients
- WPConfig — konfiguracja biblioteki
- WPConfig — library configuration
- WPService — standardowe WP REST API
- WPService — standard WP REST API
- WPkitService — API pluginu workspace
- WPkitService — workspace plugin API
- WordPressRepository — warstwa repozytorium
- WordPressRepository — repository layer
- WPState, WPResult — modele stanu UI
- WPState, WPResult — UI state models
- WPPostsViewModel — bazowy ViewModel
- WPPostsViewModel — base ViewModel
- WPBookmarkManager, WPShareUtils, WPKitLogger
- WPBookmarkManager, WPShareUtils, WPKitLogger
- Modele domenowe i DTO, rozszerzenia
- Domain & DTO models, extensions
- Paginacja (Paging 3) + cache offline (KitsuneDB)
- Pagination (Paging 3) + offline cache (KitsuneDB)
ui rip.nerd.wpkit.ui
- PostListView — lista postów z paginacją (RecyclerView)
- PostListView — paginated post list (RecyclerView)
- WPContentView — widok HTML (View-based, Jsoup)
- WPContentView — HTML view (View-based, Jsoup)
- WPContent — Composable renderujący HTML
- WPContent — Composable rendering HTML
- CategoryChipsView — chipy kategorii (Material)
- CategoryChipsView — category chips (Material)
- MenuBarView — poziomy pasek menu
- MenuBarView — horizontal menu bar
- WPPostCard, WPPostGrid, WPRelatedPostsRow…
- WPPostCard, WPPostGrid, WPRelatedPostsRow…
- WPSearchBar, WPTagChips, WPCategoryChips…
- WPSearchBar, WPTagChips, WPCategoryChips…
- WPPostFilterSheet — dolna szuflada z filtrami
- WPPostFilterSheet — bottom sheet with filters
core Parse Module
- ParseKit — singleton zarządzający SDK Parse, sesją, push
- ParseKit — singleton managing Parse SDK, session, push
- ParseRepository — warstwa repozytorium Parse
- ParseRepository — Parse repository layer
- ParseUserInfo — profil użytkownika
- ParseUserInfo — user profile model
- ParseObject — generyczny obiekt Parse
- ParseObject — generic Parse object
- Anonimowi użytkownicy + push (ParseInstallation)
- Anonymous users + push (ParseInstallation)
- Obsługa banów, odtwarzanie sesji
- Ban handling, session restore
Instalacja
Installation
Krok 1 — Repozytorium GitHub Packages
Step 1 — GitHub Packages Repository
Dodaj repozytorium do pliku settings.gradle(.kts). Wymagany Personal Access Token z uprawnieniem read:packages.
Add the repository to settings.gradle(.kts). A Personal Access Token with read:packages permission is required.
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
maven {
url = uri("https://maven.pkg.github.com/nerdrip/wpkit")
credentials {
username = providers.gradleProperty("gpr.user").orNull
?: System.getenv("GITHUB_ACTOR")
password = providers.gradleProperty("gpr.token").orNull
?: System.getenv("GITHUB_TOKEN")
}
}
}
}
local.properties lub jako zmienne środowiskowe. Nie commituj tokenów do repozytorium!
⚠️ Store credentials in local.properties or as environment variables. Never commit tokens to version control!
Krok 2 — Zależność
Step 2 — Dependency
// build.gradle.kts (moduł aplikacji / app module)
dependencies {
implementation("rip.nerd.wpkit:wpkit:1.0.1")
}
Krok 3 — Uprawnienia AndroidManifest
Step 3 — AndroidManifest permissions
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Krok 4 — Plugin WordPress (opcjonalny, zalecany)
Step 4 — WordPress Plugin (optional but recommended)
Skopiuj katalog wordpress-plugin/ do wp-content/plugins/wpkit-workspace/ i aktywuj plugin w panelu WordPress. Bez pluginu biblioteka korzysta ze standardowego WP REST API (bez filtrowania workspace, bez autoryzacji tokenem).
Copy the wordpress-plugin/ directory to wp-content/plugins/wpkit-workspace/ and activate it in WordPress admin. Without the plugin, the library falls back to the standard WP REST API (no workspace filtering, no token auth).
Konfiguracja
Configuration
Inicjalizuj WPKit w klasie Application:
Initialize WPKit in your Application class:
class App : Application() {
override fun onCreate() {
super.onCreate()
WPKit.init(
app = this,
cfg = WPConfig(
baseUrl = "https://your-wp-site.com/",
workspaceToken = "your_64_char_token", // optional
cacheMB = 20,
timeoutMs = 30_000L,
retryOnError = 1,
logger = if (BuildConfig.DEBUG)
WPKitLogger.Android
else WPKitLogger.Noop
),
debug = BuildConfig.DEBUG,
registerForNotifications = true // default: false
)
}
}
debug = true włącza pełne logowanie HTTP (ciała żądań i odpowiedzi) przez KNETLoggingInterceptor. Wyłącz w buildach produkcyjnych.
💡 debug = true enables full HTTP logging (request/response bodies) via KNETLoggingInterceptor. Disable in production builds.
registerForNotifications = true aktywuje rejestrację urządzenia w ParseInstallation dla push notyfikacji. Domyślnie wyłączone (false) — Parse SDK jest inicjalizowane, ale urządzenie nie jest rejestrowane do push-ów.
💡 registerForNotifications = true enables device registration in ParseInstallation for push notifications. Disabled by default (false) — the Parse SDK is still initialized but the device is not registered for push.
WPKit (singleton)
WPKit to obiekt Kotlin pełniący rolę głównego punktu wejścia biblioteki. Po wywołaniu init() udostępnia:
WPKit is a Kotlin object serving as the library's main entry point. After init(), it exposes:
Parametry init()
init() parameters
| Parametr | Parameter | Typ | Type | Domyślnie | Default | Opis / Description |
|---|---|---|---|---|---|---|
app |
Application |
— | Instancja Application Androida. |
Android Application instance. |
||
cfg |
WPConfig |
— | Konfiguracja biblioteki — patrz WPConfig. | Library configuration — see WPConfig. | ||
debug |
Boolean |
— | Włącza pełne logowanie HTTP (ciała żądań/odpowiedzi). | Enables full HTTP logging (request/response bodies). | ||
registerForNotifications |
Boolean |
false |
Gdy true, urządzenie jest rejestrowane w ParseInstallation dla push notyfikacji. Tworzona jest też anonimowa sesja jeśli użytkownik nie jest zalogowany. Gdy false (domyślnie), Parse SDK jest inicjalizowane, ale urządzenie nie jest rejestrowane do push-ów. |
When true, the device is registered in ParseInstallation for push notifications. An anonymous session is also created if the user is not logged in. When false (default), the Parse SDK is initialized but the device is not registered for push. |
Pola dostępne po inicjalizacji
Fields available after initialization
| Pole | Field | Typ | Type | Opis / Description |
|---|---|---|---|---|
api |
WPService |
Klient standardowego WP REST API (KitsuneNET). | Standard WP REST API client (KitsuneNET). | |
pluginApi |
WPkitService? |
Klient API pluginu workspace. Non-null gdy podano workspaceToken. |
Workspace plugin API client. Non-null when workspaceToken is provided. |
|
cfg |
WPConfig |
Konfiguracja przekazana podczas inicjalizacji. | Configuration passed during initialization. | |
log |
WPKitLogger |
Skonfigurowany logger. | Configured logger instance. |
WPConfig
Klasa danych (data class) przechowująca konfigurację biblioteki.
A data class holding the library configuration.
data class WPConfig(
val baseUrl: String,
val workspaceToken: String? = null,
val authTokenProvider: (() -> String?)? = null,
val cacheMB: Int = 10,
val timeoutMs: Long = 30_000L,
val retryOnError: Int = 1,
val logger: WPKitLogger = WPKitLogger.Android
)
| Parametr | Parameter | Domyślnie | Default | Opis / Description |
|---|---|---|---|---|
baseUrl |
— | URL witryny WordPress, np. "https://example.com/" |
WordPress site URL, e.g. "https://example.com/" |
|
workspaceToken |
null |
Token workspace z panelu WP (plugin WPKit). Aktywuje WPkitService. |
Workspace token from WP admin (WPKit plugin). Activates WPkitService. |
|
authTokenProvider |
null |
Lambda zwracająca token WP (np. "Bearer …") dla standardowego REST API. |
Lambda returning a WP token (e.g. "Bearer …") for the standard REST API. |
|
cacheMB |
10 |
Rozmiar dyskowego cache HTTP w MB. | HTTP disk cache size in MB. | |
timeoutMs |
30000 |
Timeout sieci w milisekundach. | Network timeout in milliseconds. | |
retryOnError |
1 |
Liczba automatycznych ponowień przy błędzie sieci. | Number of automatic retries on network error. | |
logger |
WPKitLogger.Android |
Implementacja loggera. | Logger implementation. |
WPService core
Klient standardowego WordPress REST API (/wp-json/wp/v2/). Wszystkie metody są suspend. Używany jako fallback gdy nie skonfigurowano workspaceToken.
Standard WordPress REST API client (/wp-json/wp/v2/). All methods are suspend. Used as fallback when no workspaceToken is configured.
| Metoda | Method | Endpoint | Endpoint | Zwraca | Returns |
|---|---|---|---|---|---|
posts(page?, perPage?, categories?, search?, orderBy?, order?, after?, before?) |
GET /wp/v2/posts |
List<PostDto> |
|||
pages(perPage?, slug?, orderBy?, order?) |
GET /wp/v2/pages |
List<PostDto> |
|||
categories(perPage?, slug?) |
GET /wp/v2/categories |
List<CategoryDto> |
|||
tags(perPage?, slug?) |
GET /wp/v2/tags |
List<CategoryDto> |
|||
menus(locationsCsv?) |
GET /wpkit/v1/menus |
List<MenuDto> |
|||
menu(location) |
GET /wpkit/v1/menu |
MenuDto |
WPkitService plugin
Klient API pluginu WPKit Workspace (/wp-json/wpkit/v1/). Aktywny gdy podano workspaceToken. Token jest wstrzykiwany automatycznie do nagłówka X-WPKit-Token.
WPKit Workspace plugin API client (/wp-json/wpkit/v1/). Active when workspaceToken is provided. The token is injected automatically into the X-WPKit-Token header.
| Metoda | Method | Opis / Description |
|---|---|---|
info() |
Wersja pluginu (publiczny, bez tokenu). | Plugin version (public, no token). |
siteInfo() |
Informacje o stronie: nazwa, tagline, logo, strefa czasowa. | Site info: name, tagline, logo, timezone. |
workspace() |
Informacje o workspace i jego możliwościach. | Workspace info and capabilities. |
workspaceSettings() |
Niestandardowe ustawienia klucz-wartość. | Custom key-value settings. |
stats() |
Statystyki workspace (liczniki + śledzenie żądań). | Workspace statistics (counts + request tracking). |
posts(page?, perPage?, search?, categories?, tags?, orderBy?, order?, after?, before?, authorId?) |
Stronicowane posty workspace. | Paginated workspace posts. |
post(id) |
Pojedynczy post po ID. | Single post by ID. |
postBySlug(slug) |
Pojedynczy post po slug. | Single post by slug. |
relatedPosts(id, limit) |
Powiązane posty. | Related posts. |
pages(page?, perPage?, search?, orderBy?, order?) |
Stronicowane strony workspace. | Paginated workspace pages. |
page(id) |
Strona po ID. | Page by ID. |
pageBySlug(slug) |
Strona po slug. | Page by slug. |
categories() |
Kategorie workspace. | Workspace categories. |
tags() |
Tagi workspace. | Workspace tags. |
menus() / menu(location) |
Wszystkie menu / menu po lokalizacji. | All menus / menu by location. |
search(query, type?, page?, perPage?) |
Pełnotekstowe wyszukiwanie. | Full-text search. |
featuredPosts(type, limit) |
Posty oznaczone jako wyróżnione. | Featured posts/pages. |
authors() |
Autorzy postów w workspace. | Workspace post authors. |
toDomain() lub WordPressRepository, by uzyskać modele domenowe.
💡 All methods return DTOs. Use toDomain() or WordPressRepository to get domain models.
WordPressRepository
Warstwa repozytorium łącząca oba klienty API. Gdy pluginApi jest skonfigurowany, używa wyłącznie pluginu — błędy propagują się jako wyjątki. Bez pluginu używa standardowego WP REST API.
Repository layer combining both API clients. When pluginApi is configured, it uses only the plugin — errors propagate as exceptions. Without the plugin, falls back to standard WP REST API.
val repo = WordPressRepository(WPKit.api, WPKit.pluginApi, WPKit.log)
Posty i strony
Posts & pages
// Posty paginowane / Paginated posts
repo.pagedPosts(
perPage = 10, query = "kotlin",
cats = "12,34", tags = "5",
orderBy = "date", order = "desc",
after = "2024-01-01", before = null,
authorId = 3L
).collectLatest { adapter.submitData(it) }
// Pojedynczy post / Single post
val post: Post? = repo.getPost(id = 42L)
val post: Post? = repo.postBySlug("hello-world")
// Strony / Pages (lista)
val pages: List<Post> = repo.pages(perPage = 50)
val page: Post? = repo.pageById(id = 7L)
val page: Post? = repo.pageBySlug("about-us")
// Paginowane strony (Flow)
repo.pagedPages(perPage = 20).collectLatest { adapter.submitData(it) }
Kategorie, tagi, autorzy
Categories, tags, authors
val categories: List<Category> = repo.categories()
val tags: List<Tag> = repo.tags()
val authors: List<Author> = repo.authors() // plugin only
Menu
Menus
val menu: Menu = repo.menu("primary")
val menus: Map<String, Menu> = repo.menus("primary", "footer")
menu.items.forEach { item ->
println("${item.title} | ${item.itemType} | ref=${item.referenceId}")
// item.children — podmenu
}
MenuItem.itemType: "external" | "post" | "page" | "category"
MenuItem.referenceId — ID WordPressa referencjonowanego obiektu (0 = brak).
MenuItem.itemType: "external" | "post" | "page" | "category"
MenuItem.referenceId — WordPress ID of the referenced object (0 = none).
Wyróżnione i powiązane posty
Featured & related posts
val featured: List<Post> = repo.featuredPosts(type = "post", limit = 10)
val related: List<Post> = repo.relatedPosts(post, limit = 5)
Wyszukiwanie
Search
val results: List<Post> = repo.search("wordpress", type = "post")
repo.pagedSearch("kotlin", perPage = 10).collectLatest { adapter.submitData(it) }
Workspace i informacje o stronie
Workspace & site info
val info: WorkspaceInfo? = repo.workspaceInfo()
val settings: WorkspaceSettings? = repo.workspaceSettings()
val stats: WorkspaceStats? = repo.workspaceStats()
val site: SiteInfo? = repo.siteInfo()
val color = settings?.getString("primary_color")
val ads = settings?.getBool("show_ads")
val limit = settings?.getInt("post_limit")
val available: Boolean = repo.isPluginAvailable()
*Result() (np. getPostResult()) zwracający WPResult<T> zamiast wyrzucać wyjątki.
💡 Every method has a *Result() variant (e.g. getPostResult()) returning WPResult<T> instead of throwing.
Paginacja (Paging 3)
Pagination (Paging 3)
Biblioteka używa Jetpack Paging 3 do ładowania postów strona po stronie. Metody pagedPosts(), pagedPages() i pagedSearch() zwracają Flow<PagingData<Post>>.
The library uses Jetpack Paging 3 for page-by-page post loading. pagedPosts(), pagedPages() and pagedSearch() return Flow<PagingData<Post>>.
class PostViewModel : ViewModel() {
private val repo = WordPressRepository(WPKit.api, WPKit.pluginApi, WPKit.log)
val posts = repo.pagedPosts(perPage = 10).cachedIn(viewModelScope)
}
// W Fragment / In Fragment:
viewModel.posts.collectLatest { pagingData ->
postListView.submitData(pagingData)
// lub / or:
adapter.submitData(lifecycle, pagingData)
}
Paging automatycznie ładuje kolejne strony podczas przewijania listy. Konfiguracja przez PagingConfig(pageSize, prefetchDistance).
Paging automatically loads the next pages as the user scrolls. Configured via PagingConfig(pageSize, prefetchDistance).
Cache offline
Offline Cache
pagedPostsCached() łączy paginację Paging 3 z lokalną bazą danych KitsuneDB. Przy każdym odświeżeniu pobiera z serwera tylko posty nowsze niż ostatnio pobrane (synchronizacja przyrostowa oparta na polu modified). Gdy sieć jest niedostępna, wyświetlane są dane z lokalnej bazy.
pagedPostsCached() combines Paging 3 with a local KitsuneDB database. On each refresh it fetches only posts newer than the latest local entry (incremental sync based on the modified field). When the network is unavailable, cached data is displayed transparently.
// Utwórz cache raz (np. w Application lub ViewModel)
// Create cache once (e.g. in Application or ViewModel)
val cache = PostCacheStore.create(context, workspaceSlug = "my-workspace")
// Używaj jak zwykłego pagedPosts / Use like regular pagedPosts
repo.pagedPostsCached(
cache = cache,
perPage = 50, // rozmiar batcha synchronizacji / sync batch size
query = null,
cats = null
).cachedIn(viewModelScope)
.collectLatest { adapter.submitData(it) }
WPState<T>
Trójstanowy model UI dla ViewModeli: Loading → Success | Error. Zaprojektowany do użycia ze StateFlow.
Three-state UI model for ViewModels: Loading → Success | Error. Designed for use with StateFlow.
sealed class WPState<out T> {
data object Loading : WPState<Nothing>()
data class Success<T>(val data: T) : WPState<T>()
data class Error(val message: String,
val cause: Throwable?,
val code: Int = 0) : WPState<Nothing>()
}
// Collect in Fragment
viewModel.categories.collect { state ->
when (state) {
is WPState.Loading -> showSpinner()
is WPState.Success -> showCategories(state.data)
is WPState.Error -> showError(state.message)
}
}
// Functional combinators
state
.onLoading { showSpinner() }
.onSuccess { data -> render(data) }
.onError { msg, _, _ -> showError(msg) }
// Wrap any suspend block
val state: WPState<List<Post>> = WPState.from { repo.categories() }
// Accessors
val data: T? = state.getOrNull()
val data: T = state.getOrElse(emptyList())
val error: String? = state.errorOrNull()
WPResult<T>
Bezpieczny typ wyniku operacji sieciowych. Każda metoda repozytorium posiada wariant *Result() zwracający WPResult<T> zamiast wyrzucać wyjątki.
Safe result type for network operations. Every repository method has a *Result() variant returning WPResult<T> instead of throwing.
sealed class WPResult<out T> {
data class Success<T>(val data: T) : WPResult<T>()
data class Error(val code: Int, val message: String,
val cause: Throwable?) : WPResult<Nothing>()
}
val result: WPResult<Post> = repo.postBySlugResult("hello-world")
result
.onSuccess { post -> showPost(post) }
.onError { code, message, cause -> showError(message) }
// Transforms
val title: String = result.map { it.title }.getOrElse("Untitled")
// Unsafe unwrap (throws on Error)
val post: Post = result.getOrThrow()
// Combine results
val result2 = result.flatMap { post -> repo.getPostResult(post.id) }
WPPostsViewModel
Abstrakcyjna klasa bazowa ViewModel obsługująca paginowaną listę postów z pełnym wsparciem dla filtrów. Podklasa musi dostarczyć instancję WordPressRepository.
Abstract base ViewModel handling a paginated post list with full filter support. Subclass must provide a WordPressRepository instance.
class MyViewModel : WPPostsViewModel() {
override val repo = WordPressRepository(WPKit.api, WPKit.pluginApi, WPKit.log)
}
| Flow / StateFlow | Flow / StateFlow | Opis / Description |
|---|---|---|
posts: Flow<PagingData<Post>> |
Paginowane posty. Automatycznie ponownie ładowane przy zmianie filtrów (debounce 300 ms). | Paginated posts. Auto-reloads on filter change (300 ms debounce). |
categories: StateFlow<WPState<List<Category>>> |
Kategorie (ładowane przez loadSideData()). |
Categories (loaded by loadSideData()). |
tags, featured, siteInfo |
Analogicznie jak categories. |
Same pattern as categories. |
Polecenia filtrowania
Filter commands
viewModel.loadSideData() // ładuje categories, tags, siteInfo, featured
viewModel.setQuery("kotlin")
viewModel.clearQuery()
viewModel.toggleCategory(12L)
viewModel.setCategories(setOf(12L, 34L))
viewModel.clearCategories()
viewModel.toggleTag(5L)
viewModel.setTags(setOf(5L))
viewModel.setOrderBy("date", ascending = false)
viewModel.setDateRange(after = "2024-01-01", before = null)
viewModel.setDatePreset(WPDateRangePreset.LAST_7_DAYS)
viewModel.clearDateRange()
viewModel.setPerPage(20)
viewModel.clearFilters()
WPDateRangePreset
Enum z predefiniowanymi zakresami dat. Każda wartość oblicza zakres względem aktualnej daty i zwraca obiekty DateRange(after, before) w formacie ISO 8601.
Enum with predefined date ranges. Each value computes the range relative to the current date and returns DateRange(after, before) objects in ISO 8601 format.
val range = WPDateRangePreset.LAST_30_DAYS.toRange()
// range.after = "2024-02-17T00:00:00"
// range.before = null
repo.pagedPosts(after = range.after, before = range.before)
// Dostępne presets / Available presets:
// TODAY, YESTERDAY, LAST_7_DAYS, LAST_30_DAYS,
// THIS_WEEK, LAST_WEEK, THIS_MONTH, LAST_MONTH,
// THIS_YEAR, LAST_YEAR, ALL_TIME
Modele domenowe
Domain Models
Czyste modele Kotlin używane przez warstwę UI. Tworzone z obiektów DTO metodą rozszerzającą toDomain().
Clean Kotlin models used by the UI layer. Created from DTO objects via the toDomain() extension function.
Post
data class Post(
val id: Long,
val slug: String,
val type: String, // "post" | "page"
val title: String,
val excerptHtml: String,
val contentHtml: String,
val featuredUrl: String?,
val date: String, // ISO 8601
val modified: String, // ISO 8601
val author: Author?,
val categories: List<Category>,
val tags: List<Tag>,
val link: String,
val featured: Boolean, // wyróżniony w workspace / featured in workspace
val readingTimeMinutes: Int, // -1 = nieznany / unknown
val wordCount: Int // -1 = nieznany / unknown
)
Category / Tag / Author
data class Category(val id: Long, val name: String, val slug: String,
val description: String, val parent: Long, val count: Int)
data class Tag(val id: Long, val name: String, val slug: String,
val description: String, val count: Int)
data class Author(val id: Long, val name: String, val avatarUrl: String?,
val bio: String, val url: String, val postCount: Int)
Menu & MenuItem
data class Menu(val id: Long, val name: String, val slug: String,
val location: String?, val items: List<MenuItem>)
data class MenuItem(
val id: Long,
val title: String,
val url: String,
val target: String,
val itemType: String, // "external" | "post" | "page" | "category"
val referenceId: Long, // WP ID referencji (0 = brak) / reference WP ID (0 = none)
val children: List<MenuItem>
)
WorkspaceInfo / WorkspaceSettings / WorkspaceStats / SiteInfo
data class WorkspaceInfo(val id: Int, val slug: String, val name: String,
val description: String, val version: String,
val capabilities: Map<String, Boolean>)
data class WorkspaceSettings(val data: Map<String, Any?>) {
fun getString(key: String): String?
fun getInt(key: String): Int?
fun getBool(key: String): Boolean?
fun getList(key: String): List<*>?
}
data class WorkspaceStats(val postCount: Int, val pageCount: Int, val menuCount: Int,
val tagCount: Int, val featuredCount: Int,
val requestCount: Long, val lastRequestAt: String?)
data class SiteInfo(val name: String, val tagline: String, val url: String,
val language: String, val timezone: String,
val logoUrl: String?, val iconUrl: String?, val adminEmail: String)
Rozszerzenia
Extensions
Rozszerzenia Post
Post extensions
post.readingTimeMinutes() // server-side lub ~200 wpm; min 1
post.wordCount() // server-side lub z HTML
post.toPlainText() // usunięcie tagów HTML
post.formattedDate("dd MMM yyyy") // "01 Jan 2024"
post.formattedModified()
post.isRecent(days = 7) // true jeśli opublikowany w ostatnich N dniach
post.hasCategory("tech") // wg slug
post.hasTag("kotlin") // wg slug
post.shareText() // "Tytuł\nhttps://link"
post.primaryCategory() // pierwsza kategoria lub null
Rozszerzenia List<Post>
List<Post> extensions
posts.groupByMonth() // Map<"January 2024", List<Post>>
posts.filterByCategory("tech")
posts.filterByTag("kotlin")
posts.featured() // tylko posty z featured = true
Rozszerzenia dat (String)
Date extensions (String)
"2024-01-15T10:00:00".parseWPDate() // → Date?
"2024-01-15T10:00:00".formatWPDate("MMM d") // → "Jan 15"
Rozszerzenia Menu
Menu extensions
menu.flatItems() // płaska lista wszystkich MenuItem (depth-first)
menu.findByUrl("/about") // dopasowanie dokładne URL
menu.findByTitle("About") // dopasowanie tytułu (case-insensitive)
Rozszerzenia kategorii i tagów
Category & tag extensions
categories.sortedByName()
categories.sortedByCount() // sortowanie malejące wg count
categories.findBySlug("tech")
tags.sortedByCount()
tags.withMinCount(5) // tylko tagi z ≥ 5 postami
tags.findBySlug("kotlin")
Rozszerzenia autorów
Author extensions
authors.topAuthor() // autor z największą liczbą postów
WPBookmarkManager
Zarządzanie zakładkami postów zapisywanymi w SharedPreferences. Reaktywny dostęp przez Flow.
Manages post bookmarks persisted in SharedPreferences. Reactive access via Flow.
val bookmarks = WPBookmarkManager.create(context, workspaceSlug = "default")
// Dodaj / usuń / przełącz
bookmarks.add(post)
bookmarks.remove(post.id)
val added: Boolean = bookmarks.toggle(post)
// Sprawdź
if (bookmarks.isBookmarked(post.id)) { … }
// Obserwuj reaktywnie / Observe reactively
lifecycleScope.launch {
bookmarks.bookmarkedIds.collect { ids -> adapter.updateBookmarks(ids) }
bookmarks.count.collect { n -> badge.text = n.toString() }
}
// Filtruj listę postów do zakładkowanych
val saved: List<Post> = bookmarks.filterBookmarked(posts)
// Snapshot i czyszczenie
val ids: Set<Long> = bookmarks.snapshot()
bookmarks.clearAll()
WPKitLogger
Interfejs loggera z wbudowanymi implementacjami i konstruktorem własnego loggera.
Logger interface with built-in implementations and a custom logger builder.
// Wbudowane / Built-in
WPKitLogger.Android // → android.util.Log (domyślny / default)
WPKitLogger.Noop // → cichy / silent
// Własny (np. Timber) / Custom (e.g. Timber)
val logger = WPKitLogger.custom(
onDebug = { tag, msg -> Timber.tag(tag).d(msg) },
onWarn = { tag, msg, t -> Timber.tag(tag).w(t, msg) },
onError = { tag, msg, t -> Timber.tag(tag).e(t, msg) }
)
WPKit.init(app, cfg = WPConfig(baseUrl = "…", logger = logger), debug = false)
ParseKit core (singleton)
ParseKit to singleton Kotlin zarządzający cyklem życia Parse Android SDK, persystencją sesji, rejestracją push notyfikacji (ParseInstallation) i cache profilu użytkownika. Jest inicjalizowany automatycznie przez WPKit.init().
ParseKit is a Kotlin singleton managing the Parse Android SDK lifecycle, session persistence, push notification registration (ParseInstallation) and user profile caching. It is initialized automatically by WPKit.init().
Proces inicjalizacji (bootstrap)
Bootstrap flow
Cały proces jest uruchamiany automatycznie przez WPKit.init():
The entire process is triggered automatically by WPKit.init():
- Natychmiastowa inicjalizacja Parse SDK z konfiguracji zapisanej w
SharedPreferences(zero latencji). - Instant Parse SDK initialization from cached
SharedPreferencesconfig (zero latency). - W tle: pobranie świeżej konfiguracji z WordPress bridge (
/wpkit/v1/parse/config). - Background: fetch fresh config from WordPress bridge (
/wpkit/v1/parse/config). - Odtworzenie sesji użytkownika:
ParseUser.become(token)+ rejestracjaParseInstallation(push) — tylko gdyregisterForNotifications = true. - Session restore:
ParseUser.become(token)+ParseInstallationregistration (push) — only whenregisterForNotifications = true. - Odświeżenie profilu z serwera (wykrywanie banów).
- Profile refresh from server (ban detection).
- Jeśli brak zalogowanego użytkownika i
registerForNotifications = true→ automatyczne utworzenie anonimowego użytkownika dla push notyfikacji. - If no logged-in user and
registerForNotifications = true→ automatic anonymous user creation for push notifications.
registerForNotifications = false (domyślnie), kroki rejestracji ParseInstallation i tworzenia anonimowych użytkowników są pomijane. Parse SDK jest inicjalizowane, a logowanie/rejestracja działają normalnie — jedynie urządzenie nie jest rejestrowane do otrzymywania push notyfikacji.
💡 When registerForNotifications = false (default), the ParseInstallation registration and anonymous user creation steps are skipped. The Parse SDK is still initialized and login/registration works normally — only the device is not registered to receive push notifications.
Anonimowi użytkownicy
Anonymous users
Gdy registerForNotifications = true, SDK Parse jest gotowe i nie istnieje sesja prawdziwego użytkownika, ParseKit automatycznie tworzy anonimowego użytkownika za pomocą ParseAnonymousUtils. Dzięki temu urządzenie jest natychmiast zarejestrowane w ParseInstallation — push notyfikacje działają od razu, jeszcze przed logowaniem.
When registerForNotifications = true, the Parse SDK is ready and no real user session exists, ParseKit automatically creates an anonymous user via ParseAnonymousUtils. This immediately registers the device in ParseInstallation — push notifications work right away, even before login.
Przy późniejszym logowaniu (login) lub rejestracji (registerAndLogin) sesja anonimowa jest zastępowana / aktualizowana — ParseInstallation jest ponownie powiązana z prawdziwym użytkownikiem.
On subsequent login (login) or registration (registerAndLogin), the anonymous session is replaced / upgraded — the ParseInstallation is reassociated with the real user.
Persystencja sesji
Session persistence
Po udanym logowaniu token sesji i pełny profil użytkownika (ParseUserInfo) są zapisywane w SharedPreferences. Przy kolejnym uruchomieniu aplikacji:
After a successful login, the session token and full user profile (ParseUserInfo) are persisted in SharedPreferences. On the next app launch:
- Profil jest dostępny natychmiast z cache (bez sieci) — UI może wyświetlić dane od razu.
- Profile is available instantly from cache (no network) — UI can display data immediately.
- Sesja SDK jest przywracana w tle przez
ParseUser.become(token). - SDK session is restored in background via
ParseUser.become(token). - Po udanym
become()wywoływane jestsaveInstallation()— rejestracja urządzenia dla push notyfikacji. - After successful
become(),saveInstallation()is called — registering the device for push notifications. - Profil jest odświeżany z serwera w tle.
- Profile is refreshed from server in background.
Obsługa banów
Ban handling
WordPress Parse bridge egzekwuje bany po stronie serwera. Każde wywołanie API, które napotka zbanowanego użytkownika (HTTP 403, kod user_banned), automatycznie czyści lokalną sesję i emituje null na userState.
The WordPress Parse bridge enforces bans server-side. Any API call that encounters a banned user (HTTP 403, code user_banned) automatically clears the local session and emits null on userState.
| Typ bana | Ban type | Opis / Description | |
|---|---|---|---|
| Permanentny | Permanent | banned = true, ban_timestamp = 0 |
banned = true, ban_timestamp = 0 |
| Tymczasowy | Temporary | banned = true, ban_timestamp > now (Unix epoch) |
banned = true, ban_timestamp > now (Unix epoch) |
| Wygasły | Expired | Serwer automatycznie zdejmuje ban przy kolejnym logowaniu. | Server auto-lifts the ban on the next login attempt. |
Obserwowalny stan
Observable state
// Obserwacja stanu użytkownika / Observe user state
ParseKit.userState.collect { user: ParseUserInfo? ->
if (user != null) showProfile(user)
else showLoginScreen()
}
// Stan anonimowy / Anonymous state
ParseKit.isAnonymous.collect { anon: Boolean ->
// true = sesja tymczasowa (push działa, ale użytkownik niezarejestrowany)
// true = temporary session (push works, but user not registered)
}
// Gotowość SDK / SDK readiness
val ready: Boolean = ParseKit.awaitReady()
ParseRepository core
Warstwa repozytorium dla wszystkich operacji Parse. Deleguje do ParseKit. Przeznaczona do użycia w ViewModelach i warstwach biznesowych.
Repository layer for all Parse operations. Delegates to ParseKit. Designed for use in ViewModels and business layers.
val parseRepo = ParseRepository(logger = WPKit.log)
Uwierzytelnianie
Authentication
// Login — zwraca profil / returns profile
val result: WPResult<ParseUserInfo> = parseRepo.login("username", "password")
result
.onSuccess { user -> showProfile(user) }
.onError { code, msg, _ -> showError(msg) }
// Rejestracja bez logowania / Register only (no auto-login)
parseRepo.register("username", "password", "user@example.com")
// Rejestracja + auto-login (aktualizuje anonimowego użytkownika, jeśli istnieje)
// Register + auto-login (upgrades anonymous user if present)
val result = parseRepo.registerAndLogin("username", "password", "user@example.com")
// Wylogowanie — czyści sesję serwera + lokalną, tworzy nowego anonimowego użytkownika
// Logout — clears server + local session, re-creates anonymous user for push
parseRepo.logout()
Profil użytkownika
User profile
// Natychmiast z cache (bez sieci) / Instant from cache (no network)
val user: ParseUserInfo? = parseRepo.cachedUser()
// Świeży z serwera (wykrywa bany) / Fresh from server (detects bans)
val result: WPResult<ParseUserInfo?> = parseRepo.refreshUser()
// Aktualizacja pól (profil odświeżany automatycznie po zapisie)
// Update fields (profile refreshed automatically after save)
parseRepo.updateUser(mapOf("username" to "new_name"))
parseRepo.updateUser(mapOf("email" to "new@example.com"))
parseRepo.updateUser(mapOf("points" to "+10")) // punkty relatywne / relative points
parseRepo.updateUser(mapOf("points" to "-5"))
// Email resetowania hasła / Password reset email
parseRepo.requestPasswordReset("user@example.com")
Obserwowalny stan autoryzacji
Observable auth state
// Obserwuj w ViewModel / Fragment
// Observe in ViewModel / Fragment
parseRepo.userState.collect { user: ParseUserInfo? ->
// null = wylogowany / zbanowany / sesja wygasła
// null = logged out / banned / expired
}
parseRepo.isAnonymousState.collect { isAnon: Boolean ->
// true = tymczasowa sesja anonimowa
// true = temporary anonymous session
}
Sprawdzanie statusu
Status checks
val loggedIn: Boolean = parseRepo.isLoggedIn()
val anonymous: Boolean = parseRepo.isAnonymous()
val token: String? = parseRepo.getSessionToken()
Zapytania o dane Parse
Parse data queries
val result: WPResult<List<ParseObject>> = parseRepo.queryObjects("GameScore")
result.onSuccess { objects ->
objects.forEach { obj ->
val score = obj.getInt("score")
val name = obj.getString("playerName")
val id = obj.objectId
}
}
| Metoda | Method | Zwraca | Returns | Opis / Description |
|---|---|---|---|---|
login(user, pass) |
WPResult<ParseUserInfo> |
Login przez WP bridge. Cache token + profil. | Login via WP bridge. Caches token + profile. | |
register(user, pass, email) |
WPResult<String> |
Rejestracja (bez logowania). | Register only (no login). | |
registerAndLogin(…) |
WPResult<ParseUserInfo> |
Rejestracja + login. Aktualizuje anonimowego użytkownika. | Register + login. Upgrades anonymous user. | |
logout() |
WPResult<Unit> |
Wylogowanie + ponowne utworzenie anonimowej sesji. | Logout + re-creates anonymous session. | |
cachedUser() |
ParseUserInfo? |
Profil z cache (natychmiast, bez sieci). | Cached profile (instant, no network). | |
refreshUser() |
WPResult<ParseUserInfo?> |
Świeży profil z serwera. Wykrywa bany. | Fresh profile from server. Detects bans. | |
updateUser(fields) |
WPResult<String> |
Aktualizacja pól: username, email, password, points ("+10", "-5"). | Update fields: username, email, password, points ("+10", "-5"). | |
requestPasswordReset(email) |
WPResult<String> |
Wysyłka emaila resetowania hasła. | Sends password reset email. | |
queryObjects(className) |
WPResult<List<ParseObject>> |
Zapytanie o obiekty danej klasy Parse. | Query objects of a given Parse class. | |
userState |
StateFlow<ParseUserInfo?> |
Obserwowalny stan użytkownika (null = wylogowany). | Observable user state (null = logged out). | |
isAnonymousState |
StateFlow<Boolean> |
Obserwowalny stan anonimowy. | Observable anonymous state. | |
isLoggedIn() |
Boolean |
Czy istnieje lokalna sesja (token + profil). | Whether a local session exists (token + profile). | |
isAnonymous() |
Boolean |
Czy bieżąca sesja jest anonimowa. | Whether current session is anonymous. | |
getSessionToken() |
String? |
Zapisany token sesji Parse. | Stored Parse session token. |
Modele Parse core
Parse Models core
ParseUserInfo
Profil uwierzytelnionego użytkownika Parse. Tworzony z DTO metodą toDomain().
Authenticated Parse user profile. Created from DTO via toDomain().
data class ParseUserInfo(
val objectId: String,
val username: String,
val email: String,
val emailVerified: Boolean = false,
val points: Int = 0,
val banned: Boolean = false,
val banTimestamp: Long = 0L, // 0 = ban permanentny / permanent ban (when banned=true)
val createdAt: String = "", // ISO 8601
val updatedAt: String = "" // ISO 8601
)
ParseObject
Generyczny obiekt Parse (klucz-wartość). Zwracany przez queryObjects().
Generic Parse object (key-value). Returned by queryObjects().
data class ParseObject(
val objectId: String,
val className: String,
val data: Map<String, Any?>
) {
fun getString(key: String): String?
fun getInt(key: String): Int?
fun getLong(key: String): Long?
fun getBool(key: String): Boolean?
operator fun get(key: String): Any? // raw access
}
Przykład użycia:
Usage example:
val obj: ParseObject = …
val name: String? = obj.getString("playerName")
val score: Int? = obj.getInt("score")
val raw: Any? = obj["customField"]
Endpointy Parse bridge plugin
Parse Bridge Endpoints plugin
Endpointy WordPress bridge dla Parse Server. Dostępne pod /wp-json/wpkit/v1/parse/. Wymagają nagłówka X-WPKit-Token (workspace token) lub tokenu sesji Parse.
WordPress bridge endpoints for Parse Server. Available under /wp-json/wpkit/v1/parse/. Require the X-WPKit-Token header (workspace token) or a Parse session token.
| Endpoint | Auth | Auth | Opis / Description |
|---|---|---|---|
GET /wpkit/v1/parse/config |
token | Konfiguracja Parse Server (appId, serverUrl, clientKey). Używana do inicjalizacji SDK. | Parse Server config (appId, serverUrl, clientKey). Used for SDK initialization. |
POST /wpkit/v1/parse/login |
token | Login — zwraca sessionToken. Body: username, password. |
Login — returns sessionToken. Body: username, password. |
POST /wpkit/v1/parse/register |
token | Rejestracja użytkownika. Body: username, password, email. |
User registration. Body: username, password, email. |
POST /wpkit/v1/parse/logout |
session | Invalidacja sesji na serwerze. Header: X-Parse-Session. |
Server-side session invalidation. Header: X-Parse-Session. |
GET /wpkit/v1/parse/user |
session | Pełny profil użytkownika. Header: X-Parse-Session. |
Full user profile. Header: X-Parse-Session. |
POST /wpkit/v1/parse/user/update |
session | Aktualizacja pól użytkownika. Obsługiwane klucze: username, email, password, points (wartości relatywne: "+10", "-5"). |
Update user fields. Supported keys: username, email, password, points (relative values: "+10", "-5"). |
POST /wpkit/v1/parse/password-reset |
token | Wysyłka emaila resetowania hasła. Body: email. |
Send password reset email. Body: email. |
GET /wpkit/v1/parse/objects/{class} |
session | Zapytanie o wszystkie obiekty danej klasy Parse. | Query all objects of a given Parse class. |
token = nagłówek X-WPKit-Token (workspace token); session = nagłówek X-Parse-Session (token sesji użytkownika). Oba są wstrzykiwane automatycznie przez WPkitService.
💡 Auth types: token = X-WPKit-Token header (workspace token); session = X-Parse-Session header (user session token). Both are injected automatically by WPkitService.
Dobre praktyki — Parse core
Best Practices — Parse core
Obserwacja stanu autoryzacji
Observing auth state
Zamiast odpytywać isLoggedIn(), obserwuj userState jako StateFlow — to gwarantuje reaktywne aktualizacje UI przy logowaniu, wylogowaniu i banach.
Instead of polling isLoggedIn(), observe userState as a StateFlow — this guarantees reactive UI updates on login, logout and bans.
class ProfileViewModel : ViewModel() {
private val parseRepo = ParseRepository()
val user: StateFlow<ParseUserInfo?> = parseRepo.userState
fun login(username: String, password: String) {
viewModelScope.launch {
parseRepo.login(username, password)
.onError { _, msg, _ -> _error.value = msg }
}
}
fun logout() {
viewModelScope.launch { parseRepo.logout() }
}
}
Bezpieczne korutyny we Fragmentach
Safe coroutines in Fragments
We Fragmentach zawsze używaj viewLifecycleOwner.lifecycleScope zamiast lifecycleScope. Zapobiega to NullPointerException gdy korutyna wznowi się po onDestroyView() (np. użytkownik zmieni zakładkę podczas ładowania danych).
In Fragments always use viewLifecycleOwner.lifecycleScope instead of lifecycleScope. This prevents NullPointerException when a coroutine resumes after onDestroyView() (e.g. user switches tabs while data is loading).
// ✅ Poprawnie / Correct — anuluje się automatycznie z widokiem
// ✅ Cancels automatically with the view lifecycle
viewLifecycleOwner.lifecycleScope.launch {
val result = parseRepo.refreshUser()
_binding?.textView?.text = result.getOrNull()?.username
}
// ❌ Źle / Wrong — korutyna przeżywa zniszczenie widoku
// ❌ Coroutine survives view destruction → NPE on _binding!!
lifecycleScope.launch {
val result = parseRepo.refreshUser()
binding.textView.text = result.getOrNull()?.username // 💥
}
Push notyfikacje przy odtwarzaniu sesji
Push notifications on session restore
Od wersji 1.1.0 ParseKit automatycznie wywołuje saveInstallation() po udanym ParseUser.become() podczas odtwarzania sesji. Dzięki temu urządzenie jest zawsze zarejestrowane dla push notyfikacji — także po restarcie aplikacji z istniejącą sesją.
Since v1.1.0, ParseKit automatically calls saveInstallation() after a successful ParseUser.become() during session restore. This ensures the device is always registered for push notifications — even after an app restart with an existing session.
ParseInstallation.saveInBackground() — ParseKit zarządza rejestracją instalacji automatycznie przy logowaniu, wylogowaniu i odtwarzaniu sesji.
⚠️ Do not call ParseInstallation.saveInBackground() manually — ParseKit manages installation registration automatically on login, logout and session restore.
PostListView UI
Gotowy widok Android wyświetlający listę postów z paginacją Paging 3. Bazuje na RecyclerView + PagingDataAdapter + SwipeRefreshLayout.
Ready-made Android View displaying a paginated post list using Paging 3. Based on RecyclerView + PagingDataAdapter + SwipeRefreshLayout.
<rip.nerd.wpkit.ui.PostListView
android:id="@+id/postList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
| Metoda | Method | Opis / Description |
|---|---|---|
submitData(flow) |
Podłącza Flow<PagingData<Post>>. Automatycznie obserwuje lifecycle. |
Connects a Flow<PagingData<Post>>. Automatically observes lifecycle. |
submitList(posts) |
Wyświetla zwykłą listę postów (bez paginacji). | Displays a plain post list (no paging). |
setOnPostClick(l) |
Callback kliknięcia posta. | Post click callback. |
setOnPostLongClick(l) |
Callback długiego przytrzymania posta. | Post long-press callback. |
setRefreshing(bool) |
Programowe sterowanie wskaźnikiem odświeżania. | Programmatic refresh indicator control. |
Każdy element zawiera: tytuł, skrót HTML i opcjonalny obrazek wyróżniający (Coil).
Each item shows: title, HTML excerpt and optional featured image (Coil).
WPContentView UI / XML
Widok Android renderujący treść HTML WordPress natywnie — bez WebView. Buduje układ z TextView, ImageView itp. Parsowanie przez Jsoup.
Android View that renders WordPress HTML content natively — no WebView. Builds the layout from TextView, ImageView etc. Parsing via Jsoup.
<rip.nerd.wpkit.ui.WPContentView
android:id="@+id/wpContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:wp_paragraphTextSize="16sp"
app:wp_h1TextSize="28sp"
app:wp_linkColor="@color/primary" />
Atrybuty stylizacji
Styling attributes
| Attribute | Type | Domyślnie | Default |
|---|---|---|---|
wp_textColor | color | textColorPrimary | |
wp_bodyTextColor | color | textColorSecondary | |
wp_captionTextColor | color | textColorTertiary | |
wp_dividerColor | color | #1A000000 | |
wp_quoteColor | color | #33000000 | |
wp_codeBackgroundColor | color | #0D000000 | |
wp_codeTextColor | color | textColorPrimary | |
wp_linkColor | color | colorPrimary | |
wp_titleTextSize | dimension | 28px | |
wp_h1TextSize … wp_h6TextSize | dimension | 26–15px | |
wp_paragraphTextSize | dimension | 15px |
Publiczne metody
Public methods
| Metoda | Method | Opis / Description |
|---|---|---|
renderPost(post: Post) |
Renderuje cały post: tytuł, obrazek wyróżniający, treść HTML. | Renders the full post: title, featured image, HTML content. |
renderHtml(html, baseUrl?) |
Renderuje dowolny fragment HTML. | Renders arbitrary HTML fragment. |
clear() |
Czyści widok i przewija do góry. | Clears the view and scrolls to top. |
setOnLinkClick(listener) |
Callback kliknięcia linku. | Link click callback. |
Obsługiwane elementy HTML: h1–h6, p, blockquote, hr, img, figure/figcaption, ul/ol, pre/code, table, iframe (YouTube z miniaturą).
Supported HTML elements: h1–h6, p, blockquote, hr, img, figure/figcaption, ul/ol, pre/code, table, iframe (YouTube with thumbnail).
WPContent Compose
Funkcja @Composable renderująca HTML WordPress jako natywne elementy Jetpack Compose. Używa Jsoup do parsowania.
A @Composable function rendering WordPress HTML as native Jetpack Compose elements. Uses Jsoup for parsing.
@Composable
fun WPContent(html: String, modifier: Modifier = Modifier)
WPContent(
html = post.contentHtml,
modifier = Modifier.padding(16.dp)
)
Obsługiwane tagi: h1–h6, p, img (Coil AsyncImage), ul/ol, blockquote.
Supported tags: h1–h6, p, img (Coil AsyncImage), ul/ol, blockquote.
CategoryChipsView UI
Poziomo przewijany widok chipów kategorii (Material ChipGroup). Obsługuje tryb pojedynczego i wielokrotnego wyboru.
Horizontally scrollable category chips (Material ChipGroup). Supports single and multi-selection modes.
<rip.nerd.wpkit.ui.CategoryChipsView
android:id="@+id/chips"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
chips.setData(
items = categories,
singleSelection = true,
preselected = emptyList(),
onChanged = { selectedIds -> viewModel.setCategories(selectedIds.toSet()) }
)
chips.clearSelection()
val ids: List<Long> = chips.selectedIds()
Komponenty Compose Compose
Compose Components Compose
WPPostCard / WPPostCardCompact
WPPostCard(post = post, onClick = { openPost(it) })
// Posty wyróżnione (featured = true) pokazują odznakę ⭐
// Featured posts display a ⭐ badge on the image
WPPostCardCompact(post = post, onClick = { openPost(it) })
WPPostGrid
// Siatka 2-kolumnowa kart postów / 2-column grid of post cards
WPPostGrid(posts = posts, onClick = { openPost(it) }, columns = 2)
WPRelatedPostsRow
// Poziomo przewijany wiersz "Czytaj dalej" / Horizontal "Read next" row
WPRelatedPostsRow(
posts = relatedPosts,
onClick = { openPost(it) },
title = "Read next",
cardWidth = 160.dp
)
WPSiteHeader / WPReadingTimeChip / WPAuthorRow
WPSiteHeader(siteInfo = siteInfo) // logo + nazwa + tagline
WPReadingTimeChip(post = post) // "5 min read"
WPAuthorRow(author = author, showBio = true) // avatar + imię + bio
WPSearchBar
WPSearchBar(
onSearch = { query -> viewModel.setQuery(query) },
debounceMs = 400L
)
WPTagChips / WPCategoryChips
Poziomo przewijalne chipy tagów/kategorii (LazyRow) — wydajne przy dużych listach.
Horizontally scrollable tag/category chips (LazyRow) — efficient for large lists.
WPTagChips(
tags = tags,
selected = selectedTagIds,
onToggle = { id -> viewModel.toggleTag(id) }
)
WPCategoryChips(
categories = categories,
selected = selectedCatIds,
onToggle = { id -> viewModel.toggleCategory(id) }
)
WPPostFilterSheet
Dolna szuflada (Modal Bottom Sheet) łącząca wszystkie filtry: kategorie, tagi, porządek sortowania, preset zakresu dat.
Modal Bottom Sheet combining all filters: categories, tags, sort order, date range preset.
var showFilter by remember { mutableStateOf(false) }
if (showFilter) {
WPPostFilterSheet(
categories = categories,
tags = tags,
selectedCats = selectedCatIds,
selectedTags = selectedTagIds,
currentOrderBy = "date",
currentOrder = "desc",
currentPreset = null,
onApply = { cats, tags, orderBy, order, preset ->
viewModel.setCategories(cats)
viewModel.setTags(tags)
viewModel.setOrderBy(orderBy, ascending = order == "asc")
viewModel.setDatePreset(preset)
showFilter = false
},
onDismiss = { showFilter = false }
)
}
Plugin WordPress — przegląd plugin
WordPress Plugin — Overview plugin
WPKit Workspace to plugin WordPress dostarczający niestandardowe REST API (/wp-json/wpkit/v1/) oraz panel administracyjny do zarządzania workspace'ami. Workspace to izolowana kolekcja treści (posty, strony, menu, kategorie) przypisana do konkretnej aplikacji mobilnej i chroniona unikalnym tokenem.
WPKit Workspace is a WordPress plugin providing a custom REST API (/wp-json/wpkit/v1/) and an admin panel for managing workspaces. A workspace is an isolated content collection (posts, pages, menus, categories) assigned to a specific mobile app and protected by a unique token.
Instalacja
Installation
wp-content/plugins/
wpkit-workspace/
wpkit.php
admin/
assets/
includes/
Po aktywacji w panelu WordPress pojawia się pozycja menu WPKit z zakładkami: General, Posts, Pages, Categories, Tags, Menus, Settings.
After activation in WordPress admin, a WPKit menu item appears with tabs: General, Posts, Pages, Categories, Tags, Menus, Settings.
Autoryzacja
Authorization
Wszystkie endpointy workspace wymagają nagłówka X-WPKit-Token z unikalnym 64-znakowym tokenem widocznym w panelu WPKit. Token jest wstrzykiwany automatycznie przez WPkitService.
All workspace endpoints require the X-WPKit-Token header with the unique 64-character token shown in the WPKit admin panel. The token is injected automatically by WPkitService.
Endpointy API pluginu
Plugin API Endpoints
| Endpoint | Auth | Auth | Opis / Description | |
|---|---|---|---|---|
GET /wpkit/v1/info | publiczny | public | Wersja pluginu. | Plugin version. |
GET /wpkit/v1/site | publiczny | public | Nazwa, tagline, logo, strefa czasowa. | Site name, tagline, logo, timezone. |
GET /wpkit/v1/workspace | token | Informacje i możliwości workspace. | Workspace info & capabilities. | |
GET /wpkit/v1/workspace/settings | token | Niestandardowe ustawienia klucz-wartość. | Custom key-value settings. | |
GET /wpkit/v1/workspace/stats | token | Liczniki postów/stron/menu + śledzenie żądań. | Post/page/menu counts + request tracking. | |
GET /wpkit/v1/workspace/posts | token | Stronicowane posty. | Paginated posts. | |
GET /wpkit/v1/workspace/posts/{id} | token | Post po ID. | Post by ID. | |
GET /wpkit/v1/workspace/posts/slug/{slug} | token | Post po slug. | Post by slug. | |
GET /wpkit/v1/workspace/posts/{id}/related | token | Powiązane posty. | Related posts. | |
GET /wpkit/v1/workspace/featured | token | Posty/strony wyróżnione. Param: type (post/page/any), limit (1–50). | Featured posts/pages. Params: type (post/page/any), limit (1–50). | |
GET /wpkit/v1/workspace/pages | token | Stronicowane strony. | Paginated pages. | |
GET /wpkit/v1/workspace/pages/{id} | token | Strona po ID. | Page by ID. | |
GET /wpkit/v1/workspace/pages/slug/{slug} | token | Strona po slug. | Page by slug. | |
GET /wpkit/v1/workspace/categories | token | Kategorie workspace. | Workspace categories. | |
GET /wpkit/v1/workspace/tags | token | Tagi workspace. | Workspace tags. | |
GET /wpkit/v1/workspace/authors | token | Autorzy postów w workspace. | Workspace post authors. | |
GET /wpkit/v1/workspace/menus | token | Wszystkie menu. | All menus. | |
GET /wpkit/v1/workspace/menus/{location} | token | Menu po lokalizacji. | Menu by location. | |
GET /wpkit/v1/workspace/search?q= | token | Pełnotekstowe wyszukiwanie. | Full-text search. |
Parametry zapytań (posty/strony)
Query parameters (posts/pages)
page, per_page, search, categories, tags, orderby (date/modified/title/id), order (asc/desc), after (ISO 8601), before (ISO 8601), author
page, per_page, search, categories, tags, orderby (date/modified/title/id), order (asc/desc), after (ISO 8601), before (ISO 8601), author
Pola elementu menu (MenuItem)
Menu item fields
| Pole / Field | Wartości | Values |
|---|---|---|
item_type |
"external" (URL), "post", "page", "category" |
"external" (URL), "post", "page", "category" |
reference_id |
WordPress ID referencjonowanego wpisu/strony/kategorii (0 = brak). | WordPress ID of referenced post/page/category (0 = none). |
Dodatkowe pola w odpowiedzi dla postów
Extra post response fields
| Pole / Field | Opis / Description | |
|---|---|---|
featured |
true jeśli oznaczony jako wyróżniony w panelu workspace. |
true if marked as featured in workspace admin. |
reading_time |
Szacowany czas czytania w minutach (~200 słów/min). | Estimated reading time in minutes (~200 wpm). |
word_count |
Liczba słów treści posta. | Word count of post content. |
Nagłówki odpowiedzi
Response headers
Cache-Control: public, max-age=120 · X-WPKit-Version · X-WP-Total · X-WP-TotalPages
Panel administracyjny pluginu
Plugin Admin Panel
- Tworzenie workspace — unikalny 64-znakowy token generowany automatycznie.
- Workspace creation — unique 64-character token generated automatically.
- Posty i strony — przypisywanie wpisów WordPress do workspace; przełącznik ⭐ wyróżnienia per wpis (AJAX, bez przeładowania strony).
- Posts & pages — assigning WordPress posts to workspace; ⭐ featured toggle per entry (AJAX, no page reload).
- Kategorie — zarządzanie kategoriami na poziomie workspace. Posty przypisane do kategorii workspace, nie zanieczyszczają struktury kategorii całego WP.
- Categories — managed at workspace level. Posts are assigned to workspace categories, keeping the global WP category structure clean.
- Tagi — zakładka tagów widoczna i funkcjonalna dla każdego workspace.
- Tags — tags tab visible and functional for every workspace.
- Menu — kreator menu z selektorem typu pozycji (Zewnętrzny link / Post / Strona / Kategoria). Dla typów post/strona/kategoria widoczna jest lista wyboru obiektu z workspace.
- Menus — menu builder with item type selector (External link / Post / Page / Category). For post/page/category types a reference picker shows workspace objects.
- Ustawienia — dowolne pary klucz-wartość konfigurowane w panelu; dostępne przez
repo.workspaceSettings(). - Settings — arbitrary key-value pairs configurable in the panel; accessible via
repo.workspaceSettings(). - Statystyki — karta z licznikami: posty, strony, menu, tagi, wyróżnione, liczba żądań API i czas ostatniego żądania.
- Statistics — card with counters: posts, pages, menus, tags, featured, API request count and last request time.
- Duplikacja, Eksport, Import — klon workspace z nowym tokenem; eksport/import JSON z pełną konfiguracją.
- Duplicate, Export, Import — clone workspace with new token; export/import JSON with full configuration.
Publikacja wersji
Publishing
Konfiguracja wersji
Version configuration
// wpkit/build.gradle
group = 'rip.nerd.wpkit'
def baseVersion = '1.1.0'
def isDevBuild = true // → dodaje sufiks -SNAPSHOT / adds -SNAPSHOT suffix
Komendy
Commands
# Zbuduj AAR / Build AAR
./gradlew clean :wpkit:assembleDebug
# Opublikuj do GitHub Packages / Publish to GitHub Packages
./gradlew :wpkit:publishAarPublicationToGitHubPackagesRepository
# Opublikuj lokalnie / Publish to local Maven (~/.m2)
./gradlew :wpkit:publishAarPublicationToMavenLocal
gradle.properties lub local.properties ustaw gpr.user i gpr.token aby uwierzytelniać publikację do GitHub Packages.
💡 Set gpr.user and gpr.token in gradle.properties or local.properties to authenticate publishing to GitHub Packages.