A plugin for Strapi CMS that adds a preview button and live view button to the content manager edit view.

Overview
Logo for Strapi preview button plugin

Strapi Preview Button

A plugin for Strapi CMS that adds a preview button and live view button to the content manager edit view.

Screenshot for Strapi preview button plugin

Get Started

Features

  • New button in content manager sidebar which links the user to a preview or live view of a frontend app view.
  • Customize which content types should use the preview button.
  • Customize endpoints for draft and published URLs.
  • Support collection and single types.

💎 Installation

yarn add strapi-plugin-preview-button@latest

🚨 Requirements

Include the following variables in your application's .env file.

STRAPI_PREVIEW_SECRET=YOURSECRET
STRAPI_PREVIEW_DRAFT_URL=https://example.com/api/preview
STRAPI_PREVIEW_PUBLISHED_URL=https://example.com

You must generate your own secret key to use for STRAPI_PREVIEW_SECRET which will also be given to the frontend app later.

Draft and publish mode

With draftAndPublish mode enabled for a content type, a preview button will render when the entry is in a draft state while a live view button will render when it is in a published state.

It is not required to enable draftAndPublish for content types using this plugin. The live view button will still display to conveniently redirect a user to the live version of the page.

🔧 Configuration

property type (default) description
contentTypes array ([]) An array of objects describing which content types should use the preview button.

contentTypes

An array of objects describing which content types should use the preview button.

Each object in the array requires a uid prop at minimum. If you are configuring a collection type, the targetField is also required but it is optional with single types. The field name "slug" is recommended for the targetField value because it represents the unique part of the URL path, but it is not required.

Collection type example

Consider we have Page and Post content types, where each has a uid field named slug and entries created for each, with the slug values set to my-page and my-post. Here is the minimum required config.

module.exports = {
  'preview-button': {
    enabled: true,
    config: {
      contentTypes: [
        {
          uid: 'api::page.page',
          targetField: 'slug',
        },
        {
          uid: 'api::post.post',
          targetField: 'slug',
        },
      ],
    },
  },
};

In this example, our pages and posts will be routed differently in our frontend app. To help with this, props like basePath and query may be configured for variations between draft and published URLs.

module.exports = {
  'preview-button': {
    enabled: true,
    config: {
      contentTypes: [
        {
          uid: 'api::page.page',
          targetField: 'slug',
        },
        {
          uid: 'api::post.post',
          targetField: 'slug',
          draft: {
            query: {
              type: 'post',
            },
          },
          published: {
            basePath: 'blog',
          },
        },
      ],
    },
  },
};

This configuration will result in the following preview URLs for Page and Post. Notice in the URLs below how env vars and config settings work together to build the final URLs.

Draft URL paths
https://example.com/api/preview?slug=my-page&secret=YOURSECRET
https://example.com/api/preview?slug=my-post&type=post&secret=YOURSECRET
Published URL paths
https://example.com/my-page
https://example.com/blog/my-post

Single type example

Consider we have an About single type to serve as our "About" page. Unlike collection types, we don't necessarily need an editable targetField with our model if we know for sure it will always be /about. You can still provide the targetField if you want to keep this value editable in Strapi.

module.exports = {
  'preview-button': {
    enabled: true,
    config: {
      contentTypes: [
        {
          uid: 'api::about.about',
          draft: {
            query: {
              slug: 'about',
            },
          },
          published: {
            basePath: 'about',
          },
        },
      ],
    },
  },
};

This configuration will result in the following preview URLs for About.

Draft URL path
https://example.com/api/preview?slug=aboute&secret=YOURSECRET
Published URL path
https://example.com/about

📘 User Guide

How does this work with my frontend app?

The Open live view button will lead directly to the live page URL.

The Open draft preview button should lead to an endpoint that redirects to the appropriate preview page based on the query parameters passed to it.

Before granting access to the preview, the values for STRAPI_PREVIEW_SECRET should be compared and validated between both Strapi and the frontend app.

For in-depth examples and instructions, please reference the links below to learn how this can be accomplished with Next.js and Strapi.

Comments
  • Support multiple targetFields (or locale support)

    Support multiple targetFields (or locale support)

    I'm working on a project with i18n, where it would be useful to provide a locale to the preview URL in addition to a slug.

    I wonder if it might be helpful for others if the targetField option could support more than one field which is included for the front-end query - in my case it would be slug and locale - so that a config such as this:

    'preview-button': {
      enabled: true,
      config: {
        contentTypes: [
          {
            uid: 'api::page.page',
            targetField: ['slug', 'locale'],
          },
        ],
      },
    },
    

    would result in a URL: http://example.com/api/preview?slug=your-page&locale=en&secret=YOURSECRET

    request 
    opened by zrothauser 11
  • Can't get the button to show

    Can't get the button to show

    The button is not showing, I have an article type, and I have added the following to the plugins file

    module.exports = ({ env }) => ({
      ...,
      "preview-button": {
        enabled: true,
        config: {
          contentTypes: [
            {
              uid: "api::article.article",
              targetField: "slug",
              draft: {
                query: {
                  type: "article",
                },
              },
              published: {
                basePath: "articles",
              },
            },
          ],
        },
      },
      ...,
    });
    

    Is there anything else I'm missing?

    opened by mengqing 8
  • Documentation could be more accurate on some points

    Documentation could be more accurate on some points

    Hi, great plugin 👍, easygoing instructions, but maybe you should precise a couple of things, as some of us are just starting out with v4 (I struggled with these at first):

    • Precise the configuration snippet has to be place inside a plugin.js file under the config folder.
    • Precise we have to rebuild the admin first before seeing changes (you used the development mode from your screenshot, but it’s likely we’ll just use the normal dev mode).
    • Precise we need to toggle the publicationState API parameter to preview when querying the content, otherwise, the draft will never be part of the response.
    opened by lansolo99 8
  • Autoupdate preview-URL, when slug-field is changed

    Autoupdate preview-URL, when slug-field is changed

    Thank you very much for this great plugin! I encountert one small inconvenience: I pass a slug-field to the preview-URL. When I change the slug, the preview-URL is not updated immediately. The user has to reload the page, that the preview-URL gets updated.

    Is there a way to fix this?

    opened by AndreasFaust 7
  • [Feature] Preview button in List View

    [Feature] Preview button in List View

    Hello,

    Thanks for this plugin currently working in Strapi 4.

    I would like to know if is possible to show the preview button(with an eye icon for example) and how can we do that. image

    If it is not an available feature, I would like to suggest reviewing this plugin which supports this feature but is not migrated to version four.

    Thank you

    request 
    opened by SalahAdDin 6
  • Button not display for single-types

    Button not display for single-types

    Hey folks! I have the plugin installed here is my package.json :

    "dependencies": { "@strapi/plugin-i18n": "4.3.2", "@strapi/plugin-users-permissions": "4.3.2", "@strapi/strapi": "4.3.2", "better-sqlite3": "7.4.6", "dotenv": "^16.0.1", "find-config": "^1.0.0", "mysql": "^2.18.1", "strapi-plugin-preview-button": "^0.3.5" },

    and I added the following configuration in ./config/plugins.js

    module.exports = { 'preview-button': { config: { contentTypes: [ { uid: 'api::home-page.home-page' } ] } } }

    But the button in never display. Do i miss something in the de docs ?

    bug 
    opened by WebMamba 5
  • npm install error (peer dependency conflict)

    npm install error (peer dependency conflict)

    npm install error

    image

    versions

    Strapi: 4.4.0 node: v16.17.0 npm: 8.15.0

    reproduction

    • npx create-strapi-app@latest my-project --quickstart
    • npm i strapi-plugin-preview-button@latest

    workaround

    Yes, using the --force flag on install

    opened by samzlab 4
  • Added option to use different target fields based on draft or publish mode

    Added option to use different target fields based on draft or publish mode

    Hello, nice?

    Well, i`m working in a project that i have a really specificied necessity: use different target fields for publish and draft content types. I have this necessity because im using this plugin: https://market.strapi.io/plugins/@notum-cz-strapi-plugin-content-versioning that basiclly do what his name propose. For my user get the preview page based on DRAFT the content that he is seeing, I have to use the id property to know what page to show for my user, but if he is seeing the PUBLISHED page, i have to use the slug property because my url seems like this "https://domain/[slug]", not "https://domain/[id]".When a use the preview mode, I can use the id of my data to get the preview and than redirect to the page based on the slug, like this:

    import StrapiAPI from "../../services/strapi";
    
    export default async function preview(req, res) {
      if (req.query.secret !== process.env.STRAPI_PREVIEW_SECRET || !req.query.id) {
        return res.status(401).json({ message: "Invalid token" });
      }
    
      const page = await StrapiAPI.getPreviewProductPage(req.query.id);
    
      if (!page) {
        return res.status(401).json({ message: "Invalid slug" });
      }
    
      res.setPreviewData({ id: page.id });
    
      res.writeHead(307, { Location: `/${page.slug}` });
      res.end();
    }
    

    but when I use the live published mode, I am not able to do this.

    What do yout think about it? Thanks

    feature 
    opened by CaioGrossi 4
  • Nothing appears to show on strapi 4.4.5

    Nothing appears to show on strapi 4.4.5

    Nothing appears to show on the content manager view for Example Blog when I have the following added to plugins,ts. Am I missing an installation step?

     "preview-button": {
          config: {
            contentTypes: [
              {
                uid: "api::example-blog.example-blog",
                draft: {
                  url: "http://localhost:1337/api/preview",
                  query: {
                    type: "post",
                    id: "{slug}",
                  },
                }
              },
            ],
          },
        },
    
    opened by cherring07 3
  • When a value is unset, the URL retains the un-interpolated variable with curly brackets

    When a value is unset, the URL retains the un-interpolated variable with curly brackets

    In this use case, I'm using a "page" content type, and the site's Home page is the only page to have an empty slug. When previewing other pages with slugs set, everything works as expected, but when trying to preview the homepage, the created URL path is /en/{slug} (or /en/%7Bslug%7D after the browser's URL encoding).

    Maybe the default for an empty variable such as the slug should be to interpolate the query URL with an empty string?

    Here is my config:

    'preview-button': {
      enabled: true,
      config: {
        contentTypes: [
          {
            uid: 'api::page.page',
            draft: {
              url: env('STRAPI_PREVIEW_DRAFT_URL'),
              query: {
                type: 'page',
                slug: '{slug}',
                secret: env('STRAPI_PREVIEW_SECRET'),
                locale: '{locale}',
              },
            },
            published: {
              url: `${env('STRAPI_PREVIEW_PUBLISHED_URL')}/{locale}/{slug}`,
            },
          },
        ],
      },
    }
    
    request 
    opened by zrothauser 3
  • Open preview page in new tab, instead of replacing already opened tab

    Open preview page in new tab, instead of replacing already opened tab

    Is it possible to add possibility to open 'preview' page always in new tab (not just replace the opened tab)?

    I think we can remove (or make optional) the target prop (PREVIEW_WINDOW_NAME) in window.open( url, PREVIEW_WINDOW_NAME );

    Code: https://github.com/mattmilburn/strapi-plugin-preview-button/blob/staging/admin/src/components/PreviewButton/index.js#L19

    request 
    opened by Krak86 3
  • Preview button not appearing if you extend the plugin with async code

    Preview button not appearing if you extend the plugin with async code

    Hello! I could not extend the plugin with the async code using the new "plugin/preview-button/before-build-url" hook.

    Sync code works perfectly fine, but Strapi currently returns a minimal amount of fields for the relations. So to overcome that, we need to fetch particular fields of relations. If I add async code, the URL returned within the hook is correct but Live View button doesn't show on the admin FE. I have briefly checked the plugin admin code and the URL is returned as "undefined" assume because it's not ready to handle async code.

    Here is the implementation:

     // ...
      bootstrap(app) {
        app.registerHook("plugin/preview-button/before-build-url", async ({ state, data }) => {
          const url = await parseUrlRelation(state, data);
    
          return {
            state: {
              ...state,
              url,
            },
          };
        });
      },
     // ...
    

    And in "parseUrlRelation":

    const parseUrlRelation = async (config, data) => {
      // ...
    
      for (const relation of relations) {
        // ...
        
        // get relations data and modify url
        const entity = await request(`/get-my-relation-data`, {
          fields: [field]
        });
        url = url.replace(relation, entity[field]);
      }
    
      return url;
    };
    

    Am I missing something or new hook just can't handle it? If so, any idea how to achieve that? Thanks!

    opened by bskuratov 0
  • Preview button in list is not working after logging in

    Preview button in list is not working after logging in

    When you first time entering admin page before logging in request to admin API to get config is sent but because it has 'admin::isAuthenticatedAdmin' it crashes and so we are not getting any data (because on login page we're actually still not admin). That's why when you enter list page pluginConfig is empty and additional column is not showing.

    bug 
    opened by not-vainglorious 2
  • Content Manager stuck at specify URL and the UI crashed

    Content Manager stuck at specify URL and the UI crashed

    I encounter this at random when I turn on the plugin. After disabling and reload the content editor, there is a popup "An error occurred". Anyone encountered this before?

    Screenshot 2022-10-27 at 3 29 06 PM Screenshot 2022-10-27 at 3 31 19 PM

    opened by karg-betacode 1
  • Ability to generate url (or parts of it) when the button is clicked

    Ability to generate url (or parts of it) when the button is clicked

    Currently urls for posts are pre-generated. By allowing the generation of the url (or parts of it) it would be possible to create more secure preview urls. The static key solution suggested in the docs is problematic for larger deployments, once the key leaked it have to be rotated, and rotation requires the Strapi instance to be restarted. This not only painful to manage, but it is impossible to track when the key is leaked so it have to be rotated on a timely basis. Generating tokens on demand would be a lot more secure, because you could use time based algorithms (JWT for example).

    This would also open up other possibilities, for having custom logic determining the preview url.

    I'm thinking for something similar:

          // ...
          'preview-button': {
            config: {
              contentTypes: [
                {
                  uid: 'api::post.post',
                  draft: {
                    url: 'https://my-preview-solution.tld/{slug}',
                    query: {
                      token: function() {
                        return generateToken();
                      }
                    },
                  },
                },
              ],
            },
          },
          // ...
    

    The button's onClick handler could check if the provided url is callable. If yes, it should call it and use the return value as the url. (Promises or something similar would be even better).

    I'm not very familiar JavaScript so please forgive me for my inaccuracies.

    question 
    opened by marcsello 2
  • no preview button and only showing live button

    no preview button and only showing live button

    here is my code

    'preview-button': {
        config: {
          enabled: true,
          // injectListViewColumn: false,
          contentTypes: [
            {
              uid: 'api::home.home',
              draft: {
                url: 'http://localhost:6001/{locale}/posts/{slug}',
                query: {
                  type: 'home',
                  locale: '{locale}',
                  slug: '{slug}',
                },
              },
              published: {
                url: 'http://localhost:3000',
              },
            },
            {
              uid: 'api::post.post',
              draft: {
                url: 'http://localhost:6001/{locale}/posts/{slug}',
                query: {
                  type: 'post',
                  locale: '{locale}',
                  slug: '{slug}',
                },
              },
              published: {
                url: 'http://localhost:6001/{locale}/posts/{slug}',
                copy: true,
              },
            },
          ],
        },
      },
    

    but i'm not able to see any draft (preview. button) but it's only showing copylink and live button. Is there anything i'm missing now?

    opened by sr1k3sh 1
Releases(v1.1.1)
  • v1.1.1(Dec 23, 2022)

    💅🏻 Enhancements

    • Add plugin/preview-button/before-build-url hook too allow modifying the config options before building the preview URL.

    ⚙️ Chore

    • Add "Extending" section to the README.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Dec 21, 2022)

    ⚙️ Chore

    • Bump peer dependencies for Strapi to v4.5.3.
    • Bump peer dependencies for Strapi design system to v1.4.0.
    • Bump node engines versions to >=14.19.1 <=18.x.x.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Nov 17, 2022)

    🐛 Bug fixes

    • Fix issue where preview URL does not update after saving with new slug value.

    💅🏻 Enhancements

    • Add openTarget config option to allow opening multiple tabs instead of re-using the same tab.
    • Replace unmatched vars in URL templates with empty string instead of ignoring them.

    ⚙️ Chore

    • Add explanation of openTarget option to the README.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Sep 27, 2022)

    💥 Breaking Changes! 💥

    Please see the Migrations Guide to keep your preview button plugin up-to-date.

    • Refactor how the plugin is configured for draft and published URLs.
    • Environment vars are no longer required, but can still be used.
    • New feature to map values from an entry's data into the preview URLs.
    • Refactor admin so preview URLs do not need to be queried from the API.
    • Introduce copy link button below the preview button, which can be disabled.
    • Add preview and copy buttons to content manager list view.
    Source code(tar.gz)
    Source code(zip)
  • v0.3.6(Aug 17, 2022)

    🐛 Bug fixes

    • Fix bug where single types would return null if they were in draft state or have draftAndPublish disabled - https://github.com/mattmilburn/strapi-plugin-preview-button/issues/40
    Source code(tar.gz)
    Source code(zip)
  • v0.3.5(Aug 1, 2022)

  • v0.3.4(Aug 1, 2022)

    Consider this the first official stable release for this plugin.

    💅🏻 Enhancements

    • Add Japanese translations

    🐛 Bug Fixes

    • Refactor usePreviewData hook so it executes during each render
    • Correction to French translation
    Source code(tar.gz)
    Source code(zip)
Owner
Matt Milburn
Things with HTML, CSS and JavaScript.
Matt Milburn
A plugin for Strapi Headless CMS that provides ability to sign-in/sign-up to an application by link had sent to email.

Strapi PasswordLess Plugin A plugin for Strapi Headless CMS that provides ability to sign-in/sign-up to an application by link had sent to email. A pl

Andrey Kucherenko 51 Dec 12, 2022
A plugin for Strapi Headless CMS that provides the ability to transform the API request or response.

strapi-plugin-transformer A plugin for Strapi that provides the ability to transform the API request and/or response. Requirements The installation re

daedalus 71 Jan 6, 2023
A plugin for Obsidian (https://obsidian.md) that adds a button to its search view for copying the Obsidian search URL.

Copy Search URL This plugin adds a button to Obsidian's search view. Clicking it will copy the Obsidian URL for the current search to the clipboard. T

Carlo Zottmann 6 Dec 26, 2022
A plugin for Strapi that provides the ability to easily schedule publishing and unpublishing of any content type

strapi-plugin-publisher A plugin for Strapi that provides the ability to easily schedule publishing and unpublishing of any content type. Requirements

daedalus 19 Dec 7, 2022
A plugin for Strapi that provides the ability to auto slugify a field for any content type

strapi-plugin-slugify A plugin for Strapi that provides the ability to auto slugify a field for any content type. It also provides a findOne by slug e

daedalus 25 Nov 28, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Codebraid Preview provides a Markdown preview for Pandoc documents within VS Code.

Codebraid Preview provides a Markdown preview for Pandoc documents within VS Code. Most Markdown previews don't support all of Pandoc's extensions to Markdown syntax. Codebraid Preview supports 100% of Pandoc features—because the preview is generated by Pandoc itself! There is also full bidirectional scroll sync and document export.

Geoffrey Poore 12 Dec 28, 2022
Get an isolated preview database for every Netlify Preview Deployment

Netlify Preview Database Plugin Create an isolated preview database for each preview deployment in Netlify Quickstart • Website • Docs • Discord • Twi

Snaplet 10 Nov 16, 2022
💄 An app to create, edit, and preview HDR environment maps in the browser

Environment Map Light Editor Create, edit, and preview HDR environment maps in the browser. Preview your models in realtime and export lightmaps to us

Poimandres 30 Dec 30, 2022
A Technical Blogging Website that utilizes Notion as a CMS for ease of modification with the help of the notion-API & whose content has been rendered with next-js and react-notion-x

GDSC MCE Blogs This repo is what GDSC MCE uses to power their blogging website gdsc-mce-blogs. It uses Notion as a CMS, fetching content from Notion a

null 7 Dec 16, 2022
Update & Revalidate Content from a Headless CMS in Next.js with Incremental Static Regeneration

Update & Revalidate Content from a Headless CMS in Next.js with Incremental Static Regeneration Demo for tutorial How to Update & Revalidate Content f

Colby Fayock 4 Jul 22, 2022
Create Bootstrap 5 Modal Box using JavaScript with custom title, description, button labels and custom YES button callback

Dynamic BS5 Modal Box Create Bootstrap 5 Modal Box using JavaScript with custom title, description, button labels and custom YES button callback Insta

null 5 Oct 23, 2022
Strapi V4 Plugin to schedule publish and depublish actions

Strapi plugin scheduler This plugin allows you to publish and depublish collection types in the future. There are a couple of steps necessary to get t

Webbio 12 Nov 24, 2022
Basic types & utilities for Strapi v4 and plugin creators

Strapi v4 - Types & utilities Basic set of types and utilities for Strapi v4 and plugins creators A developers goodie for Strapi Headless CMS which pr

 VirtusLab Open-Source 7 Oct 14, 2022
A custom Chakra UI component that adds ready-made styles for rendering remote HTML content.

Chakra UI Prose Prose is a Chakra UI component that adds a ready-made typography styles when rendering remote HTML. Installation yarn add @nikolovlaza

Lazar Nikolov 50 Jan 3, 2023
A jQuery plugin that works in harmony with animate.css in order to enable animations only when content comes into view.

jQuery AniView A jQuery plugin that works in harmony with animate.css in order to enable animations only when content comes into view. Now supports v4

Jonathan James Cosgrove 216 Sep 10, 2022