├── .editorconfig ├── .eleventy.js ├── .eleventyignore ├── .env.example ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .npmignore ├── README.md ├── _includes └── base.njk ├── changelog.md ├── config ├── index.js └── queries.js ├── demo ├── .eleventy.js ├── package.json └── src │ ├── _includes │ └── base.njk │ ├── index.njk │ └── page.njk ├── package.json └── src ├── articles.js ├── collections.js ├── pages.js ├── products.js └── shop.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | max_line_length = 80 15 | -------------------------------------------------------------------------------- /.eleventy.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | const getShopInfo = require('./src/shop'); 4 | const getAllProducts = require('./src/products'); 5 | const getAllCollections = require('./src/collections'); 6 | const getAllPages = require('./src/pages'); 7 | const getAllArticles = require('./src/articles'); 8 | 9 | const defaultConfig = require("./config"); 10 | 11 | const getShopifyContent = async (config) => { 12 | // defaultConfig is a standard config file with the default queries assigned 13 | // anything that the user changes overwrites the default config 14 | // the result from this overwriting is the below shopifyConfig variable 15 | const shopifyConfig = Object.assign(defaultConfig, config); 16 | 17 | console.log(chalk.yellow.bold(`SHOPIFY:GETTING SHOP INFO`)) 18 | console.log(chalk.yellow.bold(`SHOPIFY:GETTING PRODUCTS`)) 19 | console.log(chalk.yellow.bold(`SHOPIFY:GETTING COLLECTIONS`)) 20 | console.log(chalk.yellow.bold(`SHOPIFY:GETTING PAGES`)) 21 | console.log(chalk.yellow.bold(`SHOPIFY:GETTING ARTICLES`)) 22 | 23 | const shop = await getShopInfo(shopifyConfig.shopQuery); 24 | const products = await getAllProducts(shopifyConfig.productsQuery); 25 | const collections = await getAllCollections(shopifyConfig.collectionsQuery); 26 | const pages = await getAllPages(shopifyConfig.pagesQuery); 27 | const articles = await getAllArticles(shopifyConfig.articlesQuery); 28 | 29 | console.log(chalk.greenBright.bold(`SHOPIFY:SUCCESSFULLY RETRIEVED ${shop.name.toUpperCase()} INFO`)) 30 | console.log(chalk.greenBright.bold(`SHOPIFY:SUCCESSFULLY RETRIEVED ${products.length} PRODUCT${products.length > 1 || products.length == 0 ? 'S' : ''}`)) 31 | console.log(chalk.greenBright.bold(`SHOPIFY:SUCCESSFULLY RETRIEVED ${collections.length} COLLECTIONS`)) 32 | console.log(chalk.greenBright.bold(`SHOPIFY:SUCCESSFULLY RETRIEVED ${pages.length} PAGE${pages.length > 1 || pages.length == 0 ? 'S' : ''}`)) 33 | console.log(chalk.greenBright.bold(`SHOPIFY:SUCCESSFULLY RETRIEVED ${articles.length} ARTICLE${articles.length > 1 || articles.length == 0 ? 'S' : ''}`)) 34 | 35 | console.log(chalk.yellow.bold(`SHOPIFY:MAPPING PRODUCTS TO COLLECTIONS`)) 36 | 37 | collections.map(collection => { 38 | if (collection.products.length > 0) { 39 | return collection.products.map(collectionProduct => { 40 | const foundProduct = products.find(product => { 41 | return product.id === collectionProduct.id 42 | }) 43 | return foundProduct 44 | }) 45 | } else { 46 | return collection 47 | } 48 | }) 49 | 50 | console.log(chalk.greenBright.bold(`SHOPIFY:SUCCESSFULLY MAPPED PRODUCTS TO COLLECTIONS`)) 51 | 52 | return { 53 | shop: shop, 54 | products: products, 55 | collections: collections, 56 | pages: pages, 57 | articles: articles, 58 | }; 59 | }; 60 | 61 | module.exports = (eleventyConfig, pluginConfig) => { 62 | eleventyConfig.addGlobalData( 63 | "shopify", 64 | async () => await getShopifyContent(pluginConfig || {}) 65 | ); 66 | }; 67 | -------------------------------------------------------------------------------- /.eleventyignore: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | SHOPIFY_STORE_URL=*.myshopify.com 2 | SHOPIFY_ACCESS_TOKEN= 3 | SHOPIFY_API_VERSION=2021-07 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | _site 3 | package-lock.json 4 | .env 5 | .DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | index.md 2 | _includes 3 | _site -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eleventy-plugin-shopify 2 | 3 | [![npm version](https://badge.fury.io/js/eleventy-plugin-shopify.svg)](https://badge.fury.io/js/eleventy-plugin-shopify) 4 | 5 | Import your [Shopify](https://www.shopify.com/?ref=permalight-nyc) products, pages, and collections into [Eleventy](https://11ty.dev/) as global data. 6 | 7 | [View the demo site](https://eleventy-plugin-shopify-demo.netlify.app/) 8 | 9 | ## Installation 10 | 11 | 1. Install plugin using npm: 12 | 13 | ``` 14 | npm install eleventy-plugin-shopify 15 | ``` 16 | 17 | 2. Add plugin to your `.eleventy.js` config, ensuring to add your Shopify url and a Storefront API key. Check out the Shopify docs for [how to create a Storefront API key](https://shopify.dev/api/storefront/getting-started): 18 | 19 | You may also pass through your own graphql queries for products, collections, pages, and articles. Check out the [graphiql storefront explorer](https://shopify.dev/custom-storefronts/tools/graphiql-storefront-api) to test queries. You may have to adjust the queries based on cost and size of the store. 20 | 21 | ```js 22 | const pluginShopify = require("eleventy-plugin-shopify"); 23 | 24 | require("dotenv").config(); 25 | 26 | const { SHOPIFY_STORE_URL, SHOPIFY_ACCESS_TOKEN, SHOPIFY_API_VERSION } = 27 | process.env; 28 | 29 | module.exports = (eleventyConfig) => { 30 | eleventyConfig.addPlugin(pluginShopify, { 31 | url: SHOPIFY_STORE_URL, 32 | key: SHOPIFY_ACCESS_TOKEN, 33 | version: SHOPIFY_API_VERSION, 34 | // optional: shopQuery, productsQuery, collectionsQuery, pagesQuery, articlesQuery 35 | }); 36 | }; 37 | ``` 38 | 39 | The example above is using `dotenv` with a `.env` file to ensure credentials are **not** stored in the source code. Here's an example of the `.env` file: 40 | 41 | ```text 42 | SHOPIFY_STORE_URL=*.myshopify.com 43 | SHOPIFY_ACCESS_TOKEN= 44 | SHOPIFY_API_VERSION=2021-10 45 | ``` 46 | 47 | ## Usage 48 | 49 | ## API 50 | 51 | - `shopify.shop`: A tool for accessing the shop name and URL 52 | - `shopify.products`: An array of all products in Shopify 53 | - `shopify.articles`: An array of all articles in Shopify 54 | - `shopify.pages`: An array of all pages in Shopify 55 | - `shopify.collections`: An array of all collections in Shopify 56 | 57 | ## Development 58 | 59 | 1. Create a `.env` file inside of `demo` with the following credentials: 60 | 61 | ```text 62 | SHOPIFY_STORE_URL=*.myshopify.com 63 | SHOPIFY_ACCESS_TOKEN= 64 | SHOPIFY_API_VERSION=2021-07 65 | ``` 66 | 67 | 2. Amend the `.eleventy.js` file within `demo` so it points to the source code in the parent directory: 68 | 69 | #### When developing locally 70 | 71 | ```js 72 | const pluginShopify = require("../"); 73 | // const pluginShopify = require("eleventy-plugin-shopify"); 74 | ``` 75 | 76 | #### When using npm file 77 | 78 | ```js 79 | // const pluginShopify = require("../"); 80 | const pluginShopify = require("eleventy-plugin-shopify"); 81 | ``` 82 | 83 | 3. Install development dependencies (in root): 84 | 85 | ```text 86 | npm install 87 | ``` 88 | 89 | 4. Install the demo dependencies (in ./demo): 90 | 91 | ```text 92 | cd demo 93 | npm install 94 | ``` 95 | 96 | 5. Run the demo locally: 97 | ```text 98 | npm run dev 99 | ``` 100 | 101 | # Gotchas 102 | 103 | Beware of the `page` keyword when adding a layout for your shopify pages. In the demo we've called this `spage` 104 | -------------------------------------------------------------------------------- /_includes/base.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Eleventy Shopify Plugin Test Page 8 | 9 | 10 | {{ content | safe }} 11 | 12 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # 0.0.5 2 | 3 | - Refactor pagination for large catalogs 4 | - Gets products and then maps those products to collections by ID 5 | 6 | # 0.0.4 7 | 8 | - Proof of concept 9 | - Added queries and config for different stores 10 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const productsQuery = require("./queries").productsQuery; 2 | const collectionsQuery = require("./queries").collectionsQuery; 3 | const pagesQuery = require("./queries").pagesQuery; 4 | const articlesQuery = require("./queries").articlesQuery; 5 | const shopQuery = require("./queries").shopQuery; 6 | 7 | require("dotenv").config(); 8 | 9 | const { SHOPIFY_STORE_URL, SHOPIFY_ACCESS_TOKEN, SHOPIFY_API_VERSION } = process.env; 10 | 11 | const config = { 12 | url: SHOPIFY_STORE_URL, 13 | key: SHOPIFY_ACCESS_TOKEN, 14 | version: SHOPIFY_API_VERSION, 15 | endpoint: `https://${SHOPIFY_STORE_URL}/api/${SHOPIFY_API_VERSION}/graphql.json`, 16 | headers: { 17 | 'X-Shopify-Storefront-Access-Token': SHOPIFY_ACCESS_TOKEN, 18 | 'Content-Type': 'application/graphql' 19 | }, 20 | shopQuery, 21 | productsQuery, 22 | collectionsQuery, 23 | pagesQuery, 24 | articlesQuery, 25 | }; 26 | 27 | module.exports = config; 28 | -------------------------------------------------------------------------------- /config/queries.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | productsQuery: (cursor = null) => ` 3 | query { 4 | products(first: 50, sortKey: CREATED_AT${cursor ? `, after: "${cursor}"` : ``}) { 5 | edges { 6 | cursor 7 | node { 8 | id 9 | title 10 | handle 11 | } 12 | } 13 | } 14 | }`, 15 | collectionsQuery: (cursor = null) => ` 16 | query { 17 | collections(first:20${cursor ? `, after: "${cursor}"` : ``}) { 18 | edges { 19 | cursor 20 | node { 21 | title 22 | handle 23 | descriptionHtml 24 | products(first: 250) { 25 | edges { 26 | node { 27 | id 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | }`, 35 | pagesQuery: (cursor = null) => ` 36 | query { 37 | pages(first:50, sortKey: TITLE${cursor ? `, after: "${cursor}"` : ``}) { 38 | edges { 39 | cursor 40 | node{ 41 | id 42 | title 43 | updatedAt 44 | handle 45 | body 46 | seo { 47 | title 48 | description 49 | } 50 | } 51 | } 52 | } 53 | }`, 54 | articlesQuery: (cursor = null) => ` 55 | query { 56 | articles(first:50${cursor ? `, after: "${cursor}"` : ``}) { 57 | edges { 58 | cursor 59 | node { 60 | id 61 | handle 62 | title 63 | publishedAt 64 | contentHtml 65 | tags 66 | image { 67 | originalSrc 68 | altText 69 | } 70 | publishedAt 71 | seo { 72 | title 73 | description 74 | } 75 | } 76 | } 77 | } 78 | }`, 79 | shopQuery: () => ` 80 | query { 81 | shop { 82 | name 83 | description 84 | moneyFormat 85 | privacyPolicy { 86 | title 87 | body 88 | handle 89 | } 90 | refundPolicy { 91 | title 92 | body 93 | handle 94 | } 95 | shippingPolicy { 96 | title 97 | body 98 | handle 99 | } 100 | termsOfService { 101 | title 102 | body 103 | handle 104 | } 105 | paymentSettings{ 106 | currencyCode 107 | } 108 | primaryDomain { 109 | url 110 | } 111 | } 112 | }`, 113 | } 114 | -------------------------------------------------------------------------------- /demo/.eleventy.js: -------------------------------------------------------------------------------- 1 | // const pluginShopify = require("../"); // For local development 2 | 3 | const pluginShopify = require("eleventy-plugin-shopify"); 4 | 5 | require("dotenv").config(); 6 | 7 | const { SHOPIFY_STORE_URL, SHOPIFY_ACCESS_TOKEN, SHOPIFY_API_VERSION } = process.env; 8 | 9 | module.exports = (eleventyConfig) => { 10 | eleventyConfig.addPlugin(pluginShopify, { 11 | url: SHOPIFY_STORE_URL, 12 | key: SHOPIFY_ACCESS_TOKEN, 13 | version: SHOPIFY_API_VERSION, 14 | }); 15 | return { 16 | htmlTemplateEngine: 'njk', 17 | dir: { 18 | input: 'src' 19 | }, 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "eleventy --serve", 4 | "build": "eleventy" 5 | }, 6 | "dependencies": { 7 | "@11ty/eleventy": "^2.0.0", 8 | "dotenv": "^10.0.0", 9 | "eleventy-plugin-shopify": "^0.0.5" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo/src/_includes/base.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ title + " | " }}Eleventy Shopify Demo 9 | 15 | 16 | 17 | {{shopify.shop.name}} 18 | {{ content | safe }} 19 | {#

The Eleventy Shopify plugin was made by Dan Leatherman in Brooklyn, NY. Demo hosted on Netlify. View the code on Github.

#} 20 | 21 | 22 | -------------------------------------------------------------------------------- /demo/src/index.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base.njk 3 | title: Eleventy Shopify 4 | --- 5 | 6 | {% if shopify.products.length > 0 %} 7 |

Products

8 | 13 | {% endif %} 14 | 15 | {% if shopify.collections.length > 0 %} 16 |

Collections

17 | 22 | {% endif %} 23 | 24 |

Pages

25 | 30 | 31 |

Articles

32 | 37 | -------------------------------------------------------------------------------- /demo/src/page.njk: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base.njk 3 | title: Eleventy Shopify 4 | --- 5 | 6 | {% if shopify.products.length > 0 %} 7 |

Products

8 | 13 | {% endif %} 14 | 15 | {% if shopify.collections.length > 0 %} 16 |

Collections

17 | 22 | {% endif %} 23 | 24 |

Pages

25 | 30 | 31 |

Articles

32 | 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eleventy-plugin-shopify", 3 | "version": "0.1.0", 4 | "description": "An eleventy plugin to pull in Shopify Data", 5 | "main": ".eleventy.js", 6 | "scripts": { 7 | "start": "eleventy --serve", 8 | "build": "eleventy", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/dleatherman/eleventy-plugin-shopify.git" 14 | }, 15 | "keywords": [ 16 | "11ty", 17 | "11ty-plugin", 18 | "eleventy", 19 | "eleventy-plugin" 20 | ], 21 | "author": "Dan Leatherman", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/dleatherman/eleventy-plugin-shopify/issues" 25 | }, 26 | "homepage": "https://github.com/dleatherman/eleventy-plugin-shopify#readme", 27 | "dependencies": { 28 | "chalk": "^4.1.2", 29 | "node-fetch-cache": "^3.0.3" 30 | }, 31 | "devDependencies": { 32 | "@11ty/eleventy": "^2.0.0", 33 | "dotenv": "^10.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/articles.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch-cache') 2 | 3 | const config = require('../config') 4 | const { articlesQuery } = require('../config/queries') 5 | 6 | let allArticles = []; 7 | 8 | async function getArticles(query = articlesQuery, cursor = null, previousArticles = []) { 9 | if (previousArticles.length > 0) { 10 | allArticles = [...previousArticles]; 11 | } 12 | const response = await fetch(config.endpoint, { 13 | method: 'post', 14 | body: query(cursor), 15 | headers: config.headers 16 | }) 17 | const res = await response.json() 18 | const articles = res.data.articles.edges 19 | try { 20 | await getArticles(query, articles[articles.length - 1].cursor, [...articles]) 21 | } catch (error) { 22 | return allArticles 23 | } 24 | } 25 | 26 | async function getAllArticles(query) { 27 | const articles = await getArticles(query); 28 | return allArticles.map((article) => { 29 | return article.node; 30 | }); 31 | } 32 | 33 | module.exports = getAllArticles 34 | -------------------------------------------------------------------------------- /src/collections.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch-cache') 2 | 3 | const config = require('../config') 4 | const { collectionsQuery } = require('../config/queries') 5 | 6 | let allCollections = []; 7 | 8 | async function getCollections(query = collectionsQuery, cursor = null, previousCollections = []) { 9 | if (previousCollections.length > 0) { 10 | allCollections = [...previousCollections]; 11 | } 12 | const response = await fetch(config.endpoint, { 13 | method: 'post', 14 | body: query(cursor), 15 | headers: config.headers 16 | }) 17 | const res = await response.json() 18 | const collections = res.data.collections.edges 19 | try { 20 | await getCollections(query, collections[collections.length - 1].cursor, [...collections]) 21 | } catch (error) { 22 | return allCollections 23 | } 24 | } 25 | 26 | async function getAllCollections(query) { 27 | let collections = await getCollections(query); 28 | return allCollections.map((collection) => { 29 | // collection.node.products = collection.node.products.edges.map(product => { 30 | // return product.node 31 | // }) 32 | return collection.node 33 | }) 34 | } 35 | 36 | module.exports = getAllCollections 37 | -------------------------------------------------------------------------------- /src/pages.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch-cache') 2 | 3 | const config = require('../config') 4 | const { pagesQuery } = require('../config/queries') 5 | 6 | let allPages = []; 7 | 8 | async function getPages(query = pagesQuery, cursor = null, previousPages = []) { 9 | if (previousPages.length > 0) { 10 | allPages = [...previousPages]; 11 | } 12 | const response = await fetch(config.endpoint, { 13 | method: 'post', 14 | body: query(cursor), 15 | headers: config.headers 16 | }) 17 | const res = await response.json() 18 | const pages = res.data.pages.edges 19 | try { 20 | await getPages(query, pages[pages.length - 1].cursor, [...pages]) 21 | } catch (error) { 22 | return allPages 23 | } 24 | } 25 | 26 | async function getAllPages(query) { 27 | let pages = await getPages(query); 28 | return allPages.map((page) => { 29 | return page.node; 30 | }); 31 | } 32 | 33 | module.exports = getAllPages 34 | -------------------------------------------------------------------------------- /src/products.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch-cache') 2 | 3 | const config = require('../config') 4 | const { productsQuery } = require('../config/queries') 5 | 6 | let allProducts = []; 7 | 8 | async function getProducts(query = productsQuery, cursor = null, previousProducts = []) { 9 | if (previousProducts.length > 0) { 10 | allProducts = [...previousProducts]; 11 | } 12 | const response = await fetch(config.endpoint, { 13 | method: 'post', 14 | body: query(cursor), 15 | headers: config.headers 16 | }) 17 | const res = await response.json() 18 | const products = res.data.products.edges 19 | try { 20 | await getProducts(query, products[products.length - 1].cursor, [...products]) 21 | } catch (error) { 22 | return allProducts 23 | } 24 | } 25 | 26 | async function getAllProducts(query) { 27 | const products = await getProducts(query); 28 | return allProducts.map((product) => { 29 | return product.node; 30 | }); 31 | } 32 | 33 | module.exports = getAllProducts 34 | -------------------------------------------------------------------------------- /src/shop.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch-cache'); 2 | 3 | const config = require('../config') 4 | const { shopQuery } = require('../config/queries') 5 | 6 | async function getShopInfo(query = shopQuery) { 7 | const response = await fetch(config.endpoint, { 8 | method: 'post', 9 | body: query(), 10 | headers: config.headers 11 | }) 12 | const res = await response.json() 13 | const shop = res.data.shop 14 | return shop 15 | } 16 | 17 | module.exports = getShopInfo 18 | --------------------------------------------------------------------------------