6 |
7 | ### 👋 Looking for a way to support live previews with Gatsby + WordPress?
8 | [Check this repo out](https://github.com/justinwhall/wordpress-gatsby-preview-starter)!
9 |
10 | # Gatsby + Headless WordPress + Netlify Starter
11 |
12 | A starter skeleton that leverages the WordPress API for [Gatsby](https://github.com/gatsbyjs/gatsby/). Support for Continuous integration with Netlify. Publishing posts call the Netlify build hook. Deploy to Netlify stage or production enviroment when updating a WordPress post or page.
13 |
14 | ## Dependencies
15 |
16 | * [WP Buildhook Deploy](https://github.com/justinwhall/littlebot-netlify) installed and activated on the source WordPress installation.
17 |
18 | #### This Project was forked from the default [Gatsby Starter](https://github.com/gatsbyjs/gatsby-starter-blog)
19 |
20 |
21 | ### [Production Demo](https://gatsby-wordpress-netlify-production.netlify.com/)
22 | ### [Stage Demo](https://gatsby-wordpress-netlify-stage.netlify.com/)
23 |
24 | ## Getting Started
25 | 1. Fork Gatsby WordPress Netlify
26 | 2. Clone your forked repository
27 | 3. `npm install --global gatsby-cli` (if you don't have Gatsby CLI installed)
28 | 4. In the root of your project yarn install
29 | 5. Open your `gatsby-config.js` file and change the baseUrl to your WordPress url
30 | 6. Run `yarn develop` -- _not_ `gatsby develop`
31 |
32 | ### Netlify
33 | _Signup for a Netlify account if you don't already have one._
34 |
35 | 1. Create a new site
36 | 2. Select "GitHub" from "Continuous Deployment"
37 | 3. Search and select your repository
38 | 4. Click "show advanced"
39 | 5. Click "new variable"
40 | 6. Add a deploy key DEPLOY_ENV with a value of lbn_published_stage
41 | 7. Click "deploy site"
42 | 8. Under Settings > Build & Deploy click "add build hook"
43 | 9. Name something that signifies environment (stage or production)
44 | 10. (Optional) Click "site options" and then "change site name". Rename to something that signifies this is the environment (stage or production).
45 | 11. (Optional) Repeat the process above a second time to create a production environment. Change the DEPLOY_ENV to lbn_published_production Optionally rename accordingly.
46 |
47 | ### Install WordPress
48 | Install WordPress on the server of your choice or use an existing site. I recommend a stripped down theme with no front end like this. For example, this site uses [http://gatsbynetliflydemo.justinwhall.com/wp-json/](http://gatsbynetliflydemo.justinwhall.com/wp-json/) for its data source. which is no more than a stripped down _s theme.
49 |
50 | ### Install WP Buildhook Deploy plugin (Optional. Can be used without this if you don't care about building on publish.)
51 |
52 | 1. Download or clone the [WP Buildhook Deploy plugin](https://github.com/justinwhall/littlebot-netlify) and install on your source WordPress site.
53 | 2. Find your build hooks on Netlify **Settings > Build & Deploy**
54 | 3. Add build hooks to your WordPress install under **WP Admin > Settings > WP BuildHook Deploy**
55 |
56 | ### Publish!
57 |
58 | Support for Gutenberg out of the box. If you are using the classic editor, the default "Publish" metabox has been replaced with:
59 |
60 |
61 |
62 | If you update or publish a post with an environment checked, your post will be published to that environment. Likewise, if you update/publish with an environment unchecked, A post will be removed from that environment. For example, if you uncheck both environments and update, the post will be removed from both. If you publish/update with both environments checked, the post will be published to both.
63 |
64 | ### Example:
65 |
66 | Using this starter requires configuring the gatsby-config.js file. You really only need to change BaseUrl, and hostingWPCOM if you're using WP.com rather than WP.org
67 |
68 | ```javascript
69 | {
70 | resolve: 'gatsby-source-wordpress',
71 | options: {
72 | // The base url to your WP site.
73 | baseUrl: 'YOUR_WORDPRESS_URL',
74 | // WP.com sites set to true, WP.org set to false
75 | hostingWPCOM: false,
76 | // The protocol. This can be http or https.
77 | protocol: 'http',
78 | // Use 'Advanced Custom Fields' Wordpress plugin
79 | useACF: true,
80 | auth: {},
81 | // Set to true to debug endpoints on 'gatsby build'
82 | verboseOutput: false
83 | }
84 | },
85 | ```
86 |
87 | * Update GraphQL queries to match your WordPress Content. This is the query currently on the index page. You either need to add ACF's in your WordPress to match the query (in this case Project and Date), or you need to remove those aspects of the query. The featured_media isn't a problem -- it'll work even if you have posts without featured images.
88 |
89 | ```javascript
90 | allWordpressPost {
91 | edges {
92 | node {
93 | featured_media {
94 | source_url
95 | }
96 | author {
97 | name
98 | avatar_urls {
99 | wordpress_24
100 | wordpress_48
101 | wordpress_96
102 | }
103 | }
104 | date
105 | slug
106 | title
107 | modified
108 | excerpt
109 | id
110 | acf {
111 | project
112 | date
113 | }
114 | categories {
115 | name
116 | }
117 | tags {
118 | name
119 | }
120 | content
121 | }
122 | }
123 | }
124 | ```
125 |
126 | * Finally, you'll probably want to update the SiteConfig to match your info, because right now it has mine. 🤠
127 |
128 |
--------------------------------------------------------------------------------
/content/assets/gatsby-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justinwhall/gatsby-wordpress-netlify-starter/4f02159aec32f0fab54069765f60d0154d7713a6/content/assets/gatsby-icon.png
--------------------------------------------------------------------------------
/content/assets/profile-pic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justinwhall/gatsby-wordpress-netlify-starter/4f02159aec32f0fab54069765f60d0154d7713a6/content/assets/profile-pic.png
--------------------------------------------------------------------------------
/content/blog/hello-world/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Hello World
3 | date: "2015-05-01T22:12:03.284Z"
4 | ---
5 |
6 | This is my first post on my new fake blog! How exciting!
7 |
8 | I'm sure I'll write a lot more interesting things in the future.
9 |
10 | Oh, and here's a great quote from this Wikipedia on
11 | [salted duck eggs](http://en.wikipedia.org/wiki/Salted_duck_egg).
12 |
13 | > A salted duck egg is a Chinese preserved food product made by soaking duck
14 | > eggs in brine, or packing each egg in damp, salted charcoal. In Asian
15 | > supermarkets, these eggs are sometimes sold covered in a thick layer of salted
16 | > charcoal paste. The eggs may also be sold with the salted paste removed,
17 | > wrapped in plastic, and vacuum packed. From the salt curing process, the
18 | > salted duck eggs have a briny aroma, a gelatin-like egg white and a
19 | > firm-textured, round yolk that is bright orange-red in color.
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/content/blog/hello-world/salty_egg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justinwhall/gatsby-wordpress-netlify-starter/4f02159aec32f0fab54069765f60d0154d7713a6/content/blog/hello-world/salty_egg.jpg
--------------------------------------------------------------------------------
/content/blog/hi-folks/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: New Beginnings
3 | date: "2015-05-28T22:40:32.169Z"
4 | description: This is a custom description for SEO and Open Graph purposes, rather than the default generated excerpt. Simply add a description field to the frontmatter.
5 | ---
6 |
7 | Far far away, behind the word mountains, far from the countries Vokalia and
8 | Consonantia, there live the blind texts. Separated they live in Bookmarksgrove
9 | right at the coast of the Semantics, a large language ocean. A small river named
10 | Duden flows by their place and supplies it with the necessary regelialia.
11 |
12 | ## On deer horse aboard tritely yikes and much
13 |
14 | The Big Oxmox advised her not to do so, because there were thousands of bad
15 | Commas, wild Question Marks and devious Semikoli, but the Little Blind Text
16 | didn’t listen. She packed her seven versalia, put her initial into the belt and
17 | made herself on the way.
18 |
19 | - This however showed weasel
20 | - Well uncritical so misled
21 | - this is very interesting
22 | - Goodness much until that fluid owl
23 |
24 | When she reached the first hills of the **Italic Mountains**, she had a last
25 | view back on the skyline of her hometown _Bookmarksgrove_, the headline of
26 | [Alphabet Village](http://google.com) and the subline of her own road, the Line
27 | Lane. Pityful a rethoric question ran over her cheek, then she continued her
28 | way. On her way she met a copy.
29 |
30 | ### Overlaid the jeepers uselessly much excluding
31 |
32 | But nothing the copy said could convince her and so it didn’t take long until a
33 | few insidious Copy Writers ambushed her, made her drunk with
34 | [Longe and Parole](http://google.com) and dragged her into their agency, where
35 | they abused her for their projects again and again. And if she hasn’t been
36 | rewritten, then they are still using her.
37 |
38 | > Far far away, behind the word mountains, far from the countries Vokalia and
39 | > Consonantia, there live the blind texts. Separated they live in Bookmarksgrove
40 | > right at the coast of the Semantics, a large language ocean.
41 |
42 | It is a paradisematic country, in which roasted parts of sentences fly into your
43 | mouth. Even the all-powerful Pointing has no control about the blind texts it is
44 | an almost unorthographic life One day however a small line of blind text by the
45 | name of Lorem Ipsum decided to leave for the far World of Grammar.
46 |
47 | ### According a funnily until pre-set or arrogant well cheerful
48 |
49 | The Big Oxmox advised her not to do so, because there were thousands of bad
50 | Commas, wild Question Marks and devious Semikoli, but the Little Blind Text
51 | didn’t listen. She packed her seven versalia, put her initial into the belt and
52 | made herself on the way.
53 |
54 | 1. So baboon this
55 | 2. Mounted militant weasel gregariously admonishingly straightly hey
56 | 3. Dear foresaw hungry and much some overhung
57 | 4. Rash opossum less because less some amid besides yikes jeepers frenetic
58 | impassive fruitlessly shut
59 |
60 | When she reached the first hills of the Italic Mountains, she had a last view
61 | back on the skyline of her hometown Bookmarksgrove, the headline of Alphabet
62 | Village and the subline of her own road, the Line Lane. Pityful a rethoric
63 | question ran over her cheek, then she continued her way. On her way she met a
64 | copy.
65 |
66 | > The copy warned the Little Blind Text, that where it came from it would have
67 | > been rewritten a thousand times and everything that was left from its origin
68 | > would be the word "and" and the Little Blind Text should turn around and
69 | > return to its own, safe country.
70 |
71 | But nothing the copy said could convince her and so it didn’t take long until a
72 | few insidious Copy Writers ambushed her, made her drunk with Longe and Parole
73 | and dragged her into their agency, where they abused her for their projects
74 | again and again. And if she hasn’t been rewritten, then they are still using
75 | her. Far far away, behind the word mountains, far from the countries Vokalia and
76 | Consonantia, there live the blind texts.
77 |
78 | #### Silent delightfully including because before one up barring chameleon
79 |
80 | Separated they live in Bookmarksgrove right at the coast of the Semantics, a
81 | large language ocean. A small river named Duden flows by their place and
82 | supplies it with the necessary regelialia. It is a paradisematic country, in
83 | which roasted parts of sentences fly into your mouth.
84 |
85 | Even the all-powerful Pointing has no control about the blind texts it is an
86 | almost unorthographic life One day however a small line of blind text by the
87 | name of Lorem Ipsum decided to leave for the far World of Grammar. The Big Oxmox
88 | advised her not to do so, because there were thousands of bad Commas, wild
89 | Question Marks and devious Semikoli, but the Little Blind Text didn’t listen.
90 |
91 | ##### Wherever far wow thus a squirrel raccoon jeez jaguar this from along
92 |
93 | She packed her seven versalia, put her initial into the belt and made herself on
94 | the way. When she reached the first hills of the Italic Mountains, she had a
95 | last view back on the skyline of her hometown Bookmarksgrove, the headline of
96 | Alphabet Village and the subline of her own road, the Line Lane. Pityful a
97 | rethoric question ran over her cheek, then she continued her way. On her way she
98 | met a copy.
99 |
100 | ###### Slapped cozy a that lightheartedly and far
101 |
102 | The copy warned the Little Blind Text, that where it came from it would have
103 | been rewritten a thousand times and everything that was left from its origin
104 | would be the word "and" and the Little Blind Text should turn around and return
105 | to its own, safe country. But nothing the copy said could convince her and so it
106 | didn’t take long until a few insidious Copy Writers ambushed her, made her drunk
107 | with Longe and Parole and dragged her into their agency, where they abused her
108 | for their projects again and again.
109 |
--------------------------------------------------------------------------------
/content/blog/my-second-post/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: My Second Post!
3 | date: "2015-05-06T23:46:37.121Z"
4 | ---
5 |
6 | Wow! I love blogging so much already.
7 |
8 | Did you know that "despite its name, salted duck eggs can also be made from
9 | chicken eggs, though the taste and texture will be somewhat different, and the
10 | egg yolk will be less rich."?
11 | ([Wikipedia Link](http://en.wikipedia.org/wiki/Salted_duck_egg))
12 |
13 | Yeah, I didn't either.
14 |
--------------------------------------------------------------------------------
/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | // custom typefaces
2 | import "typeface-montserrat"
3 | import "typeface-merriweather"
4 |
--------------------------------------------------------------------------------
/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | siteMetadata: {
3 | title: `WordPress Gatsby Starter`,
4 | author: `Justin W Hall`,
5 | description: `A Gatsby WordPress Starter with special love for Netlify`,
6 | siteUrl: `https://gatsby-wordpress-netlify-production.netlify.com`,
7 | social: {
8 | twitter: `justinwhall`,
9 | },
10 | postPrefix : '/blog',
11 | pagePrefix: '',
12 | },
13 | plugins: [
14 | {
15 | resolve: `gatsby-source-filesystem`,
16 | options: {
17 | path: `${__dirname}/content/blog`,
18 | name: `blog`,
19 | },
20 | },
21 | {
22 | resolve: `gatsby-source-filesystem`,
23 | options: {
24 | path: `${__dirname}/content/assets`,
25 | name: `assets`,
26 | },
27 | },
28 | {
29 | resolve: 'gatsby-source-wordpress',
30 | options: {
31 | // The base url to your WP site.
32 | baseUrl: 'gatsbynetliflydemo.justinwhall.com',
33 | // baseUrl: 'data.justinwhall.com',
34 | // baseUrl: 'wpgatsby.wtf',
35 | // WP.com sites set to true, WP.org set to false
36 | hostingWPCOM: false,
37 | // The protocol. This can be http or https.
38 | protocol: 'https',
39 | // Use 'Advanced Custom Fields' Wordpress plugin
40 | useACF: false,
41 | auth: {},
42 | // Set to true to debug endpoints on 'gatsby build'
43 | verboseOutput: true,
44 | excludedRoutes: [
45 | "/*/*/comments",
46 | "/yoast/**",
47 | "/oembed/*"
48 | ],
49 | normalizer: function({ entities }) {
50 | return entities
51 | },
52 | }
53 | },
54 | `gatsby-transformer-sharp`,
55 | `gatsby-plugin-sharp`,
56 | {
57 | resolve: `gatsby-plugin-google-analytics`,
58 | options: {
59 | //trackingId: `ADD YOUR TRACKING ID HERE`,
60 | },
61 | },
62 | `gatsby-plugin-offline`,
63 | `gatsby-plugin-react-helmet`,
64 | {
65 | resolve: `gatsby-plugin-typography`,
66 | options: {
67 | pathToConfigModule: `src/utils/typography`,
68 | },
69 | },
70 | ],
71 | }
72 |
--------------------------------------------------------------------------------
/gatsby-node.js:
--------------------------------------------------------------------------------
1 | const DEPLOY_ENV = process.env.DEPLOY_ENV || 'lbn_published_production';
2 |
3 | /**
4 | * Generate node edges
5 | *
6 | * @param {any} { node, actions, getNode }
7 | */
8 | exports.onCreateNode = ({ node, actions }) => {
9 | const { createNodeField } = actions;
10 |
11 | /**
12 | * If these don't exist, the LBN WordPress Plugin isn't installed – so build all posts.
13 | */
14 | if (
15 | !Object.prototype.hasOwnProperty.call(node, 'meta') ||
16 | !Object.prototype.hasOwnProperty.call(node.meta, 'lbn_published_production')
17 | ) {
18 | createNodeField({ node, name: 'deploy', value: true });
19 | return;
20 | }
21 |
22 | let deploy;
23 |
24 | if (node.meta[DEPLOY_ENV]) {
25 | deploy = true;
26 | } else {
27 | deploy = false;
28 | }
29 |
30 | createNodeField({ node, name: 'deploy', value: deploy });
31 | };
32 |
33 |
34 | const createPosts = require('./gatsby/createPosts');
35 | const createPages = require('./gatsby/createPages');
36 | const createCategories = require('./gatsby/createCategories');
37 |
38 | exports.createPages = async ({ actions, graphql }) => {
39 | await createPosts({ actions, graphql });
40 | await createPages({ actions, graphql });
41 | await createCategories({ actions, graphql });
42 | }
--------------------------------------------------------------------------------
/gatsby/createCategories.js:
--------------------------------------------------------------------------------
1 |
2 | const _ = require(`lodash`)
3 | const path = require(`path`)
4 |
5 | /**
6 | * Create WordPress Category Pages
7 | */
8 | module.exports = async ({ actions, graphql }) => {
9 |
10 | const { createPage } = actions
11 | const categoriesTemplate = path.resolve(`./src/templates/category.js`)
12 |
13 | return graphql(
14 | `
15 | {
16 | allWordpressCategory {
17 | edges {
18 | node {
19 | id
20 | link
21 | path
22 | name
23 | count
24 | slug
25 | }
26 | }
27 | }
28 | }
29 | `
30 | ).then(result => {
31 | if (result.errors) {
32 | throw result.errors
33 | }
34 |
35 | const categories = result.data.allWordpressCategory.edges;
36 | categories.forEach(cat => {
37 | createPage({
38 | path: `/category/${cat.node.slug}/`,
39 | component: categoriesTemplate,
40 | context: {
41 | slug: cat.node.slug,
42 | name: cat.node.name,
43 | }
44 | })
45 | })
46 |
47 | // ==== END POSTS ====
48 | return null
49 | })
50 | }
--------------------------------------------------------------------------------
/gatsby/createPages.js:
--------------------------------------------------------------------------------
1 | const path = require(`path`);
2 |
3 | /**
4 | * Create WordPress Posts
5 | */
6 | module.exports = async ({ actions, graphql }) => {
7 |
8 | const { createPage } = actions;
9 | const postTemplate = path.resolve(`./src/templates/page.js`);
10 |
11 | return graphql(
12 | `
13 | {
14 | site {
15 | siteMetadata {
16 | pagePrefix
17 | }
18 | }
19 | allWordpressPage {
20 | edges {
21 | node {
22 | id
23 | slug
24 | fields {
25 | deploy
26 | }
27 | }
28 | }
29 | }
30 | }
31 | `
32 | ).then(result => {
33 | if (result.errors) {
34 | throw result.errors
35 | }
36 |
37 | const { pagePrefix } = result.data.site.siteMetadata;
38 | const { edges } = result.data.allWordpressPage;
39 |
40 | edges.forEach( edge => {
41 | if (edge.node.fields.deploy) {
42 | createPage({
43 | path: `${pagePrefix}/${edge.node.slug}`,
44 | component: postTemplate,
45 | context: {
46 | id: edge.node.id,
47 | }
48 | })
49 | }
50 | })
51 | // ==== END POSTS ====
52 | return null;
53 | })
54 | }
--------------------------------------------------------------------------------
/gatsby/createPosts.js:
--------------------------------------------------------------------------------
1 |
2 | const path = require(`path`);
3 |
4 | /**
5 | * Create WordPress Posts
6 | */
7 | module.exports = async ({ actions, graphql }) => {
8 |
9 | const { createPage } = actions;
10 | const postTemplate = path.resolve(`./src/templates/post.js`);
11 |
12 | return graphql(
13 | `
14 | {
15 | site {
16 | siteMetadata {
17 | postPrefix
18 | }
19 | }
20 | allWordpressPost {
21 | edges {
22 | node {
23 | id
24 | slug
25 | modified
26 | categories {
27 | name
28 | }
29 | fields {
30 | deploy
31 | }
32 | }
33 | }
34 | }
35 | }
36 | `
37 | ).then(result => {
38 | if (result.errors) {
39 | throw result.errors
40 | }
41 |
42 | const { postPrefix } = result.data.site.siteMetadata;
43 | const { edges } = result.data.allWordpressPost;
44 |
45 | edges.forEach( edge => {
46 | if (edge.node.fields.deploy) {
47 | createPage({
48 | path: `${postPrefix}/${edge.node.slug}`,
49 | component: postTemplate,
50 | context: {
51 | id: edge.node.id,
52 | }
53 | })
54 | }
55 | })
56 | // ==== END POSTS ====
57 | return null;
58 | })
59 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gatsby-wordpress-netlify-starter",
3 | "description": "A starter for a blog powered by Gatsby and Markdown",
4 | "version": "2.0.0",
5 | "author": "Justin W Hall",
6 | "keywords": [
7 | "gatsby"
8 | ],
9 | "license": "MIT",
10 | "main": "n/a",
11 | "repository": {
12 | "type": "git",
13 | "url": "git@github.com:justinwhall/gatsby-wordpress-netlify-starter.git"
14 | },
15 | "scripts": {
16 | "develop": "DEPLOY_ENV=lbn_published_production gatsby develop",
17 | "build": "gatsby build",
18 | "develop": "gatsby develop",
19 | "format": "prettier --write src/**/*.{js,jsx}",
20 | "start": "npm run develop",
21 | "serve": "gatsby serve"
22 | },
23 | "dependencies": {
24 | "gatsby": "^2.8.5",
25 | "gatsby-image": "^2.1.2",
26 | "gatsby-plugin-feed": "^2.2.2",
27 | "gatsby-plugin-google-analytics": "^2.0.20",
28 | "gatsby-plugin-manifest": "^2.1.1",
29 | "gatsby-plugin-offline": "^2.1.1",
30 | "gatsby-plugin-react-helmet": "^3.0.12",
31 | "gatsby-plugin-sharp": "^2.1.3",
32 | "gatsby-plugin-typography": "^2.2.13",
33 | "gatsby-remark-copy-linked-files": "^2.0.13",
34 | "gatsby-remark-images": "^3.0.14",
35 | "gatsby-remark-prismjs": "^3.2.10",
36 | "gatsby-remark-responsive-iframe": "^2.1.1",
37 | "gatsby-remark-smartypants": "^2.0.9",
38 | "gatsby-source-filesystem": "^2.0.38",
39 | "gatsby-source-wordpress": "^3.0.64",
40 | "gatsby-transformer-remark": "^2.3.12",
41 | "gatsby-transformer-sharp": "^2.1.21",
42 | "lodash": "^4.17.11",
43 | "prismjs": "^1.16.0",
44 | "react": "^16.8.6",
45 | "react-dom": "^16.8.6",
46 | "react-helmet": "^5.2.1",
47 | "react-typography": "^0.16.19",
48 | "typeface-merriweather": "0.0.72",
49 | "typeface-montserrat": "0.0.54",
50 | "typography": "^0.16.19",
51 | "typography-theme-wordpress-2016": "^0.16.19"
52 | },
53 | "devDependencies": {
54 | "prettier": "^1.18.0",
55 | "cli-glob": "^0.1.0",
56 | "eslint": "^3.19.0",
57 | "eslint-config-airbnb": "^15.0.2",
58 | "eslint-config-prettier": "^2.9.0",
59 | "eslint-plugin-import": "^2.8.0",
60 | "eslint-plugin-jsx-a11y": "^5.1.1",
61 | "eslint-plugin-react": "^7.5.1",
62 | "gh-pages": "^1.1.0",
63 | "remark-cli": "^4.0.0",
64 | "remark-preset-lint-recommended": "^3.0.1",
65 | "stylefmt": "^6.0.0",
66 | "stylelint": "^8.4.0",
67 | "stylelint-config-standard": "^18.0.0"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/components/bio.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Bio component that queries for data
3 | * with Gatsby's StaticQuery component
4 | *
5 | * See: https://www.gatsbyjs.org/docs/static-query/
6 | */
7 |
8 | import React from "react"
9 | import { StaticQuery, graphql } from "gatsby"
10 | import Image from "gatsby-image"
11 |
12 | import { rhythm } from "../utils/typography"
13 |
14 | function Bio() {
15 | return (
16 | {
19 | const { author, social } = data.site.siteMetadata
20 | return (
21 |