├── .gitignore ├── README.md ├── theme-w-ssr-support ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── README.md ├── docker-compose.yml ├── package-lock.json ├── package.json ├── public │ ├── composer.json │ ├── composer.lock │ ├── favicon.ico │ ├── functions.php │ ├── includes │ │ ├── core-settings-patch.php │ │ ├── schema-patch.php │ │ └── send-inquiry-mutation.php │ ├── index.php │ ├── logo.inkscape.svg │ ├── logo.svg │ ├── manifest.json │ └── style.css ├── scripts │ ├── symlink-local.js │ └── volumes.js ├── src │ ├── app.jsx │ ├── client.jsx │ ├── components │ │ ├── posed-elements.js │ │ └── waypoint.jsx │ ├── contact │ │ ├── dialog.jsx │ │ ├── index.jsx │ │ ├── inquiry-form.jsx │ │ └── send-inquiry.js │ ├── content │ │ ├── archive.jsx │ │ ├── index.jsx │ │ ├── page.jsx │ │ └── post.jsx │ ├── create-client.js │ ├── footer.jsx │ ├── icons │ │ ├── hamburger-mask.svg │ │ ├── hamburger.jsx │ │ ├── logo.jsx │ │ └── spinner.jsx │ ├── index.scss │ ├── lib │ │ └── colors.js │ ├── nav-menu │ │ ├── index.jsx │ │ ├── menu-item.jsx │ │ └── styled.js │ ├── server │ │ ├── index.js │ │ └── server.jsx │ └── serviceWorker.js └── webpack.config.js └── using-react-apollo ├── README.md ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json └── src ├── PostCard.js ├── PostsList.js ├── PostsSearch.js ├── index.css └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | node_modules 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WPGraphQL Examples 2 | 3 | This is a repo dedicated to examples making use of WPGraphQL. 4 | -------------------------------------------------------------------------------- /theme-w-ssr-support/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": "airbnb", 7 | "globals": { 8 | "Atomics": "readonly", 9 | "SharedArrayBuffer": "readonly", 10 | "context": "readonly", 11 | "dispatch": "readonly", 12 | }, 13 | "parserOptions": { 14 | "ecmaFeatures": { 15 | "jsx": true 16 | }, 17 | "ecmaVersion": 2018, 18 | "sourceType": "module" 19 | }, 20 | "plugins": [ 21 | "react" 22 | ], 23 | "rules": { 24 | } 25 | }; -------------------------------------------------------------------------------- /theme-w-ssr-support/.gitignore: -------------------------------------------------------------------------------- 1 | # Build # 2 | ######### 3 | build 4 | deploy 5 | 6 | # Docker Dev Environment # 7 | ########################## 8 | _dev 9 | 10 | # Packages # 11 | ############ 12 | *.7z 13 | *.dmg 14 | *.gz 15 | *.bz2 16 | *.iso 17 | *.jar 18 | *.rar 19 | *.tar 20 | *.zip 21 | *.tgz 22 | *.map 23 | 24 | # Logs and databases # 25 | ###################### 26 | *.log 27 | *.sql 28 | 29 | # OS generated files # 30 | ###################### 31 | **.DS_Store* 32 | ehthumbs.db 33 | Icon? 34 | Thumbs.db 35 | ._* 36 | 37 | # Vim generated files # 38 | ####################### 39 | *.un~ 40 | 41 | # SASS # 42 | ######## 43 | **/.sass-cache 44 | **/.sass-cache/* 45 | **/.map 46 | 47 | # Special # 48 | ########### 49 | .old 50 | 51 | # Externals # 52 | ############# 53 | node_modules 54 | vendor 55 | 56 | # PhpStrom Project Files # 57 | ########################## 58 | .idea 59 | 60 | # VSCode Project Files # 61 | ######################## 62 | .vscode/ 63 | .code-workspace 64 | 65 | # Other # 66 | ######### 67 | .DS_Store 68 | *.tgz 69 | my-app* 70 | template/src/__tests__/__snapshots__/ 71 | lerna-debug.log 72 | npm-debug.log* 73 | yarn-debug.log* 74 | yarn-error.log* 75 | /.changelog -------------------------------------------------------------------------------- /theme-w-ssr-support/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | ARG WORDPRESS_VERSION 3 | ARG PHP_VERSION 4 | FROM wordpress:${WORDPRESS_VERSION}-php${PHP_VERSION}-apache 5 | 6 | LABEL author="Geoff Taylor " 7 | 8 | USER root 9 | 10 | ARG NODE_VERSION 11 | RUN apt-get update && \ 12 | apt-get install -y --no-install-recommends gnupg && \ 13 | curl -sL https://deb.nodesource.com/setup_${NODE_VERSION:-10}.x | bash - && \ 14 | apt-get update && \ 15 | apt-get install -y --no-install-recommends nodejs && \ 16 | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ 17 | echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ 18 | apt-get update && \ 19 | apt-get install -y --no-install-recommends yarn -------------------------------------------------------------------------------- /theme-w-ssr-support/README.md: -------------------------------------------------------------------------------- 1 | ![logo](public/logo.svg) 2 | # WPGraphQL Theme with Server-Side Rendering 3 | An example wordpress theme that loads a React.js SPA and retrieved data from WPGraphQL using WPGraphQL Composer component library. The SPA is loaded server-side using the [spatie/server-side-rendering](https://github.com/spatie/server-side-rendering) package's Node engine. It also contains examples of for modifying WPGraphQL's schema. 4 | 5 | ## Features 6 | - Docker compose file for testing. 7 | - Sass support 8 | 9 | ## Usage 10 | 1. Clone repository `git clone https://github.com/kidunot89/oil-based-boilerplate`. 11 | 2. Run `composer install` in the public directory in project working directory 12 | 3. Run `npm install && npm run docker-vols && npm run build` in project working directory. 13 | 4. (Docker only *Docker-Compose required*) Run `npm run start-docker` in project working directory. 14 | 4. (Local Installation) Run `npm run link-wp -- ` in project working directory. 15 | 5. Run `npm start` in project working directory. 16 | 6. Navigate to `http://localhost:8088/` and run through the installation. 17 | 7. Activate `WPGraphQL` in `Plugins` as well as `WPGraphQL Examples` in `Themes`. 18 | 8. Navigate to "Permalink" under "Settings" and set "Common Settings" to anything but "Plain". 19 | 9. Load or create Posts using editor or WordPress importer. 20 | 10. Set an menu to the `main` location. 21 | 11. Now you ready to code. Run `npm run stop-docker` in project working directory to stop and destroy docker containers. 22 | 12. (Might be needed) If you get the **Connection Information** when trying to install plugins or import content. Do the following from the terminal in the project directory 23 | 1. Run `docker ps`. Make note of the container name ending in `_wordpress-node_1`. 24 | 2. Next run `docker exec -it XXXXX_wordpress-node_1 bash`. This should plugin you in the docker container at `/var/www/html`. 25 | 3. Last run `chown -hR www-data:www-data wp-content && exit`. If you notice the permission errors flashing by, ignore them. 26 | 27 | ### Usage w/o Docker 28 | The `link-wp` script simply symlinks links the required project directories into your Wordpress installation. The issue with this is that there is a good chance the script won't work if the user who owns the wordpress plugins and themes directories is not the same user as the one running the script like `www-data`. In situations like this you have two choices. 29 | - Change the owner of the themes and plugins directory to be the user running the script, run the script, and change the owner back to the original user. 30 | - Or Manually symlink all the directories. This means the three sub-directories in the `_dev` directory point to the plugins directory, the `build/plugin` to the plugins directory, `build/theme` to the themes directory. 31 | - Node.js must be installed on your machine and the NODE_PATH environmental variable must be set to the location of the node.js executable. 32 | 33 | ## SSR Notes & Caveats 34 | ### public/functions.php 35 | Context data is defined in a singleton pattern. Also, in order for ApolloGraphQL to work server side on the same machine as WordPress `127.0.0.1` has to be used instead of `localhost` in local dev environments. Otherwise, the an **ECONNREFUSED** error is thrown. Another thing if you change chunk configuration in webpack be sure to update `VENDOR_SCRIPT_URI` in both the context and the `wp_graphql_enqueue_scripts` function below 36 | ``` 37 | /** 38 | * @var app_context stores context for request 39 | */ 40 | $app_context = null; 41 | 42 | ... 43 | 44 | function wp_graphql_get_context( $server = false ){ 45 | global $app_context; 46 | $request_uri = $_SERVER['REQUEST_URI']; 47 | 48 | if ( $app_context === null ) { 49 | $app_context = [ 50 | 'HOME_URL' => home_url(), 51 | 'APP_TITLE' => get_bloginfo( 'name' ), 52 | 'LOCATION' => $request_uri, 53 | 'SERVER_SCRIPT_PATH' => get_template_directory() . '/js/server.js', 54 | 'CLIENT_SCRIPT_URI' => get_template_directory_uri() . '/js/client.js', 55 | 'VENDOR_SCRIPT_URI' => get_template_directory_uri() . '/js/vendors~main.client.js', 56 | 'STYLE_URI' => get_template_directory_uri() . '/js/main.css', 57 | 'AJAX_URL' => admin_url( 'admin-ajax.php' ), 58 | ]; 59 | } 60 | 61 | return array_merge( 62 | $app_context, 63 | [ 64 | // in a local dev environment change home_url('/') to http://127.0.0.1/ and vice-versa 65 | 'ENDPOINT' => ( $server ? 'http://127.0.0.1/' : '/' ) . apply_filters( 'graphql_endpoint', 'graphql' ), 66 | ] 67 | ); 68 | } 69 | ``` 70 | 71 | Client-side script is chunked must be loaded in order like so. Note the `wp_localize_script` call as well use to past context data client-side. 72 | ``` 73 | /** 74 | * Queues up theme's CSS/JS dependencies. 75 | */ 76 | function wp_graphql_enqueue_scripts() { 77 | global $theme_version; 78 | 79 | // Get dependencies 80 | $style_deps = []; 81 | if( wp_graphql_url_exists( wp_graphql_google_fonts_url() ) ) { 82 | wp_enqueue_style( 'google-fonts', wp_graphql_google_fonts_url() ); 83 | $style_deps[] = 'google-fonts'; 84 | } 85 | 86 | // Get request context and enqueue required styles/scripts 87 | $context = wp_graphql_get_context(); 88 | wp_enqueue_style( 89 | 'wp-graphql-style', 90 | $context[ 'STYLE_URI' ], 91 | $style_deps 92 | ); 93 | wp_enqueue_script( 94 | 'wp-graphql-vendor', 95 | $context[ 'VENDOR_SCRIPT_URI' ], 96 | array(), 97 | $theme_version, 98 | true 99 | ); 100 | wp_enqueue_script( 101 | 'wp-graphql-client', 102 | $context[ 'CLIENT_SCRIPT_URI' ], 103 | array( 'wp-graphql-vendor' ), 104 | $theme_version, 105 | true 106 | ); 107 | wp_localize_script( 'wp-graphql-client', 'context', $context ); 108 | 109 | //Dequeue unnecessary scripts 110 | wp_dequeue_script( 'react' ); 111 | wp_dequeue_script( 'react-dom' ); 112 | } 113 | add_action( 'wp_enqueue_scripts', 'wp_graphql_enqueue_scripts' ); 114 | ``` 115 | 116 | ### public/index.php 117 | Server-side rendering is executed here. The `$nodePath` must be a valid path to the Node.js executable. The V8Js is viable alternative, but it requires an alternative setup. I suggest reading Sebastian De Deyne's [article](https://sebastiandedeyne.com/server-side-rendering-javascript-from-php/) learn more about it. 118 | ``` 119 | require_once 'vendor/autoload.php'; 120 | 121 | use Spatie\Ssr\Renderer; 122 | use Spatie\Ssr\Engines\Node; 123 | 124 | $nodePath = getenv('NODE_PATH') ?: '/usr/bin/node'; 125 | $tempPath = sys_get_temp_dir(); 126 | $context = wp_graphql_get_context(true); 127 | 128 | $engine = new Node($nodePath, $tempPath); 129 | $renderer = new Renderer($engine); 130 | $app = json_decode( 131 | $renderer 132 | ->entry( $context[ 'SERVER_SCRIPT_PATH' ] ) 133 | ->context( $context ) 134 | ->debug() 135 | ->render(), 136 | true 137 | ); 138 | ``` 139 | 140 | ## WPGraphQL Component Notes & Caveats 141 | WPGraphQL-Composer is a component library relied on heavily in the root React application as see below. 142 | ``` 143 | ... 144 | import Navbar from './nav-menu'; 145 | import Footer from './footer'; 146 | import Content from './content'; 147 | ... 148 | const Main = styled.main` 149 | position: relative; 150 | padding: 0; 151 | margin: 0 auto; 152 | width: 100%; 153 | min-height: 100vh; 154 | `; 155 | 156 | export default () => ( 157 | 158 | // MAIN is the MenuLocationEnum value for the `main` menu created in public/functions.php 159 |
// Wrapper styled-component 160 | // The real main component don't let the name confuse you. I'm sorry. I suck at names XD. 161 |
162 |