Accordion

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus euismod augue dolor, id ultrices dui molestie et. Mauris sodales tellus a hendrerit volutpat. Nam et sapien commodo, porttitor lacus sit amet, euismod sapien. Nam accumsan et quam et vestibulum. Praesent vestibulum odio ipsum, vel porta arcu tincidunt sit amet. Curabitur rhoncus magna arcu, eget auctor…

  • Test accordion

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.

  • lorem ipsum

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.

  • lorem

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.

  • Lorem ipsum dolor sit amet

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas velit ante, lobortis porttitor semper eget, tempor et lacus. Curabitur nec justo ut turpis rhoncus tristique.

block.json

{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "wlc/accordion",
    "title": "Accordion",
    "category": "text",
    "icon": "editor-justify",
    "description": "Accordion",
    "keywords": [ "accordion", "wrapper" ],
    "allowedBlocks": [ "wlc/accordion-item" ],
    "version": "1.0.0",
    "textdomain": "WLC",
    "editorScript": "file:./index.js",
    "viewScript": "file:/view.js",
    "style": "file:./style-index.css",
    "render": "file:./render.php"
  }

edit.js

import { 
    useBlockProps,
    useInnerBlocksProps,
    BlockControls,
    Inserter
  } from '@wordpress/block-editor';
import { 
    Toolbar,
    Button
  } from  '@wordpress/components';

const edit = (props) => {
  const blockProps = useBlockProps();
  const { children, ...innerBlocksProps} = useInnerBlocksProps(
    blockProps,
    {
      allowedBlocks: [ "wlc/accordion-item" ]
    }
  );

  function AccordionAppender( { rootClientId } ) {
    return (
        <Inserter
            rootClientId={ rootClientId }
            renderToggle={ ( { onToggle, disabled } ) => (
                <Button
                    className="accordion-appender"
                    onClick={ onToggle }
                    disabled={ disabled }
                    label="Add a item"
                    icon="plus"
                />
            ) }
            isAppender
        />
    );
}

  return(
    <div {...useBlockProps()}>
      <BlockControls>
        <Toolbar label="Options">
          <AccordionAppender rootClientId={ props.clientId } />
        </Toolbar>
      </BlockControls>
      <div {...innerBlocksProps} className='wlc-accordion__wrapper'>
        <ul className="wlc-accordion__list">
        {children}
        </ul>
      </div>
    </div>
  );
}

export default edit;

index.js

import { registerBlockType } from "@wordpress/blocks";
import metadata from './block.json';
import save from "./save";
import edit from './edit';
import './style.css';


registerBlockType( metadata, {
    edit: edit,
    save: save,
});

render.php

<?php
/**
 * Renders the html of accordion block
 *
 * @package wlc/accordion-block
 */

?>
<div class="wlc-accordion__wrapper">
	<ul class="wlc-accordion__list">
		<?php echo wp_kses_post( $content ); ?>
	</ul>
</div>

save.js

import { InnerBlocks } from "@wordpress/block-editor";

const save = (props) => {
	return <InnerBlocks.Content />;
}

export default save;

style.css

  
  .wlc-accordion__wrapper {
    & .wlc-accordion__list {
      @apply flex flex-col gap-2;
    }
  
    & .wlc-accordion__item {
      @apply relative px-6 py-4 grid grid-rows-[auto_0fr] border border-[#ccc] transition-all [.block-editor_&]:grid-rows-[auto_1fr] [&.open]:grid-rows-[auto_1fr] cursor-pointer;
      @apply before:absolute before:content-icon-minus before:top-6 before:right-6 before:left-auto before:w-6 before:h-6 before:opacity-0 before:transition-opacity;
      @apply after:absolute after:content-icon-plus after:top-6 after:right-6 after:w-6 after:h-6 after:transition-opacity;
  
      &.open {
        &::before {
          @apply opacity-100;
        }
  
        &::after {
          @apply opacity-0;
        }
      }
    }
  
    & .wlc-accordion__title {
      @apply font-bold;
    }
  
    & .wlc-accordion__content {
      @apply overflow-hidden;
  
      & > div {
        @apply mt-4;
      }
  
      & p {
        @apply last:mb-0;
      }
    }
  }

view.js

function wlcAccorddion() {

    // Each all accordions
    [...document.querySelectorAll('.wlc-accordion__wrapper')]?.forEach( accordion => {
  
      // Each all wlc-accordion accordion
      [...accordion.querySelectorAll('.wlc-accordion__item')]?.forEach( items => {
  
        // wlc-accordion item click
        items.addEventListener('click', function() {
  
          // Check if the clicked wlc-accordion item is already open
          if (this.classList.contains('open')) {
            // If it's open, just close it
            this.classList.remove('open');
          } else {
            // If it's not open, close all others and open this one
  
            // wlc-accordion accordion remove class on click
            [...accordion.querySelectorAll('.wlc-accordion__item')]?.forEach( otheritems => {
              otheritems.classList.remove('open');
            })
  
            // wlc-accordion item add class on click
            this.classList.add('open');
          }
        })
      })
    })
  }
  
  document.addEventListener( 'DOMContentLoaded', function() {
    wlcAccorddion();
  });