├── connect.js ├── types.js ├── assets └── tophat.png ├── .gitignore ├── lerna.json ├── packages ├── kasia-plugin-wp-api-menus │ ├── .babelrc │ ├── .gitignore │ ├── .npmignore │ ├── src │ │ ├── constants │ │ │ └── ActionTypes.js │ │ ├── actions.js │ │ └── index.js │ ├── CHANGELOG.md │ ├── .editorconfig │ ├── LICENSE │ ├── package.json │ └── README.md ├── kasia-plugin-wp-api-all-terms │ ├── .babelrc │ ├── .gitignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── .editorconfig │ ├── LICENSE │ ├── src │ │ └── index.js │ ├── package.json │ └── README.md └── kasia-plugin-wp-api-response-modify │ ├── .gitignore │ ├── CHANGELOG.md │ ├── .editorconfig │ ├── index.js │ ├── package.json │ ├── LICENSE │ └── README.md ├── .npmignore ├── test ├── __mocks__ │ ├── states │ │ ├── initial.js │ │ ├── multipleBooks.js │ │ └── multipleEntities.js │ ├── WP.js │ └── components │ │ ├── BadContentType.js │ │ ├── ExplicitIdentifier.js │ │ ├── CustomContentType.js │ │ ├── CustomQuery.js │ │ ├── BuiltInContentType.js │ │ └── CustomQueryNestedPreload.js ├── __fixtures__ │ └── wp-api-responses │ │ ├── status.js │ │ ├── type.js │ │ ├── taxonomy.js │ │ ├── tag.js │ │ ├── category.js │ │ ├── user.js │ │ ├── comment.js │ │ ├── book.js │ │ ├── media.js │ │ ├── page.js │ │ └── post.js ├── util │ ├── queryBuilder.js │ ├── pickEntityIds.js │ ├── contentTypesManager.js │ ├── findEntities.js │ ├── normalise.js │ └── preload.js ├── index.js ├── redux │ ├── reducer.js │ ├── sagas.js │ └── reducer-journey.js ├── connect │ ├── preload.js │ ├── connectWpQuery.js │ └── connectWpPost.js ├── plugin.js └── universal-journey.js ├── src ├── util │ ├── debug.js │ ├── queryCounter.js │ ├── runSagas.js │ ├── pickEntityIds.js │ ├── findEntities.js │ ├── normalise.js │ ├── queryBuilder.js │ ├── preload.js │ ├── contentTypesManager.js │ └── schemasManager.js ├── wpapi.js ├── redux │ ├── actions.js │ ├── sagas.js │ └── reducer.js ├── constants.js ├── index.js ├── invariants.js └── connect.js ├── .babelrc ├── .travis.yml ├── .editorconfig ├── LICENSE ├── package.json ├── CHANGELOG.md └── README.md /connect.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/connect') 2 | -------------------------------------------------------------------------------- /types.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/constants').ContentTypes 2 | -------------------------------------------------------------------------------- /assets/tophat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/outlandishideas/kasia/HEAD/assets/tophat.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | coverage/ 5 | lib/ 6 | dist/ 7 | 8 | *.log 9 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.0.0-beta.31", 3 | "packages": [ 4 | "packages/*" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-all-terms/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | lib/ 5 | *.log 6 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-response-modify/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | *.log 5 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-all-terms/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | lib/ 5 | *.log 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | coverage/ 5 | *.log 6 | 7 | !lib/ 8 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-all-terms/.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | coverage/ 5 | *.log 6 | 7 | !lib/ 8 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-all-terms/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Kasia Plugin WP API All Terms 2 | 3 | - __v0.0.1__ - _09/09/16_ 4 | 5 | - Release! :tophat: 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | coverage/ 5 | packages/ 6 | assets/ 7 | test/ 8 | src/ 9 | dist/ 10 | *.log 11 | 12 | !lib/ 13 | -------------------------------------------------------------------------------- /test/__mocks__/states/initial.js: -------------------------------------------------------------------------------- 1 | export default (keyEntitiesBy = 'id') => ({ 2 | wordpress: { 3 | keyEntitiesBy, 4 | queries: {}, 5 | entities: {} 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /test/__mocks__/WP.js: -------------------------------------------------------------------------------- 1 | /* global jest:false */ 2 | 3 | import { setWP } from '../../src/wpapi' 4 | 5 | export const wpapi = { 6 | registerRoute: jest.fn() 7 | } 8 | 9 | export default setWP(wpapi) 10 | -------------------------------------------------------------------------------- /src/util/debug.js: -------------------------------------------------------------------------------- 1 | let on = false 2 | 3 | export default function debug (...args) { 4 | if (on) console.log('[kasia debug]', ...args) 5 | } 6 | 7 | export function toggleDebug (bool) { 8 | on = bool 9 | } 10 | -------------------------------------------------------------------------------- /src/wpapi.js: -------------------------------------------------------------------------------- 1 | let WP 2 | 3 | export default function getWP () { 4 | if (!WP) throw new Error('WP not set') 5 | return WP 6 | } 7 | 8 | export function setWP (_WP) { 9 | WP = _WP 10 | return WP 11 | } 12 | -------------------------------------------------------------------------------- /src/util/queryCounter.js: -------------------------------------------------------------------------------- 1 | let queryId = -1 2 | 3 | export default { 4 | current () { 5 | return queryId 6 | }, 7 | reset () { 8 | queryId = -1 9 | }, 10 | next () { 11 | queryId += 1 12 | return queryId 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/__fixtures__/wp-api-responses/status.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'name': 'Published', 3 | 'public': true, 4 | 'queryable': true, 5 | 'slug': 'publish', 6 | '_links': { 7 | 'archives': [{ 8 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts' 9 | }] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-0", 5 | "react" 6 | ], 7 | "plugins": [ 8 | "transform-decorators-legacy", 9 | "transform-proto-to-assign", 10 | "transform-class-properties", 11 | ["transform-es2015-classes", {"loose": true}] 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | # https://github.com/travis-ci/travis-ci/issues/4653#issuecomment-194051953 5 | before_install: "if [[ `npm -v` != 4* ]]; then npm i -g npm@4; fi" 6 | script: "npm run test:coverage" 7 | after_script: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" 8 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/src/constants/ActionTypes.js: -------------------------------------------------------------------------------- 1 | export default { 2 | REQUEST_MENUS: 'kasia/menus/REQUEST_MENUS', 3 | REQUEST_MENU: 'kasia/menus/REQUEST_MENU', 4 | REQUEST_LOCATIONS: 'kasia/menus/REQUEST_LOCATIONS', 5 | REQUEST_LOCATION: 'kasia/menus/REQUEST_LOCATION', 6 | RECEIVE_DATA: 'kasia/menus/RECEIVE_DATA' 7 | } 8 | -------------------------------------------------------------------------------- /test/__mocks__/components/BadContentType.js: -------------------------------------------------------------------------------- 1 | /* global jest:false */ 2 | 3 | jest.disableAutomock() 4 | 5 | import React, { Component } from 'react' 6 | 7 | import { connectWpPost } from '../../../src/connect' 8 | 9 | @connectWpPost(' :-( ', (props) => props.params.id) 10 | export default class BadContentType extends Component { 11 | render () { 12 | return
13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/src/actions.js: -------------------------------------------------------------------------------- 1 | import ActionTypes from './constants/ActionTypes' 2 | 3 | export const fetchMenus = () => 4 | ({ type: ActionTypes.REQUEST_MENUS }) 5 | 6 | export const fetchMenu = (id) => 7 | ({ type: ActionTypes.REQUEST_MENU, id }) 8 | 9 | export const fetchThemeLocations = () => 10 | ({ type: ActionTypes.REQUEST_LOCATIONS }) 11 | 12 | export const fetchThemeLocation = (id) => 13 | ({ type: ActionTypes.REQUEST_LOCATION, id }) 14 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Kasia Plugin WP API Menus 2 | 3 | - __v3.0.0__ - _05/08/16_ 4 | 5 | - [BREAKING] Updated for Kasia v3. 6 | - `makePreloader` now returns a function that can be passed straight to `runSaga` instead 7 | of an array that describes the saga operation. 8 | 9 | --- 10 | 11 | - __v2.0.0__ - _05/08/16_ 12 | 13 | - [BREAKING] Updated for Kasia v2. 14 | 15 | --- 16 | 17 | - __v1.0.0__ - _03/08/16_ 18 | 19 | - Release! :tophat: 20 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-response-modify/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Kasia Plugin WP API Menus 2 | 3 | - __v3.0.0__ - _05/08/16_ 4 | 5 | - [BREAKING] Updated for Kasia v3. 6 | - `makePreloader` now returns a function that can be passed straight to `runSaga` instead 7 | of an array that describes the saga operation. 8 | 9 | --- 10 | 11 | - __v2.0.0__ - _05/08/16_ 12 | 13 | - [BREAKING] Updated for Kasia v2. 14 | 15 | --- 16 | 17 | - __v1.0.0__ - _03/08/16_ 18 | 19 | - Release! :tophat: 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = false 18 | 19 | [*.js] 20 | 21 | insert_final_newline = true 22 | -------------------------------------------------------------------------------- /test/__fixtures__/wp-api-responses/type.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'description': '', 3 | 'hierarchical': false, 4 | 'name': 'Posts', 5 | 'slug': 'post', 6 | '_links': { 7 | 'collection': [{ 8 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/types' 9 | }], 10 | 'wp:items': [{ 11 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts' 12 | }], 13 | 'curies': [{ 14 | 'name': 'wp', 15 | 'href': 'https://api.w.org/{rel}', 16 | 'templated': true 17 | }] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-menus/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = false 18 | 19 | [*.js] 20 | 21 | insert_final_newline = true 22 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-all-terms/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = false 18 | 19 | [*.js] 20 | 21 | insert_final_newline = true 22 | -------------------------------------------------------------------------------- /packages/kasia-plugin-wp-api-response-modify/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = false 18 | 19 | [*.js] 20 | 21 | insert_final_newline = true 22 | -------------------------------------------------------------------------------- /test/__fixtures__/wp-api-responses/taxonomy.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'name': 'Categories', 3 | 'slug': 'category', 4 | 'description': '', 5 | 'types': ['post'], 6 | 'hierarchical': true, 7 | '_links': { 8 | 'collection': [{ 9 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/taxonomies' 10 | }], 11 | 'wp:items': [{ 12 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/categories' 13 | }], 14 | 'curies': [{ 15 | 'name': 'wp', 16 | 'href': 'https://api.w.org/{rel}', 17 | 'templated': true 18 | }] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/__mocks__/states/multipleBooks.js: -------------------------------------------------------------------------------- 1 | import merge from 'lodash.merge' 2 | 3 | import bookJson from '../../__fixtures__/wp-api-responses/book' 4 | 5 | export default { 6 | wordpress: { 7 | keyEntitiesBy: 'id', 8 | queries: { 9 | '0': { 10 | id: 0, 11 | complete: true, 12 | OK: true, 13 | entities: [bookJson.id, bookJson.id + 1] 14 | } 15 | }, 16 | entities: { 17 | books: { 18 | [bookJson.id]: bookJson, 19 | [bookJson.id + 1]: merge({}, bookJson, { id: bookJson.id + 1, slug: 'new-slug' }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/__mocks__/states/multipleEntities.js: -------------------------------------------------------------------------------- 1 | import postJson from '../../__fixtures__/wp-api-responses/post' 2 | import bookJson from '../../__fixtures__/wp-api-responses/book' 3 | 4 | const post2 = Object.assign({}, postJson, { 5 | id: postJson.id + 1, 6 | title: { rendered: 'new title' } 7 | }) 8 | 9 | export default { 10 | wordpress: { 11 | keyEntitiesBy: 'id', 12 | queries: {}, 13 | entities: { 14 | posts: { 15 | [postJson.id]: postJson, 16 | [postJson.id + 1]: post2 17 | }, 18 | books: { 19 | [bookJson.id]: bookJson 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/__mocks__/components/ExplicitIdentifier.js: -------------------------------------------------------------------------------- 1 | /* global jest:false */ 2 | 3 | jest.disableAutomock() 4 | 5 | import React, { Component } from 'react' 6 | 7 | import { ContentTypes } from '../../../src/constants' 8 | import { connectWpPost } from '../../../src/connect' 9 | 10 | export const target = class extends Component { 11 | render () { 12 | const { query, post } = this.props.kasia 13 | if (!query.complete || !query.OK) returnMolestiae aliquam eligendi facere officiis quae impedit eos. Sapiente quas non eum aut. Alias quam similique odio in cupiditate. Ut aut aut delectus officia iusto error maxime neque.
\nConsequatur eius ut aut vero culpa. Beatae delectus qui culpa occaecati maiores. Tempora voluptas quo inventore temporibus consectetur vitae. Voluptatem sit expedita et harum dolores. Dolorum magni sequi officiis temporibus.
\nPerferendis dolor sit rem. Omnis repudiandae quia minima animi sequi. Aspernatur recusandae quod ea tempora.
\n' 12 | }, 13 | 'link': 'http://demo.wp-api.org/2015/05/17/voluptates-quis-ut-qui/#comment-16', 14 | 'status': 'approved', 15 | 'type': 'comment', 16 | 'author_avatar_urls': { 17 | '24': 'http://0.gravatar.com/avatar/fe6e007015afc17a401d8ea853a3e05c?s=24&d=mm&r=g', 18 | '48': 'http://0.gravatar.com/avatar/fe6e007015afc17a401d8ea853a3e05c?s=48&d=mm&r=g', 19 | '96': 'http://0.gravatar.com/avatar/fe6e007015afc17a401d8ea853a3e05c?s=96&d=mm&r=g' 20 | }, 21 | '_links': { 22 | 'self': [{ 23 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments/16' 24 | }], 25 | 'collection': [{ 26 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments' 27 | }], 28 | 'up': [{ 29 | 'embeddable': true, 30 | 'post_type': 'post', 31 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts/43' 32 | }] 33 | }, 34 | '_embedded': { 35 | 'up': [{ 36 | 'id': 43, 37 | 'date': '2015-05-17T12:30:17', 38 | 'slug': 'voluptates-quis-ut-qui', 39 | 'type': 'post', 40 | 'link': 'http://demo.wp-api.org/2015/05/17/voluptates-quis-ut-qui/', 41 | 'title': { 42 | 'rendered': 'Voluptates quis ut qui' 43 | }, 44 | 'excerpt': { 45 | 'rendered': 'Omnis quia quam aliquid fugit. Saepe voluptas excepturi ratione corrupti cum. Animi asperiores qui nulla ut mollitia. Et neque eos aut magni et id vel Modi consequatur et qui perferendis. Dolor adipisci quo. Sequi autem illo deserunt excepturi enim ut. Vel dolores aperiam et ullam facilis. Maiores illo quis dolorem iure fugit non Magnam et […]
\n' 46 | }, 47 | 'author': 44, 48 | '_links': { 49 | 'self': [{ 50 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts/43' 51 | }], 52 | 'collection': [{ 53 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts' 54 | }], 55 | 'about': [{ 56 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/types/post' 57 | }], 58 | 'author': [{ 59 | 'embeddable': true, 60 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/44' 61 | }], 62 | 'replies': [{ 63 | 'embeddable': true, 64 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments?post=43' 65 | }], 66 | 'version-history': [{ 67 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts/43/revisions' 68 | }], 69 | 'wp:featuredmedia': [{ 70 | 'embeddable': true, 71 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media/42' 72 | }], 73 | 'wp:attachment': [{ 74 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media?parent=43' 75 | }], 76 | 'wp:term': [{ 77 | 'taxonomy': 'category', 78 | 'embeddable': true, 79 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/categories?post=43' 80 | }, 81 | { 82 | 'taxonomy': 'post_tag', 83 | 'embeddable': true, 84 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/tags?post=43' 85 | }], 86 | 'curies': [{ 87 | 'name': 'wp', 88 | 'href': 'https://api.w.org/{rel}', 89 | 'templated': true 90 | }] 91 | } 92 | }] 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /test/util/normalise.js: -------------------------------------------------------------------------------- 1 | /* global jest:false, expect:false */ 2 | 3 | jest.disableAutomock() 4 | 5 | import '../__mocks__/WP' 6 | import normalise from '../../src/util/normalise' 7 | import contentTypesManager from '../../src/util/contentTypesManager' 8 | import schemasManager from '../../src/util/schemasManager' 9 | import { ContentTypes } from '../../src/constants' 10 | 11 | function setup () { 12 | const testKeyById = true 13 | const testKeyBySlug = true 14 | 15 | contentTypesManager.register({ 16 | name: 'book', 17 | plural: 'books', 18 | slug: 'books' 19 | }) 20 | 21 | return { 22 | [ContentTypes.Category]: { 23 | // The expected entity collections on the store 24 | collections: ['categories'], 25 | // Whether to test normalisation by 'id' attr. 26 | testKeyById, 27 | // Whether to test normalisation by 'slug' attr. 28 | testKeyBySlug 29 | }, 30 | [ContentTypes.Comment]: { 31 | collections: ['comments'], 32 | testKeyById 33 | }, 34 | [ContentTypes.Media]: { 35 | collections: ['media'], 36 | testKeyById 37 | }, 38 | [ContentTypes.Page]: { 39 | collections: ['pages'], 40 | testKeyById, 41 | testKeyBySlug 42 | }, 43 | [ContentTypes.Post]: { 44 | collections: ['posts'], 45 | testKeyById, 46 | testKeyBySlug 47 | }, 48 | [ContentTypes.PostStatus]: { 49 | collections: ['statuses'], 50 | testKeyBySlug 51 | }, 52 | [ContentTypes.PostType]: { 53 | collections: ['types'], 54 | testKeyBySlug 55 | }, 56 | [ContentTypes.Tag]: { 57 | collections: ['tags'], 58 | testKeyById, 59 | testKeyBySlug 60 | }, 61 | [ContentTypes.Taxonomy]: { 62 | collections: ['taxonomies'], 63 | testKeyBySlug 64 | }, 65 | [ContentTypes.User]: { 66 | collections: ['users'], 67 | testKeyById, 68 | testKeyBySlug 69 | }, 70 | book: { 71 | collections: ['books'], 72 | testKeyById, 73 | testKeyBySlug 74 | } 75 | } 76 | } 77 | 78 | function fixtures (contentType) { 79 | const first = require('../__fixtures__/wp-api-responses/' + contentType).default 80 | 81 | // Imitate another entity by modifying identifiers 82 | const second = Object.assign({}, first, { 83 | id: first.id + 1, 84 | slug: first.slug + '1' 85 | }) 86 | 87 | return { 88 | first, 89 | second, 90 | multiple: [first, second] 91 | } 92 | } 93 | 94 | describe('util/normalise', () => { 95 | const tests = setup() 96 | 97 | Object.keys(tests).forEach((contentType) => { 98 | describe('Normalise ' + contentType, () => { 99 | const { plural } = contentTypesManager.get(contentType) 100 | const { first, second, multiple } = fixtures(contentType) 101 | const { collections, testKeyBySlug, testKeyById } = tests[contentType] 102 | 103 | afterEach(() => schemasManager.__flush__()) 104 | 105 | if (testKeyById) { 106 | it(`should normalise single "${contentType}" by id`, () => { 107 | const result = normalise(first, 'id') 108 | const actual = Object.keys(result) 109 | expect(actual).toEqual(collections) 110 | }) 111 | 112 | it(`should normalise multiple "${contentType}" by id`, () => { 113 | const result = normalise(multiple, 'id') 114 | const actual = Object.keys(result[plural]) 115 | const expected = [first.id, second.id].map(String) 116 | expect(actual).toEqual(expected) 117 | }) 118 | } 119 | 120 | if (testKeyBySlug) { 121 | it(`should normalise single "${contentType}" by slug`, () => { 122 | const result = normalise(first, 'slug') 123 | const actual = Object.keys(result) 124 | expect(actual).toEqual(collections) 125 | }) 126 | 127 | it(`should normalise multiple "${contentType}" by slug`, () => { 128 | const result = normalise(multiple, 'slug') 129 | const actual = Object.keys(result[plural]) 130 | const expected = [first.slug, second.slug] 131 | expect(actual).toEqual(expected) 132 | }) 133 | } 134 | }) 135 | }) 136 | }) 137 | -------------------------------------------------------------------------------- /src/redux/reducer.js: -------------------------------------------------------------------------------- 1 | import merge from 'lodash.merge' 2 | import isNode from 'is-node-fn' 3 | 4 | import pickEntityIds from '../util/pickEntityIds' 5 | import normalise from '../util/normalise' 6 | import { ActionTypes } from '../constants' 7 | 8 | export const INITIAL_STATE = { 9 | // WP-API request/response metadata are stored here 10 | queries: {}, 11 | // Entities are normalised and stored here 12 | entities: {} 13 | } 14 | 15 | /** 16 | * Merge all native and plugin reducers such that a single function reduces for a single action type. 17 | * @param {Object} reducers Plugin reducers 18 | * @param {Function} normaliser Function to normalise response data 19 | * @returns {Object} Reducer object 20 | */ 21 | function mergeNativeAndThirdPartyReducers (reducers, normaliser) { 22 | const baseReducer = { 23 | [ActionTypes.AckRequest]: [acknowledgeReducer], 24 | [ActionTypes.RequestComplete]: [completeReducer(normaliser)], 25 | [ActionTypes.RequestFail]: [failReducer] 26 | } 27 | 28 | // Group reducers by their action type 29 | const reducersByActionType = Object.keys(reducers) 30 | .reduce(function groupByActionType (reducer, actionType) { 31 | reducer[actionType] = [].concat( 32 | reducer[actionType] || [], 33 | reducers[actionType] || [] 34 | ) 35 | return reducer 36 | }, baseReducer) 37 | 38 | const reducer = {} 39 | 40 | // Produce a single function for each action type 41 | for (const actionType in reducersByActionType) { 42 | if (reducersByActionType[actionType].length > 1) { 43 | // Call each reducer function in succession, passing the state returned from each to the next 44 | reducer[actionType] = (state, action) => { 45 | return reducersByActionType[actionType].reduce((state, fn) => fn(state, action), state) 46 | } 47 | } else { 48 | // Take the first and only function as the whole reducer 49 | reducer[actionType] = reducersByActionType[actionType][0] 50 | } 51 | } 52 | 53 | return reducer 54 | } 55 | 56 | // ACKNOWLEDGE 57 | // Place record of request o 58 | export function acknowledgeReducer (state, action) { 59 | return merge({}, state, { 60 | queries: { 61 | [action.id]: { 62 | id: action.id, 63 | prepared: isNode(), 64 | complete: false, 65 | OK: null 66 | } 67 | } 68 | }) 69 | } 70 | 71 | // COMPLETE 72 | // Place entity on the store; update query record if for component (has an id) 73 | export function completeReducer (normalise) { 74 | return (state_, action) => { 75 | const state = merge({}, state_) 76 | 77 | state.entities = merge( 78 | state.entities, 79 | normalise(action.data) 80 | ) 81 | 82 | // The action id would be null if the preloadQuery method has initiated 83 | // the completeRequest action as they do not need a query in the store 84 | // (there is no component to pick it up). 85 | if (typeof action.id === 'number') { 86 | state.queries[action.id] = { 87 | id: action.id, 88 | entities: pickEntityIds(action.data), 89 | paging: action.data._paging || {}, 90 | prepared: isNode(), 91 | complete: true, 92 | OK: true 93 | } 94 | } 95 | 96 | return state 97 | } 98 | } 99 | 100 | // FAIL 101 | // Update query record only 102 | export function failReducer (state, action) { 103 | return merge({}, state, { 104 | queries: { 105 | [action.id]: { 106 | id: action.id, 107 | error: action.error, 108 | prepared: isNode(), 109 | complete: true, 110 | OK: false 111 | } 112 | } 113 | }) 114 | } 115 | 116 | /** 117 | * Create the aggregate reducer for an instance of Kasia. 118 | * @param {Object} keyEntitiesBy Entity property used as key in store 119 | * @param {Object} reducers Plugin reducers 120 | * @returns {Object} Kasia reducer 121 | */ 122 | export default function createReducer ({ keyEntitiesBy, reducers }) { 123 | const normaliser = (data) => normalise(data, keyEntitiesBy) 124 | const reducer = mergeNativeAndThirdPartyReducers(reducers, normaliser) 125 | const initialState = Object.assign({}, INITIAL_STATE, { keyEntitiesBy }) 126 | 127 | return { 128 | wordpress: function kasiaReducer (state = initialState, action) { 129 | const [ actionNamespace ] = action.type.split('/') 130 | 131 | if (actionNamespace === 'kasia' && action.type in reducer) { 132 | return reducer[action.type](state, action) 133 | } 134 | 135 | return state 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Kasia Changelog 2 | 3 | - __v4.0.0__ 4 | 5 | - [BREAKING] WP API responses no longer modified by `wp-api-response-modify` by default. Functionality moved into [`kasia-plugin-wp-api-response-modify`](https://github.com/outlandishideas/kasia/tree/master/packages/kasia-plugin-wp-api-response-modify) plugin. 6 | - [BREAKING] Structure of `props.kasia` object changed: `entities` key is now `data`. This is to ready the library for [#30](https://github.com/outlandishideas/kasia/issues/30), where query result may not be a normalised collection of entities. 7 | - [BREAKING] `shouldUpdate` function is mandatory for `connectWpQuery` decorator. 8 | - [BREAKING] `WP` config option is now `wpapi`. 9 | - [BREAKING] Preloaders renamed and fn signatures changes (see docs). `makePostPreloaderSaga` removed, use `preloadQuery` instead. 10 | - Provide stack trace for captured query errors. ([#37](https://github.com/outlandishideas/kasia/issues/37)) 11 | - Plugins can intercept native reducers, e.g. `kasia-plugin-wp-api-response-modify`. ([#40](https://github.com/outlandishideas/kasia/issues/40)) 12 | - `prepublish` scripts not run on `npm install`. ([#28](https://github.com/outlandishideas/kasia/issues/28)) 13 | - Added `debug` config option, if true lib logs useful lifecycle information to the console. 14 | - Big refactor of library to make codebase more maintainable, manageable. 15 | 16 | --- 17 | 18 | - __v3.2.0__ - _23/09/16_ 19 | 20 | - Implemented safer internal query reconciliation logic such that prepared queries 21 | target their components via their `displayName`. 22 | - Added `options` object parameter to connect decorators, where you can specify explicitly the `displayName` 23 | of the component if it is wrapped by other decorators. 24 | - Fix bug where preloader saga creator utilities in `kasia/util` disrupt prepared query reconciliation 25 | by incrementing prepared query count. (They do not have a corresponding component and so should not be 26 | considered "prepared" queries.) 27 | - Fixed query errors not being added to query object (`error: "undefined"`). 28 | - Log warning about erroneous queries. 29 | 30 | - __v3.1.5__ - _22/09/16_ 31 | 32 | - Replace use of redux's `connect` decorator with access to the store via `context`. 33 | - Quick fix for failed queries sneaking through to data reconciliation stage in decorators. 34 | TODO: implement more complete query error-handling solution. 35 | ([#29](https://github.com/outlandishideas/kasia/issues/29)) 36 | 37 | - __v3.1.2__ - _20/09/16_ 38 | 39 | - Pass state as third argument to `connectWpQuery` query function. 40 | 41 | - __v3.1.1__ - _19/09/16_ 42 | 43 | - Fix bug where `wordpress` object removed from props during comparison to determine if 44 | a request for new data should be made in `connectWpQuery`. 45 | 46 | - __v3.1.0__ - _09/09/16_ 47 | 48 | - Additional preloader saga creators for loading WP data into the store when server-side rendering: 49 | `makeQueryPreloaderSaga` and `makePostPreloaderSaga`. 50 | 51 | - __v3.0.0__ - _31/08/16_ 52 | 53 | - [BREAKING] Fix bug in Universal Application solution that prevented components picking 54 | up prepared query data on the client. Also involves change in API that means `ConnectComponent.makePreloader` returns array 55 | immediately instead of a function. ([#24](https://github.com/outlandishideas/kasia/issues/24)) 56 | - Improved test coverage of universal application solution. ([#26](https://github.com/outlandishideas/kasia/issues/26)) 57 | - Additional utility export `kasia/util`, currently only exporting `makePreloaderSaga()` for use with server-side rendering. 58 | - Improved developer feedback. ([#4](https://github.com/outlandishideas/kasia/issues/4), [#24](https://github.com/outlandishideas/kasia/issues/23)) 59 | - Updates to README: better documentation of Universal Application solution. ([#25](https://github.com/outlandishideas/kasia/issues/25)) 60 | - Update to latest version of Jest. 61 | 62 | --- 63 | 64 | - __v2.4.0__ - _10/08/16_ 65 | 66 | - Mixin `node-wpapi`'s available mixins to internal calls to `registerRoute` by default in order 67 | that filtering can be performed on custom content types, e.g. `news.filter(Sapiente tempore magnam molestias dolore. pariatur repellendus tempore. Illum nihil suscipit culpa. tempora facilis porro. Reiciendis inventore at sit ipsam nulla. Optio aut eum nulla harum Itaque et consequatur sint ut sed Eveniet asperiores enim dolor dolor et. Consectetur est eveniet quod voluptatem vel\n
Possimus modi consequuntur sit Ab magnam reprehenderit et est Ducimus quis et fuga Dolorem illum odio magni Porro sunt repellendus harum et. dolorem velit occaecati. non nobis molestias sed accusamus temporibus. praesentium quia autem quam. Ullam saepe dolorem. tenetur ducimus architecto. Adipisci impedit culpa facilis voluptas necessitatibus est. Commodi expedita
\nAspernatur veritatis quo quo vel in. Quod mollitia corporis iusto illo perspiciatis. Odit consequuntur ex omnis repellat voluptatem mollitia distinctio eum. Consequuntur eius ipsa qui qui consequatur. Ab consequatur enim sint voluptas. Aliquid sint ut vitae consequatur. Voluptas magnam voluptatem omnis molestias.
\n\nCulpa nam vero doloremque quis. Sed nam magni consequatur. Laboriosam maxime cupiditate et quis. Iusto omnis ratione doloremque eos animi. Voluptas impedit velit recusandae eius
\nNemo fugit aut quas et impedit. Optio et non in sapiente. Libero eum beatae maxime sed. Nulla cupiditate dolor sit excepturi sunt. Dolorum consectetur eaque consequatur enim. Et adipisci reprehenderit iure ea consequatur illo. Aperiam eum temporibus dolorem deleniti voluptatum. Eos et maxime qui iure ratione. Consequatur eaque sunt deserunt. Dolorem quia et illum dolorem aliquam quo Eos quo quaerat laborum delectus sed. Molestiae aperiam non numquam dicta. nesciunt et labore facere. Est et voluptatem architecto sapiente architecto. Minima consequatur eos rerum ut sit. accusantium et velit.
\nDucimus nostrum quod reprehenderit In asperiores amet ut consequatur Et consequatur distinctio facilis. Recusandae et beatae explicabo modi. Mollitia aut quia nemo impedit voluptatibus eum. Autem velit nam maiores architecto soluta. Animi itaque vel aut. Consectetur voluptatum necessitatibus assumenda autem corporis Magnam sed molestiae ut. Autem aut ipsam est Tenetur eius vel iste velit aut. Magni enim sequi nulla molestias. perferendis quae fugiat nam fugiat modi esse. In nostrum ut eveniet et. Aut voluptates sed assumenda. Voluptates ad ducimus totam et nihil. Dolorum optio ea. Perferendis non harum ipsa aliquid similique
Delectus pariatur sunt omnis sed soluta. Animi ducimus consectetur aperiam et. Temporibus iste qui et itaque dolores. id non tempora fuga deserunt. Perferendis laboriosam ducimus nihil saepe rem. Odit in voluptatum aspernatur. Adipisci dolore aut minima. ratione dolores eaque saepe reiciendis Explicabo eum rerum et id qui voluptatum qui. id dolores saepe fugit modi. Laboriosam libero doloribus molestiae at asperiores ut. Assumenda aut repellendus fuga animi Aut consequatur ea officia enim.
\n\nDucimus consequatur autem occaecati soluta. Molestiae voluptatum et in veniam autem. Minus aut nihil vero illo eum harum. Eveniet maxime recusandae eos. Suscipit dicta iste qui ipsa quibusdam aspernatur est.
Culpa nam vero doloremque quis. Sed nam magni consequatur. Laboriosam maxime cupiditate et quis. Iusto omnis ratione doloremque eos animi. Voluptas impedit velit recusandae eius Incidunt est itaque quo et labore. Maxime quis cum facilis debitis quia et laudantium At sequi et rerum enim Ex consectetur ullam amet Et quae consectetur itaque Mollitia est quis […]
\n' 21 | }, 22 | 'author': 95, 23 | 'featured_media': 11, 24 | 'parent': 0, 25 | 'menu_order': 0, 26 | 'comment_status': 'closed', 27 | 'ping_status': 'open', 28 | 'template': '', 29 | '_links': { 30 | 'self': [{ 31 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/pages/12' 32 | }], 33 | 'collection': [{ 34 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/pages' 35 | }], 36 | 'about': [{ 37 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/types/page' 38 | }], 39 | 'author': [{ 40 | 'embeddable': true, 41 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/95' 42 | }], 43 | 'replies': [{ 44 | 'embeddable': true, 45 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments?post=12' 46 | }], 47 | 'version-history': [{ 48 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/pages/12/revisions' 49 | }], 50 | 'wp:featuredmedia': [{ 51 | 'embeddable': true, 52 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media/11' 53 | }], 54 | 'wp:attachment': [{ 55 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media?parent=12' 56 | }], 57 | 'curies': [{ 58 | 'name': 'wp', 59 | 'href': 'https://api.w.org/{rel}', 60 | 'templated': true 61 | }] 62 | }, 63 | '_embedded': { 64 | 'author': [{ 65 | 'id': 95, 66 | 'name': 'Sonya', 67 | 'url': 'http://Beatty.info/mollitia-qui-sed-est-beatae', 68 | 'description': 'Et ut est aut rerum quis qui magnam. Vero assumenda laudantium qui autem. Saepe reprehenderit consequatur perferendis libero nam consequatur. Eius voluptate atque illum dolorem repellendus. Reprehenderit assumenda est tempore nesciunt ea.\r\n\r\nUt quia magnam sit molestiae quos. Accusamus voluptate non animi nihil esse. Labore porro quod vitae consequuntur reprehenderit saepe.\r\n\r\nMolestiae porro dolorem nihil neque sint. Reiciendis ducimus rerum suscipit labore temporibus nisi nostrum. Natus amet eum eum excepturi tempore nisi fuga. Totam aut facilis sapiente voluptatem alias unde.\r\n\r\nEaque consequatur omnis adipisci voluptatem illo. Quia neque necessitatibus ut quaerat distinctio hic molestias. Ipsum nisi molestiae vitae.\r\n\r\nAperiam sint nobis quia ut qui sint veniam. Nam animi corporis et ratione numquam est perferendis. Et dolore sit quos earum eius soluta nemo iste.\r\n\r\nVeniam incidunt voluptas reiciendis aut culpa natus. Dolor est numquam consequatur commodi.', 69 | 'link': 'http://demo.wp-api.org/author/elmira-luettgen/', 70 | 'slug': 'elmira-luettgen', 71 | 'avatar_urls': { 72 | '24': 'http://0.gravatar.com/avatar/3eb34c383eaebf4c71409ba2a95fc34a?s=24&d=mm&r=g', 73 | '48': 'http://0.gravatar.com/avatar/3eb34c383eaebf4c71409ba2a95fc34a?s=48&d=mm&r=g', 74 | '96': 'http://0.gravatar.com/avatar/3eb34c383eaebf4c71409ba2a95fc34a?s=96&d=mm&r=g' 75 | }, 76 | '_links': { 77 | 'self': [{ 78 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/95' 79 | }], 80 | 'collection': [{ 81 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users' 82 | }] 83 | } 84 | }], 85 | 'wp:featuredmedia': [{ 86 | 'id': 11, 87 | 'date': '2015-06-03T22:18:47', 88 | 'slug': 'qui-et-ipsa-maiores', 89 | 'type': 'attachment', 90 | 'link': 'http://demo.wp-api.org/qui-et-ipsa-maiores/', 91 | 'title': { 92 | 'rendered': 'Qui et ipsa maiores' 93 | }, 94 | 'author': 72, 95 | 'alt_text': '', 96 | 'media_type': 'image', 97 | 'mime_type': 'image/jpeg', 98 | 'media_details': { 99 | 'width': 1080, 100 | 'height': 677, 101 | 'file': '2015/06/e5247ed2-2a86-3a98-8f70-d5786b1318d4.jpg', 102 | 'sizes': { 103 | 'thumbnail': { 104 | 'file': 'e5247ed2-2a86-3a98-8f70-d5786b1318d4-150x150.jpg', 105 | 'width': 150, 106 | 'height': 150, 107 | 'mime_type': 'image/jpeg', 108 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/e5247ed2-2a86-3a98-8f70-d5786b1318d4-150x150.jpg' 109 | }, 110 | 'medium': { 111 | 'file': 'e5247ed2-2a86-3a98-8f70-d5786b1318d4-300x188.jpg', 112 | 'width': 300, 113 | 'height': 188, 114 | 'mime_type': 'image/jpeg', 115 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/e5247ed2-2a86-3a98-8f70-d5786b1318d4-300x188.jpg' 116 | }, 117 | 'large': { 118 | 'file': 'e5247ed2-2a86-3a98-8f70-d5786b1318d4-1024x642.jpg', 119 | 'width': 1024, 120 | 'height': 642, 121 | 'mime_type': 'image/jpeg', 122 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/e5247ed2-2a86-3a98-8f70-d5786b1318d4-1024x642.jpg' 123 | }, 124 | 'full': { 125 | 'file': 'e5247ed2-2a86-3a98-8f70-d5786b1318d4.jpg', 126 | 'width': 1080, 127 | 'height': 677, 128 | 'mime_type': 'image/jpeg', 129 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/e5247ed2-2a86-3a98-8f70-d5786b1318d4.jpg' 130 | } 131 | }, 132 | 'image_meta': { 133 | 'aperture': 0, 134 | 'credit': '', 135 | 'camera': '', 136 | 'caption': '', 137 | 'created_timestamp': 1430426977, 138 | 'copyright': '', 139 | 'focal_length': 0, 140 | 'iso': 0, 141 | 'shutter_speed': 0, 142 | 'title': '', 143 | 'orientation': 0 144 | } 145 | }, 146 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/e5247ed2-2a86-3a98-8f70-d5786b1318d4.jpg', 147 | '_links': { 148 | 'self': [{ 149 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media/11' 150 | }], 151 | 'collection': [{ 152 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media' 153 | }], 154 | 'about': [{ 155 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/types/attachment' 156 | }], 157 | 'author': [{ 158 | 'embeddable': true, 159 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/72' 160 | }], 161 | 'replies': [{ 162 | 'embeddable': true, 163 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments?post=11' 164 | }] 165 | } 166 | }] 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /test/__fixtures__/wp-api-responses/post.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 'id': 16, 3 | 'date': '2015-12-31T14:51:26', 4 | 'date_gmt': '2015-12-31T14:51:26', 5 | 'guid': { 6 | 'rendered': 'http://wp-api-de-elbinsta-n5pu020s13lb-1748419096.eu-west-1.elb.amazonaws.com/?p=16' 7 | }, 8 | 'modified': '2015-12-31T14:51:26', 9 | 'modified_gmt': '2015-12-31T14:51:26', 10 | 'slug': 'architecto-enim-omnis-repellendus', 11 | 'type': 'post', 12 | 'link': 'http://demo.wp-api.org/2015/12/31/architecto-enim-omnis-repellendus/', 13 | 'title': { 14 | 'rendered': 'Architecto enim omnis repellendus' 15 | }, 16 | 'content': { 17 | 'rendered': '\nNobis est voluptatem ipsum sunt veniam. Iusto quia mollitia sed at non. Corrupti quibusdam et doloremque sed. similique sint Ut modi neque nostrum molestiae aut. officiis id dolores numquam. Error voluptate eum quasi cum. Rerum inventore cupiditate magni inventore magnam Magnam omnis necessitatibus veritatis modi. inventore accusamus sit sapiente expedita nam eos.
\nCorporis quasi ut magnam omnis. Accusantium quasi doloremque quia quas quasi modi mollitia consequatur. Eligendi rerum repellendus mollitia iste. Architecto neque eveniet laborum iste suscipit quod aut. Nam vero rerum fugit delectus qui dolores consequatur. Porro molestiae unde voluptatum laudantium. Autem distinctio ducimus enim qui. Fugit possimus eos qui aliquid accusamus magnam. Consequatur iusto non quibusdam sapiente modi deserunt. Velit et dicta iusto est natus. Eligendi ut officiis et quasi. Nihil voluptatum facere dolores quae voluptatem. Sunt sed ex provident et quam. Molestiae aut et eveniet tempore. Voluptas est quia nobis temporibus natus sint. Autem animi et accusamus quidem occaecati dolorem impedit accusantium. Quibusdam quis omnis provident alias voluptatem. Quisquam impedit quos est tenetur animi ipsam. Recusandae aut incidunt ex minima quisquam ea quia. Quod blanditiis nulla qui maxime nemo corrupti. Itaque est voluptate voluptatem voluptates rerum quasi dolor. Autem illo cumque voluptatem pariatur repellendus commodi illum dolorem. Quidem totam ut neque praesentium. Debitis ut est eveniet itaque repellat. In labore et et quia qui aut dolor. Illum rerum magni quia porro quae et fugiat. Esse dolore sint minima possimus sed ut. Ut harum sequi corrupti. Velit distinctio eum ullam corrupti dolorem earum eum. Rerum impedit iure omnis nesciunt. Quisquam voluptatem consequatur quia. Est ab quae cum ut. Nihil quidem iste est reiciendis quisquam ut. Consequatur dolorum consequatur modi. Porro cupiditate nostrum quam recusandae unde. Autem dolorem nemo nesciunt id praesentium exercitationem aut. Eos magni natus sit dolores dolorum animi assumenda aliquid. Id cupiditate nobis officiis totam. Eveniet dolores cum voluptas quam. Ut vel est velit at et aut velit. Quod sed nam in ut sit hic.
Est unde voluptatum illum Est similique maiores omnis facere est molestiae. Sunt ut itaque omnis non. Dolore perspiciatis iste et veniam eius. Ipsum est similique consequatur. Magnam ea ex saepe dolor corrupti. Quia fuga qui ex. beatae placeat non Omnis possimus voluptate ea quia enim. et suscipit magni est illo. Qui totam vitae tenetur quos reprehenderit.
\n' 18 | }, 19 | 'excerpt': { 20 | 'rendered': 'Similique eaque voluptas cum voluptatem. Similique debitis quis sapiente veniam saepe. Architecto qui repellendus autem dolor autem est molestiae Libero ut Libero sunt nihil laboriosam rerum Rem modi Quod minus est nam alias velit Id consequatur doloribus sed et Maiores nulla eveniet Ut voluptates accusamus voluptas ea Quia esse id temporibus et et maiores Voluptatem […]
\n' 21 | }, 22 | 'author': 42, 23 | 'featured_media': 15, 24 | 'comment_status': 'open', 25 | 'ping_status': 'open', 26 | 'sticky': false, 27 | 'format': 'standard', 28 | 'categories': [1], 29 | 'tags': [], 30 | '_links': { 31 | 'self': [{ 32 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts/16' 33 | }], 34 | 'collection': [{ 35 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts' 36 | }], 37 | 'about': [{ 38 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/types/post' 39 | }], 40 | 'author': [{ 41 | 'embeddable': true, 42 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/42' 43 | }], 44 | 'replies': [{ 45 | 'embeddable': true, 46 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments?post=16' 47 | }], 48 | 'version-history': [{ 49 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts/16/revisions' 50 | }], 51 | 'wp:featuredmedia': [{ 52 | 'embeddable': true, 53 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media/15' 54 | }], 55 | 'wp:attachment': [{ 56 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media?parent=16' 57 | }], 58 | 'wp:term': [{ 59 | 'taxonomy': 'category', 60 | 'embeddable': true, 61 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/categories?post=16' 62 | }, 63 | { 64 | 'taxonomy': 'post_tag', 65 | 'embeddable': true, 66 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/tags?post=16' 67 | }], 68 | 'curies': [{ 69 | 'name': 'wp', 70 | 'href': 'https://api.w.org/{rel}', 71 | 'templated': true 72 | }] 73 | }, 74 | '_embedded': { 75 | 'author': [{ 76 | 'id': 42, 77 | 'name': 'Sophia', 78 | 'url': 'http://Little.com/fugit-rem-in-consequuntur-perspiciatis-ex', 79 | 'description': 'Cumque esse consequatur facere minus. In tenetur culpa illo sint labore nostrum quis. Explicabo animi explicabo perferendis nesciunt omnis quo sunt nihil. Quod magnam necessitatibus dicta amet omnis aliquid.\r\n\r\nEt dolor consequuntur necessitatibus sequi incidunt est ratione. Unde sint iusto possimus officiis cum molestiae. Nostrum ad illo pariatur et.\r\n\r\nDoloremque neque doloremque voluptas vel voluptas placeat est. Consectetur qui et accusamus.\r\n\r\nCorrupti qui accusamus voluptatum ab architecto sapiente fugit quis. Ut et sit quod ea voluptates nobis. Enim qui eos magnam at.\r\n\r\nQuia error tempora ullam nulla illo sint. Velit perferendis amet facere quia dignissimos. Rerum nihil pariatur eum velit rerum.\r\n\r\nVelit laudantium voluptate nesciunt et cupiditate asperiores. Voluptatem recusandae numquam et neque unde molestiae voluptate. Rerum et harum occaecati quis occaecati voluptas. Sequi qui dolores cumque nostrum ab nostrum.\r\n\r\nExplicabo cum voluptates odit asperiores ut. Ipsam exercitationem eum nostrum qui dolorum sint nulla. Aut perferendis dolorem ab itaque architecto ad enim.\r\n\r\nMinima aut nobis qui enim beatae. Quis quo modi nemo est quam ea inventore. Odit consequatur vitae perferendis mollitia pariatur voluptas ea sit.\r\n\r\nIn qui saepe ducimus labore. Perferendis ducimus quia corporis perspiciatis. Autem nobis explicabo debitis laboriosam tempora aut.', 80 | 'link': 'http://demo.wp-api.org/author/meaghan-willms/', 81 | 'slug': 'meaghan-willms', 82 | 'avatar_urls': { 83 | '24': 'http://2.gravatar.com/avatar/bf432d6e226ae2f791a59ddd2b3f8462?s=24&d=mm&r=g', 84 | '48': 'http://2.gravatar.com/avatar/bf432d6e226ae2f791a59ddd2b3f8462?s=48&d=mm&r=g', 85 | '96': 'http://2.gravatar.com/avatar/bf432d6e226ae2f791a59ddd2b3f8462?s=96&d=mm&r=g' 86 | }, 87 | '_links': { 88 | 'self': [{ 89 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/42' 90 | }], 91 | 'collection': [{ 92 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users' 93 | }] 94 | } 95 | }], 96 | 'wp:featuredmedia': [{ 97 | 'id': 15, 98 | 'date': '2015-06-03T22:18:52', 99 | 'slug': 'vero-amet-id-commodi-harum', 100 | 'type': 'attachment', 101 | 'link': 'http://demo.wp-api.org/vero-amet-id-commodi-harum/', 102 | 'title': { 103 | 'rendered': 'Vero amet id commodi harum' 104 | }, 105 | 'author': 100, 106 | 'alt_text': '', 107 | 'media_type': 'image', 108 | 'mime_type': 'image/jpeg', 109 | 'media_details': { 110 | 'width': 1080, 111 | 'height': 631, 112 | 'file': '2015/06/0845fa5d-4c5e-3c93-a054-63a976339952.jpg', 113 | 'sizes': { 114 | 'thumbnail': { 115 | 'file': '0845fa5d-4c5e-3c93-a054-63a976339952-150x150.jpg', 116 | 'width': 150, 117 | 'height': 150, 118 | 'mime_type': 'image/jpeg', 119 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/0845fa5d-4c5e-3c93-a054-63a976339952-150x150.jpg' 120 | }, 121 | 'medium': { 122 | 'file': '0845fa5d-4c5e-3c93-a054-63a976339952-300x175.jpg', 123 | 'width': 300, 124 | 'height': 175, 125 | 'mime_type': 'image/jpeg', 126 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/0845fa5d-4c5e-3c93-a054-63a976339952-300x175.jpg' 127 | }, 128 | 'large': { 129 | 'file': '0845fa5d-4c5e-3c93-a054-63a976339952-1024x598.jpg', 130 | 'width': 1024, 131 | 'height': 598, 132 | 'mime_type': 'image/jpeg', 133 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/0845fa5d-4c5e-3c93-a054-63a976339952-1024x598.jpg' 134 | }, 135 | 'full': { 136 | 'file': '0845fa5d-4c5e-3c93-a054-63a976339952.jpg', 137 | 'width': 1080, 138 | 'height': 631, 139 | 'mime_type': 'image/jpeg', 140 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/0845fa5d-4c5e-3c93-a054-63a976339952.jpg' 141 | } 142 | }, 143 | 'image_meta': { 144 | 'aperture': 0, 145 | 'credit': 'JOKINROM', 146 | 'camera': '', 147 | 'caption': '', 148 | 'created_timestamp': 1430341682, 149 | 'copyright': '', 150 | 'focal_length': 0, 151 | 'iso': 0, 152 | 'shutter_speed': 0, 153 | 'title': '', 154 | 'orientation': 0 155 | } 156 | }, 157 | 'source_url': 'http://demo.wp-api.org/content/uploads/2015/06/0845fa5d-4c5e-3c93-a054-63a976339952.jpg', 158 | '_links': { 159 | 'self': [{ 160 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media/15' 161 | }], 162 | 'collection': [{ 163 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/media' 164 | }], 165 | 'about': [{ 166 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/types/attachment' 167 | }], 168 | 'author': [{ 169 | 'embeddable': true, 170 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/users/100' 171 | }], 172 | 'replies': [{ 173 | 'embeddable': true, 174 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/comments?post=15' 175 | }] 176 | } 177 | }], 178 | 'wp:term': [[{ 179 | 'id': 1, 180 | 'link': 'http://demo.wp-api.org/category/uncategorized/', 181 | 'name': 'Uncategorized', 182 | 'slug': 'uncategorized', 183 | 'taxonomy': 'category', 184 | '_links': { 185 | 'self': [{ 186 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/categories/1' 187 | }], 188 | 'collection': [{ 189 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/categories' 190 | }], 191 | 'about': [{ 192 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/taxonomies/category' 193 | }], 194 | 'wp:post_type': [{ 195 | 'href': 'http://demo.wp-api.org/wp-json/wp/v2/posts?categories=1' 196 | }], 197 | 'curies': [{ 198 | 'name': 'wp', 199 | 'href': 'https://api.w.org/{rel}', 200 | 'templated': true 201 | }] 202 | } 203 | }], 204 | []] 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
A React Redux toolset for the WordPress API
8 | 9 |Made with ❤ at @outlandish
10 | 11 | 17 | 18 | 21 | 22 |{'Who lives in a pineapple under the sea?'}
47 | } 48 | 49 | return