
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
A React Redux toolset for the WordPress API
Made with ❤ at @outlandish
v4 introduces breaking changes. Please read the CHANGELOG for more details.
:sparkles: We welcome contributors!
:vertical_traffic_light: Issues are triaged using a traffic light system:
small - quick tasks, great for beginner contributors
medium - tasks with increased complexity, may take some time to implement
large - big tasks that touch many parts of the library, will require commitment
Get started contributing here.
Get data from WordPress and into components with ease...
// e.g. Get a post by its slug
@connectWpPost('post', 'spongebob-squarepants')
export default class extends React.Component () {
render () {
const { post: spongebob } = this.props.kasia
if (!spongebob) {
return <p>{'Who lives in a pineapple under the sea?'}</p>
}
return <h1>{spongebob.title.rendered}!</h1>
//=> Spongebob Squarepants!
}
}
node-wpapi in order to facilitate complex queries.store.wordpress, e.g. store.wordpress.pages.wp-api-menus.Kasia suits applications that are built using these technologies:
node-wpapinpm install kasia --save
yarn add kasia
// ES2015
import kasia from 'kasia'
// CommonJS
var kasia = require('kasia')
Configure Kasia in three steps:
Initialise Kasia with an instance of node-wpapi.
Spread the Kasia reducer when creating the redux root reducer.
Run the Kasia sagas after creating the redux-saga middleware.
A slimline example...
import { combineReducers, createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import kasia from 'kasia'
import wpapi from 'wpapi'
const WP = new wpapi({ endpoint: 'http://wordpress/wp-json' })
const { kasiaReducer, kasiaSagas } = kasia({ WP })
const rootSaga = function * () {
yield [...kasiaSagas]
}
const rootReducer = combineReducers({
...kasiaReducer
})
const sagaMiddleware = createSagaMiddleware()
export default function configureStore (initialState) {
const store = createStore(
rootReducer,
initialState,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga)
return store
}
kasia(options) : ObjectConfigure Kasia.
Returns an object containing the Kasia reducer and sagas.
const { kasiaReducer, kasiaSagas } = kasia({
WP: new wpapi({ endpoint: 'http://wordpress/wp-json' })
})
The options object accepts:
wpapi {wpapi}
An instance of node-wpapi.
keyEntitiesBy {String} (optional, default='id')
Property of entities that is used to key them in the store.
One of: 'slug', 'id'.
debug {Boolean} (optional, default=false)
Log debug information to the console.
contentTypes {Array} (optional)
Array of custom content type definitions.
// Example custom content type definition
contentTypes: [{
name: 'book',
plural: 'books',
slug: 'books',
route, // optional, default="/{plural}/(?P<id>)"
namespace, // optional, default="wp/v2"
methodName // optional, default={plural}
}]
plugins {Array} (optional)
Array of Kasia plugins.
import kasiaWpApiMenusPlugin from 'kasia-plugin-wp-api-menus'
// Example passing in plugin
plugins: [
[kasiaWpApiMenusPlugin, { route: 'menus' }], // with configuration
kasiaWpApiMenusPlugin, // without configuration
]
Things to keep in mind:
connectWpPost a change
in props will trigger Kasia to try and find entity data for the new identifier in the store. If it is found, no request
is made.connectWpQuery, we suggest that you always call the embed method on the
query chain, otherwise embedded content data will be omitted from the response.this.props.kasia.query.paging.@connectWpPost(contentType, identifier) : ComponentConnect a component to a single entity in WordPress, e.g. Post, Page, or custom content type.
propsReturns a connected component.
Example, using identifier derived from route parameter on props:
import React, { Component } from 'react'
import { Route } from 'react-router'
import { connectWpPost } from 'kasia/connect'
import { Page } from 'kasia/types'
@connectWpPost(Page, (props) => props.params.slug)
export default class Page extends Component {
render () {
const { query, page } = this.props.kasia
if (!query.complete) {
return <span>Loading...</span>
}
return <h1>{page.title}</h1>
}
}
// Without decorator support
export default connectWpPost(Page, (props) => props.params.slug)(Post)
@connectWpQuery(queryFn[, shouldUpdate]) : ComponentConnect a component to the result of an arbitrary WP-API query. Query is always made with ?embed query parameter.
wpapi, props, state and should return a WP-API querycomponentWillReceiveProps with args thisProps, nextProps, stateReturns a connected component.
The component will request new data via queryFn if shouldUpdate returns true.
Entities returned from the query will be placed on this.props.kasia.entities under the same
normalised structure as described in The Shape of Things.
Example, fetching the most recent "News" entities:
import React, { Component } from 'react'
import { Route } from 'react-router'
import { connectWpPost } from 'kasia/connect'
// Note the invocation of `embed` in the query chain
@connectWpQuery((wpapi, props) => {
return wpapi.news().month(props.month).embed().get()
})
export default class RecentNews extends Component {
render () {
const {
query,
data: { news }
} = this.props.kasia
if (!query.complete) {
return <span>Loading...</span>
}
return (
<div>
<h1>Recent News Headlines</h1>
{Object.keys(news).map((key) =>
<h2>{news[key].title}</h2>)}
</div>
)
}
}
// Without decorator support
export default connectWpQuery((wpapi) => {
return wpapi.news().embed().get()
})(Post)
kasiaThe Kasia configurator and preload utilities.
import kasia, { preload, preloadQuery } from 'kasia'
kasia/connectThe connect decorators.
import { connectWpPost, connectWpQuery } from 'kasia/connect'
kasia/typesThe built-in WordPress content types that can be passed to connectWpPost to define what content type
a request should be made for.
import {
Category, Comment, Media, Page,
Post, PostStatus, PostType,
PostRevision, Tag, Taxonomy, User
} from 'kasia/types'
See Universal Application Utilities for more details.
Kasia exposes a simple API for third-party plugins.
A plugin should:
be a function that accepts these arguments:
wpapireturn an object containing reducers (Object) and sagas (Array).
use the 'kasia/' action type prefix.
// Example definition returned by a plugin
{
reducer: {
'kasia/SET_DATA': function setDataReducer () {}
'kasia/REMOVE_DATA': function removeDataReducer () {}
},
sagas: [function * fetchDataSaga () {}]
}
A plugin can hook into Kasia's native action types, available at kasia/lib/constants/ActionTypes.
All reducers for an action type are merged into a single function that calls each reducer in succession
with the state returned by the previous reducer. This means the order of plugins that touch the same
action type is important.
Please create a pull request to get your own added to the list.
Important...
kasia.rewind()runSagas() from the utilities then this is done for you.runSagas(store, sagas) : PromiseRun a bunch of sagas against the store and wait on their completion.
runSaga methodReturns a Promise resolving on completion of all the sagas.
preload(components[, renderProps][, state]) : GeneratorCreate a saga operation that will preload all data for any Kasia components in components.
Returns a saga operation.
preloadQuery(queryFn[, renderProps][, state]) : GeneratorCreate a saga operation that will preload data for an arbitrary query against the WP API.
node-wpapi queryReturns a saga operation.
<KasiaConnectedComponent>.preload(renderProps[, state]) : Array<Array>Connected components expose a static method preload that produces an array of saga operations
to facilitate the request for entity data on the server.
null)Returns an array of saga operations.
A saga operation is an array of the form:
[ sagaGeneratorFn, action ]
Where:
sagaGenerator Function that must be called with the action.
action action Object containing information for the saga to fetch data.
A somewhat contrived example using the available preloader methods.
import { match } from 'react-router'
import { runSagas, preload, preloadQuery } from 'kasia'
import routes from './routes'
import store from './store'
import renderToString from './render'
import getAllCategories from './queries/categories'
export default function renderPage (res, location) {
return match({ routes, location }, (error, redirect, renderProps) => {
if (error) return res.sendStatus(500)
if (redirect) return res.redirect(302, redirect.pathname + redirect.search)
// We are using `runSagas` which rewinds for us, but if we weren't then
// we would call `kasia.rewind()` here instead:
//
// kasia.rewind()
// Each preloader accepts the state that may/may not have been modified by
// the saga before it, so the order might be important depending on your use-case!
const preloaders = [
() => preload(renderProps.components, renderProps),
(state) => preloadQuery(getAllCategories, renderProps, state)
]
return runSagas(store, preloaders)
.then(() => renderToString(renderProps.components, renderProps, store.getState()))
.then((document) => res.send(document))
})
}
All pull requests and issues welcome!
standard code style.If you're not sure how to contribute, check out Kent C. Dodds' great video tutorials on egghead.io!
kasia was created by Outlandish and is released under the MIT license.
FAQs
A React Redux toolset for the WordPress API
We found that kasia demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.