├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── push-wp-gatsby-gutenberg.yml ├── .gitignore ├── .prettierrc.js ├── .vscode └── launch.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── docs ├── .gitignore ├── .prettierignore ├── .prettierrc ├── README.md ├── content │ ├── api │ │ └── api.mdx │ ├── contributing │ │ └── contributing.mdx │ ├── example │ │ └── example.mdx │ ├── features │ │ ├── blocks.mdx │ │ └── previews.mdx │ ├── images │ │ ├── author.png │ │ ├── block-preview.gif │ │ ├── gatsby-icon.png │ │ └── page-preview.gif │ ├── index.mdx │ ├── installation │ │ ├── images │ │ │ └── quickstart │ │ │ │ ├── 01-post.png │ │ │ │ ├── 02-Blocks.png │ │ │ │ ├── 03-Unknown.gif │ │ │ │ ├── 03-Unknown.mov │ │ │ │ ├── 04-Paragraph.png │ │ │ │ ├── 05-Layout.gif │ │ │ │ └── 05-Layout.mov │ │ ├── installation.mdx │ │ ├── packages.mdx │ │ └── quickstart.mdx │ └── overview │ │ ├── sourcing.mdx │ │ └── theme.mdx ├── gatsby-config.js ├── gatsby-node.js ├── package.json ├── src │ ├── components │ │ ├── style.css │ │ └── universal-link.js │ ├── gatsby-theme-apollo-core │ │ └── components │ │ │ └── logo.js │ ├── gatsby-theme-apollo-docs │ │ ├── assets │ │ │ └── social-bg.jpg │ │ └── components │ │ │ ├── custom-seo.js │ │ │ ├── header-button.js │ │ │ ├── page-layout.js │ │ │ └── social-card.js │ └── images │ │ └── gatsby-icon.png └── yarn.lock ├── examples └── gatsby-wordpress-gutenberg-default-example │ ├── .gitignore │ ├── README.md │ ├── backend │ ├── .gitignore │ ├── docker-compose.xdebug.yml │ ├── docker-compose.yml │ ├── docker-entrypoint-initdb.d │ │ └── 01-example.sql │ └── wordpress │ │ ├── composer.json │ │ └── composer.lock │ └── frontend │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── LICENSE │ ├── README.md │ ├── gatsby-browser.js │ ├── gatsby-config.js │ ├── gatsby-node.js │ ├── gatsby-ssr.js │ ├── package.json │ ├── src │ ├── components │ │ ├── block.js │ │ ├── header.js │ │ ├── image.js │ │ ├── layout.css │ │ ├── layout.js │ │ └── seo.js │ ├── gatsby-theme-wordpress-gutenberg │ │ └── components │ │ │ ├── blocks │ │ │ └── core │ │ │ │ ├── column.js │ │ │ │ ├── columns.js │ │ │ │ └── paragraph.js │ │ │ └── unknown-block.js │ ├── images │ │ ├── gatsby-astronaut.png │ │ └── gatsby-icon.png │ ├── pages │ │ ├── 404.js │ │ ├── index.js │ │ └── using-typescript.tsx │ └── templates │ │ └── blog-post.js │ └── yarn.lock ├── lerna.json ├── netlify.toml ├── package.json ├── packages └── gatsby-theme-wordpress-gutenberg │ ├── README.md │ ├── gatsby-config.js │ ├── gatsby-node.js │ ├── index.js │ ├── package.json │ └── src │ └── components │ ├── blocks │ └── core │ │ └── block.js │ ├── previews │ └── block-preview.js │ └── unknown-block.js ├── plugins └── wp-gatsby-gutenberg │ ├── .eslintrc.js │ ├── .prettierrc.js │ ├── build │ ├── 0.js │ ├── 0.js.map │ ├── index.asset.php │ ├── index.js │ └── index.js.map │ ├── composer.json │ ├── package-lock.json │ ├── package.json │ ├── phpcs.xml.dist │ ├── plugin.php │ ├── src │ ├── Admin │ │ ├── Editor.php │ │ └── Settings.php │ ├── Preview │ │ ├── Preview.php │ │ ├── gatsby-block-preview.js │ │ ├── icon.js │ │ └── preview.js │ └── index.js │ └── vendor │ ├── autoload.php │ └── composer │ ├── ClassLoader.php │ ├── LICENSE │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_real.php │ └── autoload_static.php └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | max_line_length = 120 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.min.js 2 | **/*.build.js 3 | **/node_modules/** 4 | **/vendor/** 5 | build 6 | coverage 7 | cypress 8 | node_modules 9 | vendor -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const TSEslint = require("@typescript-eslint/eslint-plugin") 2 | 3 | module.exports = { 4 | parser: "babel-eslint", 5 | extends: [ 6 | "google", 7 | "eslint:recommended", 8 | "plugin:flowtype/recommended", 9 | "plugin:react/recommended", 10 | "prettier", 11 | "prettier/flowtype", 12 | "prettier/react" 13 | ], 14 | plugins: ["flowtype", "prettier", "react", "filenames"], 15 | parserOptions: { 16 | ecmaVersion: 2016, 17 | sourceType: "module", 18 | ecmaFeatures: { 19 | jsx: true 20 | } 21 | }, 22 | env: { 23 | browser: true, 24 | es6: true, 25 | node: true, 26 | jest: true 27 | }, 28 | globals: { 29 | before: true, 30 | after: true, 31 | spyOn: true, 32 | __PATH_PREFIX__: true, 33 | __BASE_PATH__: true, 34 | __ASSET_PREFIX__: true 35 | }, 36 | rules: { 37 | "arrow-body-style": ["error", "as-needed", { requireReturnForObjectLiteral: true }], 38 | "no-unused-expressions": [ 39 | "error", 40 | { 41 | allowTaggedTemplates: true 42 | } 43 | ], 44 | "consistent-return": ["error"], 45 | "filenames/match-regex": ["error", "^[a-z-\\d\\.]+$", true], 46 | "no-console": "off", 47 | "no-inner-declarations": "off", 48 | "prettier/prettier": "error", 49 | quotes: ["error", "backtick"], 50 | "react/display-name": "off", 51 | "react/jsx-key": "warn", 52 | "react/no-unescaped-entities": "off", 53 | "react/prop-types": "off", 54 | "require-jsdoc": "off", 55 | "valid-jsdoc": "off" 56 | }, 57 | overrides: [ 58 | { 59 | files: ["packages/**/gatsby-browser.js", "packages/gatsby/cache-dir/**/*"], 60 | env: { 61 | browser: true 62 | }, 63 | globals: { 64 | ___loader: false, 65 | ___emitter: false 66 | } 67 | }, 68 | { 69 | files: ["**/cypress/integration/**/*", "**/cypress/support/**/*"], 70 | globals: { 71 | cy: false, 72 | Cypress: false 73 | } 74 | }, 75 | { 76 | files: ["www/**/*"], 77 | rules: { 78 | // We need to import React to use the Fragment shorthand (`<>`). 79 | // When we use theme-ui's JSX pragma, it lists React as an unused var 80 | // even though it's still needed. 81 | "no-unused-vars": ["error", { varsIgnorePattern: "React" }] 82 | } 83 | }, 84 | { 85 | files: ["*.ts", "*.tsx"], 86 | parser: "@typescript-eslint/parser", 87 | plugins: ["@typescript-eslint/eslint-plugin"], 88 | rules: { 89 | ...TSEslint.configs.recommended.rules, 90 | // We should absolutely avoid using ts-ignore, but it's not always possible. 91 | // particular when a dependencies types are incorrect. 92 | "@typescript-eslint/ban-ts-ignore": "warn", 93 | // This rule is great. It helps us not throw on types for areas that are 94 | // easily inferrable. However we have a desire to have all function inputs 95 | // and outputs declaratively typed. So this let's us ignore the parameters 96 | // inferrable lint. 97 | "@typescript-eslint/no-inferrable-types": ["error", { ignoreParameters: true }], 98 | // This rule tries to ensure we use camelCase for all variables, properties 99 | // functions, etc. However, it is not always possible to ensure properties 100 | // are camelCase. Specifically we have `node.__gatsby_resolve` which breaks 101 | // this rule. This allows properties to be whatever they need to be. 102 | "@typescript-eslint/camelcase": ["error", { properties: "never" }], 103 | // This rule tries to prevent using `require()`. However in node code, 104 | // there are times where this makes sense. And it specifically is causing 105 | // problems in our tests where we often want this functionality for module 106 | // mocking. At this point it's easier to have it off and just encouarge 107 | // using top-level imports via code reviews. 108 | "@typescript-eslint/no-var-requires": "off", 109 | // This rule ensures that typescript types do not have semicolons 110 | // at the end of their lines, since our prettier setup is to have no semicolons 111 | // e.g., 112 | // interface Foo { 113 | // - baz: string; 114 | // + baz: string 115 | // } 116 | "@typescript-eslint/member-delimiter-style": [ 117 | "error", 118 | { 119 | multiline: { 120 | delimiter: "none" 121 | } 122 | } 123 | ], 124 | // This ensures all interfaces are named with an I as a prefix 125 | // e.g., 126 | // interface IFoo {} 127 | "@typescript-eslint/interface-name-prefix": ["error", { prefixWithI: "always" }], 128 | "@typescript-eslint/no-empty-function": "off", 129 | // This ensures that we always type the return type of functions 130 | // a high level focus of our TS setup is typing fn inputs and outputs. 131 | "@typescript-eslint/explicit-function-return-type": "error", 132 | // This forces us to use interfaces over types aliases for object defintions. 133 | // Type is still useful for opaque types 134 | // e.g., 135 | // type UUID = string 136 | "@typescript-eslint/consistent-type-definitions": ["error", "interface"], 137 | "@typescript-eslint/no-use-before-define": ["error", { functions: false }], 138 | // Allows us to write unions like `type Foo = "baz" | "bar"` 139 | // otherwise eslint will want to switch the strings to backticks, 140 | // which then crashes the ts compiler 141 | quotes: "off", 142 | "@typescript-eslint/quotes": [ 143 | 2, 144 | "backtick", 145 | { 146 | avoidEscape: true 147 | } 148 | ], 149 | // bump to @typescript-eslint/parser started showing Flow related errors in ts(x) files 150 | // so disabling them in .ts(x) files 151 | "flowtype/no-types-missing-file-annotation": "off" 152 | } 153 | } 154 | ], 155 | settings: { 156 | react: { 157 | version: "16.4.2" 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /.github/workflows/push-wp-gatsby-gutenberg.yml: -------------------------------------------------------------------------------- 1 | name: Push to wp-gatsby-gutenberg 2 | on: 3 | push: 4 | branches: 5 | - master # Push events on master branch 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@master 11 | - name: publish:wp-gatsby-gutenberg 12 | uses: s0/git-publish-subdir-action@master 13 | env: 14 | REPO: git@github.com:GatsbyWPGutenberg/wp-gatsby-gutenberg.git 15 | BRANCH: master 16 | FOLDER: plugins/wp-gatsby-gutenberg 17 | SSH_PRIVATE_KEY: ${{ secrets.WP_GATSBY_GUTENBERG_PRIVATE_KEY }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | .idea 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (http://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # Typescript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # dotenv environment variable files 57 | .env* 58 | 59 | # Mac files 60 | .DS_Store 61 | 62 | # Yarn 63 | yarn-error.log 64 | .pnp/ 65 | .pnp.js 66 | # Yarn Integrity file 67 | .yarn-integrity 68 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: "avoid", 3 | semi: false 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Gatsby build", 11 | "program": "${workspaceFolder}/node_modules/gatsby/dist/bin/gatsby", 12 | "args": ["build"], 13 | "cwd": "${workspaceFolder}/examples/gatsby-wordpress-gutenberg-default-example/frontend", 14 | "runtimeArgs": ["--nolazy"], 15 | "sourceMaps": false, 16 | "outputCapture": "std" 17 | }, 18 | 19 | { 20 | "name": "Listen for Default Example XDebug", 21 | "type": "php", 22 | "request": "launch", 23 | "port": 9000, 24 | "pathMappings": { 25 | "/var/www/html": "${workspaceRoot}/examples/gatsby-wordpress-gutenberg-default-example/backend/wordpress", 26 | "/plugins": "${workspaceRoot}/plugins" 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@wpgraphql.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 pristas-peter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GatsbyWPGutenberg 2 | 3 | This is a monorepo for the GatsbyWPGutenberg framework 4 | 5 | - Usage Docs 6 | - Join our community through WpGraphQL Slack 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env* 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /docs/.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /docs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | Gatsby 5 | 6 |

7 |

8 | Gatsby's default starter 9 |

10 | 11 | Kick off your project with this default boilerplate. This starter ships with the main Gatsby configuration files you might need to get up and running blazing fast with the blazing fast app generator for React. 12 | 13 | _Have another more specific idea? You may want to check out our vibrant collection of [official and community-created starters](https://www.gatsbyjs.org/docs/gatsby-starters/)._ 14 | 15 | ## 🚀 Quick start 16 | 17 | 1. **Create a Gatsby site.** 18 | 19 | Use the Gatsby CLI to create a new site, specifying the default starter. 20 | 21 | ```shell 22 | # create a new Gatsby site using the default starter 23 | gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default 24 | ``` 25 | 26 | 1. **Start developing.** 27 | 28 | Navigate into your new site’s directory and start it up. 29 | 30 | ```shell 31 | cd my-default-starter/ 32 | gatsby develop 33 | ``` 34 | 35 | 1. **Open the source code and start editing!** 36 | 37 | Your site is now running at `http://localhost:8000`! 38 | 39 | _Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby tutorial](https://www.gatsbyjs.org/tutorial/part-five/#introducing-graphiql)._ 40 | 41 | Open the `my-default-starter` directory in your code editor of choice and edit `src/pages/index.js`. Save your changes and the browser will update in real time! 42 | 43 | ## 🧐 What's inside? 44 | 45 | A quick look at the top-level files and directories you'll see in a Gatsby project. 46 | 47 | . 48 | ├── node_modules 49 | ├── src 50 | ├── .gitignore 51 | ├── .prettierrc 52 | ├── gatsby-browser.js 53 | ├── gatsby-config.js 54 | ├── gatsby-node.js 55 | ├── gatsby-ssr.js 56 | ├── LICENSE 57 | ├── package-lock.json 58 | ├── package.json 59 | └── README.md 60 | 61 | 1. **`/node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages) are automatically installed. 62 | 63 | 2. **`/src`**: This directory will contain all of the code related to what you will see on the front-end of your site (what you see in the browser) such as your site header or a page template. `src` is a convention for “source code”. 64 | 65 | 3. **`.gitignore`**: This file tells git which files it should not track / not maintain a version history for. 66 | 67 | 4. **`.prettierrc`**: This is a configuration file for [Prettier](https://prettier.io/). Prettier is a tool to help keep the formatting of your code consistent. 68 | 69 | 5. **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage of the [Gatsby browser APIs](https://www.gatsbyjs.org/docs/browser-apis/) (if any). These allow customization/extension of default Gatsby settings affecting the browser. 70 | 71 | 6. **`gatsby-config.js`**: This is the main configuration file for a Gatsby site. This is where you can specify information about your site (metadata) like the site title and description, which Gatsby plugins you’d like to include, etc. (Check out the [config docs](https://www.gatsbyjs.org/docs/gatsby-config/) for more detail). 72 | 73 | 7. **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of the [Gatsby Node APIs](https://www.gatsbyjs.org/docs/node-apis/) (if any). These allow customization/extension of default Gatsby settings affecting pieces of the site build process. 74 | 75 | 8. **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of the [Gatsby server-side rendering APIs](https://www.gatsbyjs.org/docs/ssr-apis/) (if any). These allow customization of default Gatsby settings affecting server-side rendering. 76 | 77 | 9. **`LICENSE`**: Gatsby is licensed under the MIT license. 78 | 79 | 10. **`package-lock.json`** (See `package.json` below, first). This is an automatically generated file based on the exact versions of your npm dependencies that were installed for your project. **(You won’t change this file directly).** 80 | 81 | 11. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the project’s name, author, etc). This manifest is how npm knows which packages to install for your project. 82 | 83 | 12. **`README.md`**: A text file containing useful reference information about your project. 84 | 85 | ## 🎓 Learning Gatsby 86 | 87 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.org/). Here are some places to start: 88 | 89 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. 90 | 91 | - **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. 92 | 93 | ## 💫 Deploy 94 | 95 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default) 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/content/api/api.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Reference 3 | --- 4 | 5 | > This is a stub. Help our community expand it. 6 | -------------------------------------------------------------------------------- /docs/content/contributing/contributing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: How to contribute 3 | --- 4 | 5 | > This is a stub. Help our community expand it. 6 | -------------------------------------------------------------------------------- /docs/content/example/example.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | --- 4 | 5 | > This is a stub. Help our community expand it. 6 | 7 | You can find an example project with WordPress running in `docker` (backend) and configured Gatsby project (frontend). 8 | 9 | For more information follow the README in `/examples/gatsby-wordpress-gutenberg-default-example` inside [repo](https://github.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/tree/develop/examples/gatsby-wordpress-gutenberg-default-example). 10 | -------------------------------------------------------------------------------- /docs/content/features/blocks.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Block components 3 | description: Create your block component 4 | --- 5 | 6 | You can write your own custom block implementation for each block. Otherwise the default `` component is used which just displays the raw html output of the block. 7 | 8 | ## Example 9 | 10 | To create your own block component: 11 | 12 | - create a file with path `src/gatsby-theme-wordpress-gutenberg/components/blocks/[block-name].[ext]` which has the component as its default export 13 | - the file should contain a graphql fragment definition on the block's graphql type, where you can query for block fields, this fragment will be included when querying for `Blocks` component field 14 | - the `innerBlocks` components are passed in as the `children` prop 15 | 16 | > The components can be shadowed. That means if multiple themes or your project implement the same block, the last definition wins. 17 | 18 | For example for the default `core/quote` block, the file should be created as `src/gatsby-theme-wordpress-gutenberg/components/blocks/core/quote.js`: 19 | 20 | > Graphql typename for block type name is camelCased and uses Block suffix, for example: `core/quote` -> `WpCoreQuoteBlock` 21 | 22 | ```jsx 23 | import React from "react" 24 | import { graphql } from "gatsby" 25 | 26 | export const query = graphql` 27 | fragment Quote on WpCoreQuoteBlock { 28 | attributes { 29 | ... on WpCoreQuoteBlockAttributes { 30 | value 31 | } 32 | } 33 | } 34 | ` 35 | 36 | export default ({ attributes }) => ( 37 |

38 | This is a custom implementation of quote block 39 | My value is {attributes.value} 40 |

41 | ) 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/content/features/previews.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Previews 3 | --- 4 | 5 | To enable previews you either need a running instance of `gatsby develop` with ENABLE_GATSBY_REFRESH_ENDPOINT env variable enabled or a Preview instance running in `Gatsby Cloud`. 6 | 7 | > Check out the [official docs](https://www.gatsbyjs.org/docs/running-a-gatsby-preview-server/) on how tu run your preview instance 8 | 9 | ## Wordpress 10 | 11 | To be able to see previews in gutenberg, you need to install a plugin into Wordpress. 12 | 13 | ### wp-gatsby-gutenberg 14 | 15 | - Install the plugin manually, by downloading it from [here](https://github.com/GatsbyWPGutenberg/wp-gatsby-gutenberg/releases). 16 | - Install with [composer](https://packagist.org/packages/gatsby-wordpress-gutenberg/wp-gatsby-gutenberg) 17 | 18 | ```sh 19 | composer require gatsby-wordpress-gutenberg/wp-gatsby-gutenberg 20 | ``` 21 | 22 | ## Setup 23 | 24 | The enable live previews in Gutenberg, follow these steps: 25 | 26 | - enable your preview instance through `Settings -> GatsbyJS` 27 | - enable previews in gutenberg in `Settings -> GatsbyJS Gutenberg` 28 | 29 | > You should see preview icon inside block's edit toolbar. 30 | 31 | ![Block Preview](../images/block-preview.gif) 32 | 33 | > Each time a block content is changed and the preview button is clicked, a new Gatsby Preview trigger is send. This means this will also count to your previews count when running on Gatsby Cloud. 34 | 35 | ## How does it work 36 | 37 | - `wp-graphql-gutenberg` saves the live changes in gutenberg in the database within custom post type, which has one to one relationship with the edited post 38 | - when clicking the block preview button (available when the option is enabled), the preview content is sourced by `gatsby-source-wordpress-experimental` and special preview page for that post type is created within `gatsby-theme-wordpress-gutenberg` 39 | - the page with the highlighted block is then displayed inside gutenberg within an iframe 40 | -------------------------------------------------------------------------------- /docs/content/images/author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/images/author.png -------------------------------------------------------------------------------- /docs/content/images/block-preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/images/block-preview.gif -------------------------------------------------------------------------------- /docs/content/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/images/gatsby-icon.png -------------------------------------------------------------------------------- /docs/content/images/page-preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/images/page-preview.gif -------------------------------------------------------------------------------- /docs/content/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | --- 4 | 5 | ## What is Gutenberg 6 | 7 | Gutenberg is the new default WordPress content editor. Gutenberg introduces a block based approach to editing that aims to makes it easier to work with media rich pages and posts. 8 | 9 | ## What is GatsbyWPGutenberg 10 | 11 | GatsbyWPGutenberg is a framework that makes it possible to work with Gutenberg blocks in Gatsby instead of using raw HTML content. 12 | 13 | In other words, you can use Gutenberg as a page builder for your Gatsby's content. 14 | 15 | ## Features 16 | 17 | - Render Gutenberg blocks with custom React components 18 | - Live preview in Gatsby and Gutenberg 19 | - Automatic React component generation based on post's content to keep bundle size small 20 | 21 | > Consider this software is still in beta. 22 | 23 | ## Main contributors 24 | 25 | Peter Pristas - author of the project 31 | 32 | > Hi, my name is Peter Pristas. I am a full stack developer from Slovakia. Check out my other open-source projects on [Github](https://github.com/pristas-peter), or my [LinkedIn](https://www.linkedin.com/in/peter-pristas/) profile. 33 | -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/01-post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/01-post.png -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/02-Blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/02-Blocks.png -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/03-Unknown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/03-Unknown.gif -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/03-Unknown.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/03-Unknown.mov -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/04-Paragraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/04-Paragraph.png -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/05-Layout.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/05-Layout.gif -------------------------------------------------------------------------------- /docs/content/installation/images/quickstart/05-Layout.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/content/installation/images/quickstart/05-Layout.mov -------------------------------------------------------------------------------- /docs/content/installation/installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: How to install 4 | --- 5 | 6 | To get the core functionality you need to install plugins into Wordpress and npm packages into gatsby. 7 | 8 | ## Dependencies 9 | 10 | > The source plugin is based on the new `gatsby-source-wordpress-experimental` which uses `wp-graphql` under the hood. 11 | 12 | ### gatsby-source-wordpress-experimental 13 | 14 | Follow the instructions on the [plugin's repo](https://github.com/gatsbyjs/gatsby-source-wordpress-experimental). 15 | 16 | ## Gatsby 17 | 18 | - Install the theme with npm / yarn 19 | 20 | ```sh 21 | npm i gatsby-theme-wordpress-gutenberg 22 | # or 23 | yarn add gatsby-theme-wordpress-gutenberg 24 | ``` 25 | 26 | - Setup theme in your `gatsby-config.js`: 27 | 28 | ```js 29 | module.exports = { 30 | // ... 31 | plugins: [ 32 | // ... other plugins 33 | { 34 | resolve: `gatsby-source-wordpress-experimental`, 35 | options: { 36 | // configure according to plugin's instructions 37 | }, 38 | }, 39 | `gatsby-theme-wordpress-gutenberg`, 40 | ], 41 | } 42 | ``` 43 | 44 | - To setup previews, read the [previews](/features/previews/) section. 45 | -------------------------------------------------------------------------------- /docs/content/installation/packages.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Packages 3 | description: Various packages/plugins which define the framework 4 | --- 5 | 6 | The framework is defined by various packages which need to be installed inside wordpress and gatsby. 7 | 8 | ## Dependencies 9 | 10 | - [`gatsby-source-wordpress-experimental` / `wp-gatsby`](https://github.com/gatsbyjs/gatsby-source-wordpress-experimental): Gatsby package / WP plugin to source Wordpress content into gatsby's GraphQL schema. 11 | 12 | - [`wp-graphql-gutenberg`](https://github.com/pristas-peter/wp-graphql-gutenberg): WP plugin to expose gutenberg blocks through GraphQL schema. 13 | 14 | ## Core 15 | 16 | - `gatsby-theme-wordpress-gutenberg`: Gatsby package responsible for mapping blocks into react components with ability to query them automatically as one component 17 | 18 | > Read more about how theme works [here](/overview/theme/). 19 | 20 | ## Addons 21 | 22 | - `wp-gatsby-gutenberg`: WP plugin to enable live gatsby block previews in gutenberg 23 | 24 | - [`wp-graphql-gutenberg-acf`](https://github.com/pristas-peter/wp-graphql-gutenberg-acf) WP plugin to support ACF blocks (Pro). 25 | -------------------------------------------------------------------------------- /docs/content/installation/quickstart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quickstart Tutorial 3 | description: Simple tutorial on how to use the theme 4 | --- 5 | 6 | ## Install all dependencies 7 | 8 | This tutorial works with following versions of the plugins: 9 | 10 | - wp-graphql 0.9.1 11 | - wp-gatsby 0.4.1 12 | - wp-graphql-gutenberg 0.3.4 13 | - gatsby-source-wordpress-experimental 0.7.13 14 | 15 | ## Create a site 16 | 17 | > This tutorial follows up the the official create a site from strach tutorial from `gatsby-source-wordpress-experimental`. 18 | 19 | Follow the offical [site from stratch](https://github.com/gatsbyjs/gatsby-source-wordpress-experimental/blob/master/docs/tutorials/building-a-new-site-wordpress-and-gatsby.md) tutorial. When your site is up and running go to the next section. 20 | 21 | ## Add testing content 22 | 23 | Add new blocks to the default **Hello World** post. In this example, we added `Quote` and `Columns` blocks with some random content. 24 | 25 | 26 | 27 | ## Query Blocks component 28 | 29 | Open your `src/templates/blog-post.js`. Instead of `content`, we will now query for `Blocks` field. The Blocks field returns a React component which you can use when rendering your BlogPost component. 30 | 31 | > During fast refreshing of new content, there can be situations when the Blocks component can resolve to null, so you need to also make checks for this situation in your code. 32 | 33 | The `Blocks` component is a component which represents your structured content and is created during build phase. The post content is analyzed for all the blocks it contains and then the components which currently represent each block are consolidated into one component. This way, you only provide your custom implementations for each block and the magic of querying and sticking up the content together is done for you behind the scenes. 34 | 35 | ```js 36 | import React from "react" 37 | import Layout from "../components/layout" 38 | import { graphql } from "gatsby" 39 | 40 | export default function BlogPost({ data }) { 41 | const post = data.allWpPost.nodes[0] 42 | console.log(post) 43 | return ( 44 | 45 |
46 |

{post.title}

47 | {/* Changed rendering of content to post.Blocks */} 48 | {post.Blocks && } 49 |
50 |
51 | ) 52 | } 53 | export const query = graphql` 54 | query($slug: String!) { 55 | allWpPost(filter: { slug: { eq: $slug } }) { 56 | nodes { 57 | title 58 | Blocks ### changed content to Blocks 59 | } 60 | } 61 | } 62 | ``` 63 | 64 | 65 | 66 | Not much has changed visually, however now we are now not rendering the content as a raw html, but rather as a list of child components. 67 | 68 | > You may encounter a bug when nothing is rendered when you change the fields in the query for the first time. Until this is resolved, simply stop the develop command, run `gatsby clean` and start the `gatsby develop` again. 69 | 70 | ## Add your first block implementation 71 | 72 | You can write your own custom block implementation for each block. Otherwise the default `` implementation is used which just displays the raw html output of the block. 73 | 74 | We will start with shadowing this special component so we can display tooltip with the block name when hovering mouse over each block. 75 | 76 | > The example uses `rmwc` library which is a fantastic React Material Design implementation. Make sure to install it using npm/yarn. 77 | 78 | Create a file with path `src/gatsby-theme-wordpress-gutenberg/components/unknown-block.js`, with following content: 79 | 80 | ```js 81 | import React from "react" 82 | import { graphql } from "gatsby" 83 | 84 | import Block from "../../components/block" 85 | 86 | export const query = graphql` 87 | fragment UnknownBlock on WpBlock { 88 | ...Block 89 | saveContent 90 | } 91 | ` 92 | 93 | export default function UnknownBlock(props) { 94 | const { saveContent } = props 95 | 96 | return ( 97 | 98 |
99 | 100 | ) 101 | } 102 | ``` 103 | 104 | > The file should contain a graphql fragment definition on the block's graphql type, where you can query for block fields, this fragment will be included when querying for `Blocks` component field. In the example we are using `WpBlock` type which is common interface type for all blocks. 105 | 106 | As you can see in the file above, we also need to create a file in `src/components/block.js`, with following content (this component will be reused later in our various block implementations): 107 | 108 | ```js 109 | import React from "react" 110 | import { graphql } from "gatsby" 111 | import { Tooltip } from "@rmwc/tooltip" 112 | 113 | import "@rmwc/tooltip/styles" 114 | 115 | export const query = graphql` 116 | fragment Block on WpBlock { 117 | name 118 | } 119 | ` 120 | 121 | export default function Block({ name, children }) { 122 | return {children} 123 | } 124 | ``` 125 | 126 | Now you should see a tooltip when hovering each block with its name. 127 | 128 | 129 | 130 | ## Add Paragraph 131 | 132 | Let's say we want to have a paragraph block which has an oval shape with border and some custom background color. 133 | 134 | You can add your custom block implementations in `src/gatsby-theme-wordpress-gutenberg/components/blocks/[block-name].[ext]`. 135 | 136 | To create a custom Paragraph block implementation create `src/gatsby-theme-wordpress-gutenberg/components/blocks/core/paragraph.js`: 137 | 138 | ```js 139 | import React from "react" 140 | import { graphql } from "gatsby" 141 | 142 | import Block from "../../../../components/block" 143 | 144 | import "@rmwc/tooltip/styles" 145 | 146 | export const query = graphql` 147 | fragment Paragraph on WpCoreParagraphBlock { 148 | ...Block 149 | attributes { 150 | ... on WpCoreParagraphBlockAttributes { 151 | content 152 | dropCap 153 | customBackgroundColor 154 | } 155 | } 156 | } 157 | ` 158 | 159 | export default function Paragraph(props) { 160 | const { attributes } = props 161 | 162 | return ( 163 | 164 |

173 | 174 | ) 175 | } 176 | ``` 177 | 178 | After a hot reload you should see the result instantly: 179 | 180 | 181 | 182 | ## Add custom layout for Columns, Column 183 | 184 | To demonstrate how to work with the inner blocks feature, we will create custom implementations of Columns and Column blocks, which will map to rmwc's `` and ``. 185 | 186 | > The `innerBlocks` components are passed in as the `children` prop 187 | 188 | To create a custom Columns block implementation create `src/gatsby-theme-wordpress-gutenberg/components/blocks/core/columns.js`: 189 | 190 | ```js 191 | import React, { useMemo } from "react" 192 | import { graphql } from "gatsby" 193 | import { Grid } from "@rmwc/grid" 194 | 195 | import Block from "../../../../components/block" 196 | 197 | import "@rmwc/grid/styles" 198 | 199 | export const query = graphql` 200 | fragment Columns on WpCoreColumnsBlock { 201 | ...Block 202 | } 203 | ` 204 | 205 | export const ColumnsContext = React.createContext() 206 | 207 | export default function Columns(props) { 208 | const { children, ...rest } = props 209 | 210 | const value = useMemo(() => { 211 | const element = React.Children.toArray(children).pop() 212 | 213 | return { 214 | columns: element?.props?.blocks?.length || 0, 215 | } 216 | }, [children]) 217 | 218 | return ( 219 | 220 | 221 | {children} 222 | 223 | 224 | ) 225 | } 226 | ``` 227 | 228 | To create a custom Columns block implementation create `src/gatsby-theme-wordpress-gutenberg/components/blocks/core/column.js`: 229 | 230 | ```js 231 | import React, { useContext } from "react" 232 | import { graphql } from "gatsby" 233 | import { GridCell } from "@rmwc/grid" 234 | import { ColumnsContext } from "./columns" 235 | 236 | import Block from "../../../../components/block" 237 | 238 | import "@rmwc/grid/styles" 239 | 240 | export const query = graphql` 241 | fragment Column on WpCoreColumnBlock { 242 | ...Block 243 | } 244 | ` 245 | 246 | export default function Column(props) { 247 | const { children, ...rest } = props 248 | const { columns } = useContext(ColumnsContext) 249 | 250 | return ( 251 | 252 | {children} 253 | 254 | ) 255 | } 256 | ``` 257 | 258 | And the result should like this: 259 | 260 | 261 | 262 | > You can find the final result of this tutorial in the `examples/gatsby-wordpress-gutenberg-default-example/frontend` in the project's repo 263 | -------------------------------------------------------------------------------- /docs/content/overview/sourcing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sourcing 3 | description: How does sourcing work? 4 | --- 5 | 6 | ## How does Gutenberg store its content? 7 | 8 | > Get familiar with blocks core concepts from the [official handbook](https://developer.wordpress.org/block-editor/principles/key-concepts/). 9 | 10 | In a nutshell, `block` is some kind of unit for defining structured content. Every block has unique namespaced name and has to be registered in the `block registry` upon gutenberg bootstrap. 11 | Each block also contains `attributes` or configuration setting, which acts as a further metadata storage. 12 | 13 | The gutenberg editor than uses raw post html content to serialize/parse block information which is stored in html comments. 14 | 15 | Here is the example of serialized blocks in raw html post content, 16 | 17 | ```html 18 | 19 |

20 | 21 |
22 | 23 |

Left

24 | 25 |
26 | 27 | 28 | 29 |
30 | 31 |

Middle

32 | 33 |
34 | 35 | 36 | 37 |
38 | 39 |
40 | 41 | ``` 42 | 43 | and here the parsed counterpart: 44 | 45 | ```js 46 | const blocks = [ 47 | { 48 | blockName: "core/columns", 49 | attrs: { 50 | columns: 3, 51 | }, 52 | innerBlocks: [ 53 | { 54 | blockName: "core/column", 55 | attrs: null, 56 | innerBlocks: [ 57 | { 58 | blockName: "core/paragraph", 59 | attrs: null, 60 | innerBlocks: [], 61 | innerHTML: "\n

Left

\n", 62 | }, 63 | ], 64 | innerHTML: '\n
\n', 65 | }, 66 | { 67 | blockName: "core/column", 68 | attrs: null, 69 | innerBlocks: [ 70 | { 71 | blockName: "core/paragraph", 72 | attrs: null, 73 | innerBlocks: [], 74 | innerHTML: "\n

Middle

\n", 75 | }, 76 | ], 77 | innerHTML: '\n
\n', 78 | }, 79 | { 80 | blockName: "core/column", 81 | attrs: null, 82 | innerBlocks: [], 83 | innerHTML: '\n
\n', 84 | }, 85 | ], 86 | innerHTML: '\n
\n\n\n\n
\n', 87 | }, 88 | ] 89 | ``` 90 | 91 | ## Issues with Gutenberg 92 | 93 | Gutenberg's main issue lies within its client-side only architecture for registering/validating blocks. This way the block registry and block definitions are only available in the editor itself and not available from the PHP side of WordPress. This exposes many challenges on how to actually expose this information outside of WordPress. 94 | 95 | ## How is the content sourced? 96 | 97 | The main maintainer of this project is also the author of the [`wp-graphql-gutenberg`](https://github.com/pristas-peter/wp-graphql-gutenberg). This plugin is also responsible for providing the block data when the content is sourced through `gatsby-source-wordpress-experimental`. 98 | -------------------------------------------------------------------------------- /docs/content/overview/theme.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Theme 3 | description: How does the theme work? 4 | --- 5 | 6 | Theme gives you these features: 7 | 8 | - allows you to write custom React component for each block 9 | - autogenerates the `` component importing only react components that are used in the content, to keep bundle size small 10 | - manages live previews (as you type in gutenberg) 11 | 12 | The `Blocks` component can be obtained as a field through graphql query in Gatsby: 13 | 14 | ```js 15 | import React from "react" 16 | import Layout from "../components/layout" 17 | import { graphql } from "gatsby" 18 | 19 | export default function BlogPost({ data }) { 20 | const post = data.allWpPost.nodes[0] 21 | console.log(post) 22 | return ( 23 | 24 |
25 |

{post.title}

26 | {post.Blocks && } 27 |
28 |
29 | ) 30 | } 31 | export const query = graphql` 32 | query($slug: String!) { 33 | allWpPost(filter: { slug: { eq: $slug } }) { 34 | nodes { 35 | title 36 | Blocks 37 | } 38 | } 39 | } 40 | ` 41 | ``` 42 | 43 | > Read more about how to [write your custom React component](/features/blocks/) and how the [previews](/features/previews/) work. 44 | -------------------------------------------------------------------------------- /docs/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `GatsbyWPGutenberg Docs`, 4 | description: `GatsbyWPGutenberg documentation.`, 5 | }, 6 | plugins: [ 7 | { 8 | resolve: `gatsby-theme-apollo-docs`, 9 | options: { 10 | // defaultVersion: `0.1 Beta`, 11 | // versions: { 12 | // "0.1 Beta": `version-0.1`, 13 | // }, 14 | // algoliaApiKey: `4575706171508518950c4bf031729fc9`, 15 | // algoliaIndexName: `wpgg`, 16 | siteName: `GatsbyWPGutenberg Docs`, 17 | menuTitle: `GatsbyWPGutenberg Menu`, 18 | subtitle: `GatsbyWPGutenberg`, 19 | baseUrl: `https://gatsbywpgutenberg.netlify.app`, 20 | root: __dirname, 21 | description: `GatsbyWPGutenberg documentation`, 22 | githubRepo: `GatsbyWPGutenberg/gatsby-wordpress-gutenberg/docs`, 23 | logoLink: `https://gatsbywpgutenberg.netlify.app`, 24 | navConfig: { 25 | Docs: { 26 | url: `https://gatsbywpgutenberg.netlify.app`, 27 | description: `The GatsbyWPGutenberg docs`, 28 | }, 29 | Github: { 30 | url: `https://github.com/GatsbyWPGutenberg`, 31 | description: `GatsbyWPGutenberg on Github`, 32 | }, 33 | }, 34 | // footerNavConfig: { 35 | // SomeFooterLink: { 36 | // href: `https://github.com/wpgg`, 37 | // target: `_blank`, 38 | // rel: `noopener noreferrer`, 39 | // }, 40 | // }, 41 | sidebarCategories: { 42 | null: [`index`], 43 | "Get started": [`installation/packages`, `installation/installation`, `installation/quickstart`], 44 | Overview: [`overview/sourcing`, `overview/theme`], 45 | Features: [`features/blocks`, `features/page-templates`, `features/previews`], 46 | "Example Project": [`example/example`], 47 | Contributing: [`contributing/contributing`], 48 | "API Reference": [`api/api`], 49 | }, 50 | }, 51 | }, 52 | { 53 | resolve: `gatsby-transformer-remark`, 54 | options: { 55 | plugins: [ 56 | { 57 | resolve: `gatsby-remark-images`, 58 | options: { 59 | maxWidth: 800, 60 | }, 61 | }, 62 | ], 63 | }, 64 | }, 65 | `gatsby-plugin-preval`, 66 | ], 67 | } 68 | -------------------------------------------------------------------------------- /docs/gatsby-node.js: -------------------------------------------------------------------------------- 1 | exports.createSchemaCustomization = ({ actions }) => { 2 | actions.createTypes(` 3 | type File implements Node @infer { 4 | childMarkdownRemark: MarkdownRemark 5 | } 6 | 7 | type MarkdownRemark implements Node @infer { 8 | frontmatter: MarkdownRemarkFrontmatter 9 | fields: MarkdownRemarkFields 10 | } 11 | 12 | type MarkdownRemarkFields { 13 | image: String 14 | version: String 15 | slug: String 16 | graphManagerUrl: String 17 | versionRef: String 18 | sidebarTitle: String 19 | } 20 | 21 | type MarkdownRemarkFrontmatter { 22 | title: String 23 | subtitle: String 24 | description: String 25 | } 26 | `) 27 | } 28 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-wordpress-gutenberg-docs", 3 | "private": true, 4 | "description": "GatsbyWPGutenberg Documentation", 5 | "version": "0.1.0", 6 | "contributors": [ 7 | { 8 | "name": "Peter Pristas", 9 | "email": "pristas.peter@gmail.com", 10 | "url": "https://github.com/pristas-peter" 11 | }, 12 | { 13 | "name": "Henrik Wirth", 14 | "url": "https://github.com/henrikwirth" 15 | } 16 | ], 17 | "dependencies": { 18 | "gatsby": "^2.19.21", 19 | "gatsby-plugin-preval": "^1.0.0", 20 | "gatsby-plugin-sharp": "^2.6.14", 21 | "gatsby-remark-images": "^3.3.13", 22 | "gatsby-theme-apollo-docs": "4.1.3", 23 | "gatsby-transformer-remark": "^2.8.19", 24 | "react": "16.13.1", 25 | "react-dom": "16.13.1" 26 | }, 27 | "devDependencies": { 28 | "prettier": "^1.19.1" 29 | }, 30 | "keywords": [ 31 | "gatsby" 32 | ], 33 | "license": "MIT", 34 | "scripts": { 35 | "prestart": "gatsby clean", 36 | "build": "gatsby build", 37 | "develop": "gatsby develop", 38 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 39 | "start": "npm run develop", 40 | "serve": "gatsby serve", 41 | "clean": "gatsby clean", 42 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "https://github.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg-docs" 47 | }, 48 | "bugs": { 49 | "url": "https://github.com/gatsbyjs/gatsby/issues" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docs/src/components/style.css: -------------------------------------------------------------------------------- 1 | p { 2 | word-break: break-word; 3 | } 4 | -------------------------------------------------------------------------------- /docs/src/components/universal-link.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link as GatsbyLink } from "gatsby" 3 | // Since DOM elements cannot receive activeClassName 4 | // and partiallyActive, destructure the prop here and 5 | // pass it only to GatsbyLink 6 | const UniversalLink = ({ children, to, activeClassName, partiallyActive, ...other }) => { 7 | // Tailor the following test to your environment. 8 | // This example assumes that any internal link (intended for Gatsby) 9 | // will start with exactly one slash, and that anything else is external. 10 | const internal = /^\/(?!\/)/.test(to) 11 | // Use Gatsby Link for internal links, and for others 12 | if (internal) { 13 | return ( 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | return ( 20 | 21 | {children} 22 | 23 | ) 24 | } 25 | export default UniversalLink 26 | -------------------------------------------------------------------------------- /docs/src/gatsby-theme-apollo-core/components/logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function Logo() { 4 | return ( 5 |

🚀 GatsbyWPGutenberg Docs

10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/gatsby-theme-apollo-docs/assets/social-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GatsbyWPGutenberg/gatsby-wordpress-gutenberg/4bcd987b1a79f47849a7f3b97e2e0bbea673a022/docs/src/gatsby-theme-apollo-docs/assets/social-bg.jpg -------------------------------------------------------------------------------- /docs/src/gatsby-theme-apollo-docs/components/custom-seo.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types" 2 | import React from "react" 3 | import { SEO } from "gatsby-theme-apollo-core" 4 | import { withPrefix } from "gatsby" 5 | 6 | export default function CustomSEO({ image, baseUrl, twitterHandle, ...props }) { 7 | const imagePath = withPrefix(`/` + image) 8 | return ( 9 | 10 | 11 | {baseUrl && } 12 | {twitterHandle && } 13 | 14 | ) 15 | } 16 | 17 | CustomSEO.propTypes = { 18 | baseUrl: PropTypes.string, 19 | image: PropTypes.string.isRequired, 20 | twitterHandle: PropTypes.string, 21 | } 22 | -------------------------------------------------------------------------------- /docs/src/gatsby-theme-apollo-docs/components/header-button.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import styled from "@emotion/styled" 3 | import { IconProceed } from "@apollo/space-kit/icons/IconProceed" 4 | import { breakpoints } from "gatsby-theme-apollo-core" 5 | import { colors } from "@apollo/space-kit/colors" 6 | 7 | const Container = styled.div({ 8 | display: `flex`, 9 | flexShrink: 0, 10 | width: 240, 11 | [breakpoints.lg]: { 12 | width: `auto`, 13 | marginRight: 0, 14 | }, 15 | [breakpoints.md]: { 16 | display: `none`, 17 | }, 18 | }) 19 | 20 | const StyledLink = styled.a({ 21 | display: `flex`, 22 | alignItems: `center`, 23 | color: colors.indigo.dark, 24 | lineHeight: 2, 25 | textDecoration: `none`, 26 | ":hover": { 27 | color: colors.indigo.darker, 28 | }, 29 | }) 30 | 31 | const StyledIcon = styled(IconProceed)({ 32 | height: `0.75em`, 33 | marginLeft: `0.5em`, 34 | }) 35 | 36 | export default function HeaderButton() { 37 | return ( 38 | 39 | 44 | Visit us on GitHub 45 | 46 | 47 | 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /docs/src/gatsby-theme-apollo-docs/components/page-layout.js: -------------------------------------------------------------------------------- 1 | import "gatsby-theme-apollo-docs/src/prism.less" 2 | import "prismjs/plugins/line-numbers/prism-line-numbers.css" 3 | import DocsetSwitcher from "gatsby-theme-apollo-docs/src/components/docset-switcher" 4 | import Header from "gatsby-theme-apollo-docs/src/components/header" 5 | import HeaderButton from "gatsby-theme-apollo-docs/src/components/header-button" 6 | import PropTypes from "prop-types" 7 | import React, { createContext, useMemo, useRef, useState } from "react" 8 | import Search from "gatsby-theme-apollo-docs/src/components/search" 9 | import styled from "@emotion/styled" 10 | import useLocalStorage from "react-use/lib/useLocalStorage" 11 | import { Button } from "@apollo/space-kit/Button" 12 | import { 13 | FlexWrapper, 14 | Layout, 15 | MenuButton, 16 | Sidebar, 17 | SidebarNav, 18 | breakpoints, 19 | colors, 20 | useResponsiveSidebar, 21 | } from "gatsby-theme-apollo-core" 22 | import { Helmet } from "react-helmet" 23 | import { IconLayoutModule } from "@apollo/space-kit/icons/IconLayoutModule" 24 | import { Link, graphql, navigate, useStaticQuery } from "gatsby" 25 | // import { MobileLogo } from "gatsby-theme-apollo-docs/src/components/mobile-logo" 26 | import { Select } from "gatsby-theme-apollo-docs/src/components/select" 27 | import { SelectedLanguageContext } from "gatsby-theme-apollo-docs/src/components/multi-code-block" 28 | import { getSpectrumUrl, getVersionBasePath } from "gatsby-theme-apollo-docs/src/utils" 29 | import { size } from "polished" 30 | 31 | const Main = styled.main({ 32 | flexGrow: 1, 33 | }) 34 | 35 | const ButtonWrapper = styled.div({ 36 | flexGrow: 1, 37 | }) 38 | 39 | const StyledButton = styled(Button)({ 40 | width: `100%`, 41 | ":not(:hover)": { 42 | backgroundColor: colors.background, 43 | }, 44 | }) 45 | 46 | const StyledIcon = styled(IconLayoutModule)(size(16), { 47 | marginLeft: `auto`, 48 | }) 49 | 50 | const MobileNav = styled.div({ 51 | display: `none`, 52 | [breakpoints.md]: { 53 | display: `flex`, 54 | alignItems: `center`, 55 | marginRight: 32, 56 | color: colors.text1, 57 | }, 58 | }) 59 | 60 | const HeaderInner = styled.span({ 61 | display: `flex`, 62 | alignItems: `center`, 63 | justifyContent: `space-between`, 64 | marginBottom: 32, 65 | }) 66 | 67 | const Eyebrow = styled.div({ 68 | flexShrink: 0, 69 | padding: `8px 56px`, 70 | backgroundColor: colors.background, 71 | color: colors.primary, 72 | fontSize: 14, 73 | position: `sticky`, 74 | top: 0, 75 | a: { 76 | color: `inherit`, 77 | fontWeight: 600, 78 | }, 79 | [breakpoints.md]: { 80 | padding: `8px 24px`, 81 | }, 82 | }) 83 | 84 | const NetlifyLink = styled.a({ 85 | marginRight: 12, 86 | }) 87 | 88 | function getVersionLabel(version) { 89 | return `v${version}` 90 | } 91 | 92 | const GA_EVENT_CATEGORY_SIDEBAR = `Sidebar` 93 | 94 | function handleToggleAll(expanded) { 95 | if (typeof window.analytics !== `undefined`) { 96 | window.analytics.track(`Toggle all`, { 97 | category: GA_EVENT_CATEGORY_SIDEBAR, 98 | label: expanded ? `expand` : `collapse`, 99 | }) 100 | } 101 | } 102 | 103 | function handleToggleCategory(title, expanded) { 104 | if (typeof window.analytics !== `undefined`) { 105 | window.analytics.track(`Toggle category`, { 106 | category: GA_EVENT_CATEGORY_SIDEBAR, 107 | label: title, 108 | value: Number(expanded), 109 | }) 110 | } 111 | } 112 | 113 | export const NavItemsContext = createContext() 114 | 115 | export default function PageLayout(props) { 116 | const data = useStaticQuery( 117 | graphql` 118 | { 119 | site { 120 | siteMetadata { 121 | title 122 | siteName 123 | } 124 | } 125 | } 126 | ` 127 | ) 128 | 129 | const { sidebarRef, openSidebar, sidebarOpen, handleWrapperClick, handleSidebarNavLinkClick } = useResponsiveSidebar() 130 | 131 | const buttonRef = useRef(null) 132 | const [menuOpen, setMenuOpen] = useState(false) 133 | const selectedLanguageState = useLocalStorage(`docs-lang`) 134 | 135 | function openMenu() { 136 | setMenuOpen(true) 137 | } 138 | 139 | function closeMenu() { 140 | setMenuOpen(false) 141 | } 142 | 143 | const { pathname } = props.location 144 | const { siteName, title } = data.site.siteMetadata 145 | const { subtitle, sidebarContents, versions, versionDifference, versionBasePath, defaultVersion } = props.pageContext 146 | const { 147 | spectrumHandle, 148 | twitterHandle, 149 | youtubeUrl, 150 | navConfig = {}, 151 | footerNavConfig, 152 | logoLink, 153 | algoliaApiKey, 154 | algoliaIndexName, 155 | menuTitle, 156 | } = props.pluginOptions 157 | 158 | const navItems = useMemo( 159 | () => 160 | Object.entries(navConfig).map(([title, navItem]) => ({ 161 | ...navItem, 162 | title, 163 | })), 164 | [navConfig] 165 | ) 166 | 167 | const hasNavItems = navItems.length > 0 168 | const sidebarTitle = {subtitle || siteName} 169 | 170 | return ( 171 | 172 | 173 | 174 | 175 | 176 | 177 | 185 | 186 | {hasNavItems ? ( 187 | 188 | 195 | {sidebarTitle} 196 | 197 | 198 | 199 | ) : ( 200 | sidebarTitle 201 | )} 202 | {versions && versions.length > 0 && ( 203 | ' . 77 | __('Yes', 'wordpress'); 78 | }, 79 | 'wp_gatsby_gutenberg' 80 | ); 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /plugins/wp-gatsby-gutenberg/src/Preview/Preview.php: -------------------------------------------------------------------------------- 1 | post_type)->graphql_single_name ?? null; 32 | 33 | $graphql_endpoint = apply_filters('graphql_endpoint', 'graphql'); 34 | 35 | $graphql_url = get_home_url() . '/' . ltrim($graphql_endpoint, '/'); 36 | 37 | $post_body = [ 38 | 'preview' => true, 39 | 'token' => $token, 40 | 'previewId' => $post_ID, 41 | 'id' => $global_relay_id, 42 | 'singleName' => lcfirst($referenced_node_single_name), 43 | 'isNewPostDraft' => false, 44 | 'isRevision' => false, 45 | 'remoteUrl' => $graphql_url, 46 | ]; 47 | 48 | return wp_remote_post($preview_webhook, [ 49 | 'body' => wp_json_encode($post_body), 50 | 'headers' => [ 51 | 'Content-Type' => 'application/json; charset=utf-8', 52 | ], 53 | 'method' => 'POST', 54 | 'data_format' => 'body', 55 | ]); 56 | } 57 | 58 | public static function get_gatsby_preview_url($post_ID) 59 | { 60 | $post_type_object = \get_post_type_object(get_post_type($post_ID)); 61 | 62 | $referenced_node_single_name = lcfirst( 63 | $post_type_object->graphql_single_name 64 | ); 65 | 66 | $post_url = get_the_permalink($post_ID); 67 | $path = str_ireplace(get_home_url(), '', $post_url); 68 | 69 | if (strpos($path, '?')) { 70 | $path = "/$referenced_node_single_name/$post_ID"; 71 | } 72 | 73 | $preview_url = \WPGatsby\Admin\Preview::get_gatsby_preview_instance_url(); 74 | $preview_url = rtrim($preview_url, '/'); 75 | return "$preview_url$path"; 76 | } 77 | 78 | function __construct() 79 | { 80 | // this is a fix for node not resolving properly when revision 81 | // will be fixed in wp-graphql 0.10 82 | add_filter( 83 | 'graphql_resolve_node_type', 84 | function ($type, $node) { 85 | if ($type === null && $node instanceof Post) { 86 | if ('revision' === $node->post_type) { 87 | return get_post_type_object( 88 | get_post_type(get_post($node->ID)->post_parent) 89 | )->graphql_single_name ?? null; 90 | } 91 | } 92 | 93 | return $type; 94 | }, 95 | 10, 96 | 2 97 | ); 98 | 99 | add_action('graphql_register_types', function () { 100 | register_graphql_field('Block', 'previewUUID', [ 101 | 'type' => 'String', 102 | 'description' => __( 103 | 'Preview UUID of the block', 104 | 'wp-gatsby-gutenberg' 105 | ), 106 | 'resolve' => function ($block) { 107 | return $block->attributes['wpGatsbyGutenbergUUID']; 108 | }, 109 | ]); 110 | }); 111 | 112 | add_action('rest_api_init', function () { 113 | register_rest_route('wp-gatsby-gutenberg/v1', '/previews/refresh', [ 114 | 'methods' => 'POST', 115 | 'callback' => function (WP_REST_Request $request) { 116 | if ( 117 | 'on' !== 118 | WPGatsbyPreview::get_setting('enable_gatsby_preview') 119 | ) { 120 | return new WP_Error( 121 | 400, 122 | __( 123 | 'Gatsby previews are not configured.', 124 | 'wp-gatsby-gutenberg' 125 | ) 126 | ); 127 | } 128 | 129 | if (!Settings::get_setting('enable_live_preview')) { 130 | return new WP_Error( 131 | 400, 132 | __( 133 | 'Gatsby Gutenberg previews are disabled.', 134 | 'wp-gatsby-gutenberg' 135 | ) 136 | ); 137 | } 138 | 139 | $id = BlockEditorPreview::get_preview_id( 140 | $request->get_param('postId'), 141 | $request->get_param('previewPostId') 142 | ); 143 | 144 | if (empty($id)) { 145 | return new WP_Error( 146 | 400, 147 | __( 148 | 'Preview data for given post does not exist.', 149 | 'wp-gatsby-gutenberg' 150 | ) 151 | ); 152 | } 153 | 154 | $result = self::post_preview($id); 155 | 156 | if (is_wp_error($result)) { 157 | return $result; 158 | } 159 | 160 | return array_merge($result['response'], [ 161 | 'gatsby_preview_url' => self::get_gatsby_preview_url( 162 | $id 163 | ), 164 | ]); 165 | }, 166 | 'permission_callback' => function () { 167 | return current_user_can('edit_others_posts'); 168 | }, 169 | 'args' => [ 170 | 'postId' => [ 171 | 'required' => true, 172 | 'validate_callback' => 'is_numeric', 173 | ], 174 | 'previewPostId' => [ 175 | 'required' => true, 176 | 'validate_callback' => 'is_numeric', 177 | ], 178 | ], 179 | ]); 180 | }); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /plugins/wp-gatsby-gutenberg/src/Preview/gatsby-block-preview.js: -------------------------------------------------------------------------------- 1 | import { Spinner, Button } from '@wordpress/components'; 2 | import { useState, useEffect, useRef, useCallback } from '@wordpress/element'; 3 | import { __ } from '@wordpress/i18n'; 4 | import apiFetch from '@wordpress/api-fetch'; 5 | 6 | export const useGatsbyBlockPreview = ( props ) => { 7 | const { postId, attributes, previewPostId, refresh } = props; 8 | 9 | const [ loading, setLoading ] = useState( false ); 10 | const [ error, setError ] = useState( null ); 11 | const [ data, setData ] = useState( null ); 12 | const currentPromiseRef = useRef( null ); 13 | const previousRefreshPreviewRef = useRef( null ); 14 | const previousRefreshRef = useRef( null ); 15 | 16 | const refreshPreview = useCallback( () => { 17 | setLoading( true ); 18 | setError( null ); 19 | 20 | const promise = apiFetch( { 21 | path: `/wp-gatsby-gutenberg/v1/previews/refresh`, 22 | method: `POST`, 23 | data: { postId, previewPostId }, 24 | } ) 25 | .then( ( data ) => { 26 | if ( promise === currentPromiseRef.current ) { 27 | setData( data ); 28 | } 29 | } ) 30 | 31 | .catch( ( error ) => { 32 | if ( promise === currentPromiseRef.current ) { 33 | setError( error ); 34 | } 35 | } ) 36 | 37 | .finally( () => { 38 | if ( promise === currentPromiseRef.current ) { 39 | setLoading( false ); 40 | } 41 | } ); 42 | 43 | currentPromiseRef.current = promise; 44 | return promise; 45 | }, [ postId, previewPostId, attributes, currentPromiseRef ] ); 46 | 47 | useEffect( () => { 48 | if ( 49 | refresh && 50 | ( previousRefreshPreviewRef.current !== refreshPreview || 51 | ( previousRefreshRef.current === false && error ) ) 52 | ) { 53 | previousRefreshPreviewRef.current = refreshPreview; 54 | 55 | refreshPreview(); 56 | } 57 | 58 | previousRefreshRef.current = refresh; 59 | }, [ refresh, refreshPreview ] ); 60 | 61 | return { 62 | loading, 63 | data, 64 | error, 65 | retry: refreshPreview, 66 | previewUUID: attributes.wpGatsbyGutenbergUUID, 67 | }; 68 | }; 69 | 70 | const Loader = ( { style, message } ) => ( 71 |
72 | 73 |

{ message }

74 |
75 | ); 76 | 77 | const ErrorMessage = ( { style, retry, message } ) => ( 78 |
79 |

{ message }

80 | 83 |
84 | ); 85 | 86 | const Preview = ( { src, style } ) => { 87 | const [ pageReady, setPageReady ] = useState( false ); 88 | const fetchPromiseRef = useRef( null ); 89 | const timeoutRef = useRef( null ); 90 | const mountedRef = useRef( true ); 91 | 92 | const cleanup = useCallback( () => { 93 | if ( timeoutRef.current ) { 94 | clearTimeout( timeoutRef.current ); 95 | timeoutRef.current = null; 96 | } 97 | }, [ timeoutRef ] ); 98 | 99 | const check = useCallback( () => { 100 | cleanup(); 101 | 102 | const promise = fetch( src ) 103 | .then( ( response ) => { 104 | if ( fetchPromiseRef.current === promise ) { 105 | if ( 106 | response && 107 | response.headers.get( 108 | 'X-Theme-Wordpress-Gutenberg-Preview-Page' 109 | ) 110 | ) { 111 | setPageReady( true ); 112 | } else { 113 | return Promise.reject( new Error() ); 114 | } 115 | } 116 | } ) 117 | .catch( () => { 118 | if ( fetchPromiseRef.current === promise ) { 119 | timeoutRef.current = setTimeout( () => { 120 | if ( mountedRef.current ) { 121 | check(); 122 | } 123 | }, 1500 ); 124 | } 125 | } ); 126 | 127 | fetchPromiseRef.current = promise; 128 | 129 | return promise; 130 | }, [ src, mountedRef ] ); 131 | 132 | useEffect( () => { 133 | check(); 134 | 135 | return () => { 136 | mountedRef.current = false; 137 | cleanup(); 138 | }; 139 | }, [] ); 140 | 141 | if ( pageReady ) { 142 | return