Skip to content

Replacing wysiwyg editor with a custom one doesn't work in Strapi 5 #2374

@maruthasalamr

Description

@maruthasalamr

Node Version

v18.20.2

NPM/Yarn/PNPM Version

10.5.0

Strapi Version

5.5.1

Operating System

MacOS

Database

PostgreSQL

Javascript or Typescript

Javascript

Reproduction URL

No response

Bug Description

While replacing the default wysiwyg editor with a custom plugin ckEditor in strapi v5 facing challenges and cannot able see the custom field in content type builder using addFields adding the custom field to replace the existing richtext. When i try to register as a plugin it's working and i can able to add as custom field but i want to replace the existing or default wysiwyg editor. I was using same code in strapi v4 it's working fine.

Steps to Reproduce

1.Update to strapi v4 to v5

Image

Expected Behavior

I need to replace the existing wysiwyg editor with CKEditor5 in strapi version 5

Image

Logs

Code Snippets

plugins/wysiwyg/src/admin/components/index.jsx

Import React, { useState } from 'react';
import { Button, Stack, Flex, Field, FieldLabel, FieldError } from '@strapi/design-system';
import { useLibrary, prefixFileUrlWithBackendUrl } from '@strapi/helper-plugin';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import './ck-editor.wse.css';

const Wysiwyg = ({ name, onChange, value, required, error, type }) => {
  const [showMediaLibDialog, setShowMediaLibDialog] = useState(false);
  const { components } = useLibrary();
  const MediaLibDialog = components['media-library'];

  const handleToggleMediaLibDialog = () => {
    setShowMediaLibDialog(!showMediaLibDialog);
  };

  const handleSelectAssets = (files) => {
    const formattedFiles = files.map((file) => ({
      alt: file.alternativeText || file.name,
      url: prefixFileUrlWithBackendUrl(file.url),
      mime: file.mime,
    }));
    const images = formattedFiles.map((image) => `<image src='${image.url}' alt='${image.alt}'>`).join();
    onChange({
      target: {
        name: name,
        value: (value || '') + images,
      },
    });
    handleToggleMediaLibDialog();
  };

  return (
    <div>
      <Field name={name} error={error}>
        <Button variant="secondary" onClick={handleToggleMediaLibDialog}>
          MediaLib
        </Button>
        <Stack size={2} padding={2}>
          <Flex>
            <FieldLabel required={required}>{name}</FieldLabel>
          </Flex>
          <div className={error ? 'error-active' : ''}>
            <CKEditor
              id={name}
              config={{
                toolbar: {
                  removeItems: ['uploadImage', 'outdent', 'indent'],
                  shouldNotGroupWhenFull: false,
                },
                link: {
                  decorators: {
                    isExternal: {
                      mode: 'manual',
                      label: 'Open in a new tab',
                      defaultValue: true,
                      value: true,
                      attributes: {
                        target: '_blank'
                      }
                    },
                    canFollow: {
                      mode: 'manual',
                      label: 'No Follow',
                      defaultValue: true,
                      value: true,
                      attributes: {
                        rel: 'nofollow noreferrer noopener'
                      }
                    }
                  }
                },
                contentsCss: './ck-editor.wse.css',
              }}
              name={name}
              editor={ClassicEditor}
              value={value}
              data={value}
              errors={error}
              onChange={(_, editor) => {
                onChange({ target: { name: name, type: type, value: editor.getData() } });
              }}
            />
          </div>
          <FieldError />
        </Stack>
        {showMediaLibDialog && (
          <MediaLibDialog onClose={handleToggleMediaLibDialog} onSelectAssets={handleSelectAssets} />
        )}
      </Field>
    </div>
  );
};

export default Wysiwyg;

plugins/wysiwyg/src/index.js

import pluginPkg from '../../package.json';
import Wysiwyg from './components/Wysiwyg';
import pluginId from './pluginId';
import Initializer from "./components/Initializer";


const name = pluginPkg.strapi.name;

export default {
  register(app) {
    console.log("app",app)
       app.addFields({ type: 'wysiwyg', Component: Wysiwyg });

    app.registerPlugin({
      id: pluginId,
      initializer: Initializer,
      isReady: true,
      name,
    });
    
       
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  bootstrap() {},
};

config/plugin.js

wysiwyg: {
    enabled: true,
    resolve: './src/plugins/wysiwyg', // path to plugin folder
  },

Media

No response

Additional information

No response

Confirmation Checklist

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions