DEV Community

vuejstest
vuejstest

Posted on

cms custom column task step by step

cmstheme
src
1.dataesolver
    CustomImageTextGalleryCmsElementResolver

<?php
declare(strict_types=1);

namespace CmsTheme\DataResolver;

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;
use Shopware\Core\Content\Media\MediaDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Content\Cms\DataResolver\FieldConfig;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
use Shopware\Core\Content\Cms\SalesChannel\Struct\ImageStruct;
use Shopware\Core\Content\Media\MediaEntity;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\Framework\Uuid\Uuid;

class CustomImageTextGalleryCmsElementResolver extends AbstractCmsElementResolver
{
    public function getType(): string
    {
        return 'buy-button';
    }

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $config = $slot->getFieldConfig();
        $imageConfig = $config->get('media');
        $backgroundImageConfig = $config->get('mobileMedia');

        $ids = [];
        if (!$imageConfig || $imageConfig->isMapped() || $imageConfig->getValue() === null) {
            //
        } else {
            array_push($ids, $imageConfig->getValue());
        }

        if (!$backgroundImageConfig || $backgroundImageConfig->isMapped() || $backgroundImageConfig->getValue() === null) {
            //
        } else {
            array_push($ids, $backgroundImageConfig->getValue());
        }

        if (count($ids) === 0) {
            return null;
        }

        $criteria = new Criteria($ids);

        $criteriaCollection = new CriteriaCollection();
        $criteriaCollection->add('media_' . $slot->getUniqueIdentifier(), MediaDefinition::class, $criteria);

        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $config = $slot->getFieldConfig();
        $data = new ArrayEntity();
        $data->setUniqueIdentifier(Uuid::randomHex());
        $slot->setData($data);

        $image = new ImageStruct();
        $backgroundImage = new ImageStruct();

        $imageConfig = $config->get('media');
        $backgroundImageConfig = $config->get('mobileMedia');

        if ($imageConfig && $imageConfig->getValue()) {
            $this->addMediaEntity($slot, $image, $result, $imageConfig, $resolverContext);
        }
        $data->set('media', $image);

        if ($backgroundImageConfig && $backgroundImageConfig->getValue()) {
            $this->addMediaEntity($slot, $backgroundImage, $result, $backgroundImageConfig, $resolverContext);
        }
        $data->set('mobileMedia', $backgroundImage);
    }

    private function addMediaEntity(
        CmsSlotEntity         $slot,
        ImageStruct           $image,
        ElementDataCollection $result,
        FieldConfig           $config,
        ResolverContext       $resolverContext
    ): void
    {
        if ($config->isMapped() && $resolverContext instanceof EntityResolverContext) {
            /** @var MediaEntity|null $media */
            $media = $this->resolveEntityValue($resolverContext->getEntity(), $config->getValue());

            if ($media !== null) {
                $image->setMediaId($media->getUniqueIdentifier());
                $image->setMedia($media);
            }
        }

        if ($config->isStatic()) {
            $image->setMediaId($config->getValue());

            $searchResult = $result->get('media_' . $slot->getUniqueIdentifier());
            if (!$searchResult) {
                return;
            }

            /** @var MediaEntity|null $media */
            $media = $searchResult->get($config->getValue());
            if (!$media) {
                return;
            }

            $image->setMedia($media);
        }
    }
}

2.res
app
    admin/src
    module/sw-cms
        blocks/text-image
            custom-image-text-gallery
component
index.js

import template from "./sw-cms-block-custom-image-text-gallery.html.twig";
import "./sw-cms-block-custom-image-text-gallery.scss";

Shopware.Component.register("sw-cms-block-custom-image-text-gallery", {
    template,

    compatConfig: Shopware.compatConfig,
});

twig

{% block sw_cms_block_custom_image_text_gallery %}
    <div class="sw-cms-block-image-text-gallery">
        <div class="sw-cms-block-image-text-gallery__left">
            <slot name="left-image"></slot>
            <slot name="left-text"></slot>
            <slot name="left-button"></slot>
        </div>
        <div class="sw-cms-block-image-text-gallery__center-left">
            <slot name="center-left-image"></slot>
            <slot name="center-left-text"></slot>
            <slot name="center-left-button"></slot>
        </div>
        <div class="sw-cms-block-image-text-gallery__center-right">
            <slot name="center-right-image"></slot>
            <slot name="center-right-text"></slot>
            <slot name="center-right-button"></slot>
        </div>
        <div class="sw-cms-block-image-text-gallery__right">
            <slot name="right-image"></slot>
            <slot name="right-text"></slot>
            <slot name="right-button"></slot>
        </div>
    </div>
{% endblock %}
scss

.sw-cms-block-image-text-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(195px, 1fr));
  align-content: stretch;
  align-items: start;
  grid-gap: 40px;

  .sw-cms-el-text {
    padding: 20px;
  }
  .sw-cms-el-image.is--cover {
    min-height: 20px;
  }
  .sw-cms-block-image-text-gallery__left,
  .sw-cms-block-image-text-gallery__center-left,
  .sw-cms-block-image-text-gallery__center-right,
  .sw-cms-block-image-text-gallery__right {
    box-shadow: 0 0 4px 0 rgba(0, 0, 0%, 20%);
  }
}
.sw-cms-block-image-text-gallery-shop-button {
  display: grid;
  align-items: center;
}

preview
index.js

import template from './sw-cms-preview-custom-image-text-gallery.html.twig';
import './sw-cms-preview-custom-image-text-gallery.scss';

Shopware.Component.register("sw-cms-preview-custom-image-text-gallery", {
    template,
    compatConfig: Shopware.compatConfig,
    computed: {
        assetFilter() {
            return Shopware.Filter.getByName('asset');
        },
    },
});

twig

{% block sw_cms_block_custom_image_text_gallery_preview %}
    <div class="sw-cms-preview-custom-image-text-gallery">
        <div class="sw-cms-preview-custom-image-text-gallery__left">
            <div class="sw-cms-preview-custom-image-text-gallery__image">
                <img :src="assetFilter('/administration/static/img/cms/preview_plant_small.jpg')" alt="">

            </div>
            <div class="sw-cms-preview-custom-image-text-gallery__text">
                <h2>block1</h2>
                <p>this is block1.</p>
            </div>
            <div class="sw-cms-slot sw-cms-slot-left-button">
                <div class="sw-cms-el-buy-button">
                    <div class="sw-cms-el-buy-button__actions">
                        <a class="sw-cms-el-buy-button__buy-action sw-button sw-button--small">Shop</a>
                    </div>
                </div>
                <div class="sw-cms-slot__preview-overlay"></div>
            </div>
        </div>

        <div class="sw-cms-preview-custom-image-text-gallery__center-left">
            <div class="sw-cms-preview-custom-image-text-gallery__image">
                <img :src="assetFilter('/administration/static/img/cms/preview_glasses_small.jpg')" alt="">
            </div>
            <div class="sw-cms-preview-custom-image-text-gallery__text">
                <h2>block2</h2>
                <p>this is block2</p>
            </div>
            <div class="sw-cms-slot sw-cms-slot-center-left-button">
                <div class="sw-cms-el-buy-button">
                    <div class="sw-cms-el-buy-button__actions">
                        <a class="sw-cms-el-buy-button__buy-action sw-button sw-button--small">Shop</a>
                    </div>
                </div>
                <div class="sw-cms-slot__preview-overlay"></div>
            </div>
        </div>

        <div class="sw-cms-preview-custom-image-text-gallery__center-right">
            <div class="sw-cms-preview-custom-image-text-gallery__image">
                <img :src="assetFilter('/administration/static/img/cms/preview_plant_small.jpg')" alt="">
            </div>
            <div class="sw-cms-preview-custom-image-text-gallery__text">
                <h2>block3</h2>
                <p>this is block3</p>
            </div>
            <div class="sw-cms-slot sw-cms-slot-center-right-button">
                <div class="sw-cms-el-buy-button">
                    <div class="sw-cms-el-buy-button__actions">
                        <a class="sw-cms-el-buy-button__buy-action sw-button sw-button--small">Shop</a>
                    </div>
                </div>
                <div class="sw-cms-slot__preview-overlay"></div>
            </div>
        </div>

        <div class="sw-cms-preview-custom-image-text-gallery__right">
            <div class="sw-cms-preview-custom-image-text-gallery__image">
                <img :src="assetFilter('/administration/static/img/cms/preview_camera_small.jpg')" alt="">
            </div>
            <div class="sw-cms-preview-custom-image-text-gallery__text">
                <h2>block4</h2>
                <p>this is block4</p>
            </div>
            <div class="sw-cms-slot sw-cms-slot-right-button">
                <div class="sw-cms-el-buy-button">
                    <div class="sw-cms-el-buy-button__actions">
                        <a class="sw-cms-el-buy-button__buy-action sw-button sw-button--small">Shop</a>
                    </div>
                </div>
                <div class="sw-cms-slot__preview-overlay"></div>
            </div>
        </div>
    </div>
{% endblock %}

scss

.sw-cms-preview-custom-image-text-gallery {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 10px;
  padding: 15px;

  .sw-cms-preview-custom-image-text-gallery__left,
  .sw-cms-preview-custom-image-text-gallery__center-left,
  .sw-cms-preview-custom-image-text-gallery__center-right,
  .sw-cms-preview-custom-image-text-gallery__right {
    box-shadow: 0 0 3px 0 rgba(0, 0, 0, 20%);
  }

  .sw-cms-preview-custom-image-text-gallery__image {
    height: 60px;
  }

  .sw-cms-preview-custom-image-text-gallery__text {
    padding: 8px;
    text-align: center;
  }

  img {
    display: block;
    object-fit: cover;
    width: 100%;
    height: 100%;
  }
}

.sw-cms-block-image-text-gallery-shop-button {
  display: grid;
  align-items: center;
  .sw-button {
    height: 30px;
    width: auto;
    padding: 25px;
  }
  .sw-cms-el-buy-button__buy-action{
    font-size: smaller;
  }
}

index.js

import CMS from '../../../constant/sw-cms.constant';
import "./preview";
import "./component";


Shopware.Service("cmsService").registerCmsBlock({
    name: "custom-image-text-gallery",
    label: "CMS image-text-button block",
    category: "text-image",
    component: "sw-cms-block-custom-image-text-gallery",
    previewComponent: "sw-cms-preview-custom-image-text-gallery",
    defaultConfig: {
        marginBottom: "20px",
        marginTop: "20px",
        marginLeft: "20px",
        marginRight: "20px",
        sizingMode: "boxed",
    },
    slots: {
        "left-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_plant_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "left-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block 1</h2>
              <p style="text-align: center;">this is block1</p>
            `.trim(),
                    },
                },
            },
        },
        "left-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },

        "center-left-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_glasses_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "center-left-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block2</h2>
              <p style="text-align: center;">this is block2</p>
            `.trim(),
                    },
                },
            },
        },
        "center-left-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },

        "center-right-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_plant_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "center-right-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block3</h2>
              <p style="text-align: center;">this is block3</p>
            `.trim(),
                    },
                },
            },
        },
        "center-right-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },

        "right-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_camera_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "right-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block 4</h2>
              <p style="text-align: center;">this is block 4</p>
            `.trim(),
                    },
                },
            },
        },
        "right-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },
    },
});

            image-text-gallery/custom-image-text-gallery
index.js

import CMS from '../../../constant/sw-cms.constant';
import "./preview";
import "./component";


Shopware.Service("cmsService").registerCmsBlock({
    name: "custom-image-text-gallery",
    label: "CMS image-text-button block",
    category: "text-image",
    component: "sw-cms-block-custom-image-text-gallery",
    previewComponent: "sw-cms-preview-custom-image-text-gallery",
    defaultConfig: {
        marginBottom: "20px",
        marginTop: "20px",
        marginLeft: "20px",
        marginRight: "20px",
        sizingMode: "boxed",
    },
    slots: {
        "left-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_plant_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "left-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block 1</h2>
              <p style="text-align: center;">this is block1</p>
            `.trim(),
                    },
                },
            },
        },
        "left-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },

        "center-left-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_glasses_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "center-left-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block2</h2>
              <p style="text-align: center;">this is block2</p>
            `.trim(),
                    },
                },
            },
        },
        "center-left-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },

        "center-right-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_plant_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "center-right-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block3</h2>
              <p style="text-align: center;">this is block3</p>
            `.trim(),
                    },
                },
            },
        },
        "center-right-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },

        "right-image": {
            type: "image",
            default: {
                config: {
                    displayMode: { source: "static", value: "cover" },
                },
                data: {
                    media: {
                        value: "bundles/administration/static/img/cms/preview_camera_large.jpg",
                        source: "default",
                    },
                },
            },
        },
        "right-text": {
            type: "text",
            default: {
                config: {
                    content: {
                        source: "static",
                        value: `
              <h2 style="text-align: center;">block 4</h2>
              <p style="text-align: center;">this is block 4</p>
            `.trim(),
                    },
                },
            },
        },
        "right-button": {
            type: "buy-button",
            default: {
                config: {
                    name: {
                        source: "static",
                        value: "Shop",
                        required: true,
                    },
                    link: {
                        source: "static",
                        value: null,
                    },
                },
            },
        },
    },
});

        constant
sw-cms.constant.ts

const uniqueSlotsKebab = [
    'buy-box',
    'product-description-reviews',
    'cross-selling',
];

/**
 * @sw-package discovery
 */
// eslint-disable-next-line sw-deprecation-rules/private-feature-declarations
export default Object.freeze({
    REQUIRED_FIELD_ERROR_CODE: 'c1051bb4-d103-4f74-8988-acbcafc7fdc3',
    PAGE_TYPES: {
        SHOP: 'page',
        LANDING: 'landingpage',
        LISTING: 'product_list',
        PRODUCT_DETAIL: 'product_detail',
    },
    TYPE_MAPPING_ENTITIES: {
        product_detail: {
            entity: 'product',
            mode: 'single',
        },
        product_list: {
            entity: 'category',
            mode: 'single',
        },
    },
    UNIQUE_SLOTS: uniqueSlotsKebab.map((slotName) => slotName.replace(/-./g, (char) => char.toUpperCase()[1])),
    UNIQUE_SLOTS_KEBAB: uniqueSlotsKebab,
    SLOT_POSITIONS: {
        left: 0,
        'left-image': 100,
        'left-top': 200,
        'left-text': 300,
        'left-bottom': 400,
        'center-left': 1000,
        center: 1100,
        'center-image': 1200,
        'center-top': 1300,
        'center-text': 1400,
        'center-bottom': 1500,
        'center-right': 1600,
        right: 2000,
        'right-image': 2100,
        'right-top': 2200,
        'right-text': 2300,
        'right-bottom': 2400,
        content: 3000,
        image: 3100,
        video: 3200,
        imageSlider: 3300,
        default: 5000,
    },
    MEDIA: {
        previewCamera: 'bundles/administration/static/img/cms/preview_camera_large.jpg',
        previewMountain: 'bundles/administration/static/img/cms/preview_mountain_large.jpg',
        previewPlant: 'bundles/administration/static/img/cms/preview_plant_large.jpg',
        previewGlasses: 'bundles/administration/static/img/cms/preview_glasses_large.jpg',
        SMALL:{
            previewCamera: 'framework/assets/default/cms/preview_camera_small.jpg',
            previewMountain: 'framework/assets/default/cms/preview_mountain_small.jpg',
            previewPlant: 'framework/assets/default/cms/preview_plant_small.jpg',
            previewGlasses: 'framework/assets/default/cms/preview_glasses_small.jpg',
        }
    },
});


        elements/buy-button
component
index.js

import template from "./sw-cms-el-buy-button.html.twig";
import "./sw-cms-el-buy-button.scss";

const { Mixin } = Shopware;

Shopware.Component.register("sw-cms-el-buy-button", {
    template,

    compatConfig: Shopware.compatConfig,

    mixins: [Mixin.getByName("cms-element"), Mixin.getByName("placeholder")],

    computed: {
        name() {
            return this.element?.config?.name?.value ?? "Shop";
        },
        redirectTo() {
            return this.element.config?.link?.value ?? null;
        },
    },

created(){
        this.createdComponent();
},
    methods: {
        createdComponent() {
            this.initElementConfig("buy-button");
            this.initElementData("buy-button");
        },
    },
});

twig

{% block sw_cms_el_buy_button %}
    {#    {{ dump('test') }}#}
    <div class="sw-cms-el-buy-button">
        {% block sw_cms_element_buy_button_form_action %}
            <div class="sw-cms-el-buy-button__actions">
                <a href="{{ redirectTo }}" class="sw-cms-el-buy-button__buy-action">
                    {{ name }}
                </a>
            </div>
        {% endblock %}
    </div>
{% endblock %}

scss

.sw-cms-el-buy-button {
  display: flex;
  justify-content: flex-start;
  flex-direction: column;
  height: 100%;
  width: 100%;
  pointer-events: none;
  font-size: smaller;
  color: darkgrey;

  &__placeholder {
    background-color: gray;
    height: 10px;
    border-radius: 10px;
    margin-bottom: 16px;
    max-width: 150px;

    &:nth-of-type(1) {
      height: 26px;
      max-width: 130px;
    }

    &:nth-of-type(2) {
      max-width: 100px;
      margin-bottom: 10px;
    }

    &:nth-of-type(3) {
      margin-bottom: 32px;
    }

    &:nth-of-type(4) {
      height: 16px;
      max-width: 300px;
    }

    &:nth-of-type(6) {
      margin-top: 16px;
    }
  }

  &__form {
    display: inline-flex;
    width: 100%;
  }

  &__quantity.sw-block-field {
    flex: 1;
    max-width: 150px;
    margin-bottom: 0;

    .sw-block-field__block {
      position: relative;
    }

    select {
      padding: 9px;
    }
  }

  &__variant-title {
    font-weight: bold;
  }

  &__variants {
    display: flex;
    justify-content: space-between;
    margin: 10px 0 24px;
    height: 36px;
    max-width: 260px;
  }

  &__variant {
    width: 80px;
    margin-right: 8px;
    background: gray;

    &:last-of-type {
      margin-right: 0;
    }
  }

  &__icon {
    display: flex;
    flex-direction: column;
    position: absolute;
    right: 10px;
    top: calc(50% - 15px);
    color: darkgrey;

    .icon--regular-chevron-up-xxs {
      width: 16px;
      height: 16px;
      padding-top: 5px;
      padding-right: 4px;
      padding-bottom: 6px;
      padding-left: 4px;
    }

    .icon--regular-chevron-down-xxs {
      width: 16px;
      height: 16px;
      padding-top: 6px;
      padding-right: 4px;
      padding-bottom: 5px;
      padding-left: 4px;
    }
  }

  &__actions {
    flex: 2;
    margin-left: 8px;
    max-width: 300px;
  }

  &__buy-action {
    display: block;
    line-height: 40px;
    font-size: small;
    font-weight: bold;
    text-align: center;
    text-decoration: none;
    color: white;
    background: gray;
    border-radius: 10px;
  }

  &__price {
    font-size: 26px;
    font-weight: bold;
    margin-bottom: 16px;
  }

  &__tax-info {
    margin-bottom: 10px;
  }

  &__shipping-info {
    margin-bottom: 32px;
    margin-left: 14px;
  }

  &__product-number-title {
    font-weight: bold;
  }

  &__product-number {
    margin-top: 16px;
  }
}

config
index.js

import template from "./sw-cms-el-config-buy-button.html.twig";
import "./sw-cms-el-config-buy-button.scss";
const { Mixin } = Shopware;
Shopware.Component.register("sw-cms-el-config-buy-button", {
    template,
    compatConfig: Shopware.compatConfig,

    emits: ["element-update"],

    mixins: [Mixin.getByName("cms-element")],

    created() {
        this.createdComponent();
    },

    methods: {
createdComponent(){
            this.initElementConfig("buy-button");
},
        onChange() {
            this.$emit("element-update", this.element);
        },
    },

});

twig

{% block sw_cms_element_buy_button_config %}
    <div class="sw-cms-el-config-buy-button">
        {% block sw_cms_element_buy_button_config_product_select %}
            <sw-text-field v-model:value="element.config.name.value"
                           :label="$tc('sw-cms.elements.buyButton.config.label.buttonText')"
                           :placeholder="$tc('sw-cms.elements.buyButton.config.placeholder.buttonText')"
                           name="name"
                           validation="required" required
                           @update:value="onChange" />

            <sw-text-field v-model:value="element.config.link.value"
                           :label="$tc('sw-cms.elements.buyButton.config.label.redirectLink')"
                           :placeholder="$tc('sw-cms.elements.buyButton.config.placeholder.redirectLink')"
                           name="link"
                           validation="required" required
                           @update:value="onChange" />
        {% endblock %}
    </div>
{% endblock %}

scss

.sw-cms-el-config-buy-button {
  &__alignment.sw-block-field,
  .sw-entity-single-select {
    margin-bottom: 0;
  }

  .sw-entity-single-select__selection {
    white-space: nowrap;
    display: flex;
    align-items: center;
  }

  .sw-entity-single-select__selection-text {
    vertical-align: middle;
    padding-right: 16px;
    width: 100%;
  }
}

preview
index.js

import template from "./sw-cms-el-preview-buy-button.html.twig";
import "./sw-cms-el-preview-buy-button.scss";

Shopware.Component.register("sw-cms-el-preview-buy-button", {
    template,
    compatConfig: Shopware.compatConfig,
});

twig

{% block sw_cms_element_buy_button_preview %}
<div class="sw-cms-el-preview-buy-button">
    <div class="sw-cms-el-preview-buy-button__action">shop
    </div>
</div>
{% endblock %}

scss

.sw-cms-el-preview-buy-button {
  height: 100%;
  width: 100%;
  padding: 0 10px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;

  &__price {
    font-size: smaller;
  }

  &__placeholders {
    display: grid;
    grid-template-columns: 10px 1fr;
    grid-gap: 4px;
    margin-top: 4px;

    & > .sw-cms-el-preview-buy-button__placeholder {
      width: 60px;
      margin: 0;

      &:nth-child(odd) {
        width: 8px;
        margin-right: 4px;
      }
    }
  }

  &__placeholder {
    height: 8px;
    border-radius: 50% 50%;
    background-color: gray;
  }

  &__action {
    background: gray;
    color: darkgrey;
    border-radius: 50% 50%;
    text-align: center;
    font-size: smaller;
    line-height: 26px;
    width: 100%;
    margin-top: 4px;
    align-self: flex-end;
  }
}

index.js

import './preview';
import './component';
import './config';

/**
 * @private
 * @sw-package discovery
 */
Shopware.Service("cmsService").registerCmsElement({
    name:"buy-button",
    label:"sw-cms.elements.buyButton.label",
    component:"sw-cms-el-buy-button",
    configComponent:"sw-cms-el-config-buy-button",
    previewComponent:"sw-cms-el-preview-buy-button",
    disabledConfigInfoTextKey:
        "sw-cms.elements.buyButton.infoText.tooltipSettingDisabled",
    defaultConfig:{
        name:{
            source:"static",
            value:"shop",
            required:true,
        },
        link:{
            source:"static",
            value:null,
        }
    },
    collect:Shopware.Service("cmsService").getCollectFunction(),
});

        snippet
de

{
  "sw-cms": {
    "elements": {
      "general": {
        "config": {
          "caption": {
            "mediaUpload": "Hochladen ein Bild"
          },
          "label": {
            "verticalAlign": "Vertikal ausrichten",
            "alignment": "Ausrichtung",
            "verticalAlignTop": "Spitze",
            "verticalAlignCenter": "Center",
            "verticalAlignBottom": "Unten",
            "displayMode": "Anzeige Modus",
            "displayModeStandard": "Original",
            "displayModeCover": "Beschnitten",
            "displayModeStretch": "Skaliert",
            "displayModeContain": "Behoben Höhe",
            "autoSlide": "Automatisch Übergang",
            "autoplayTimeout": "Verzögerung",
            "speed": "Animation Dauer",
            "horizontalAlign": "Horizontal ausrichten",
            "horizontalAlignLeft": "Links",
            "horizontalAlignCenter": "Center",
            "horizontalAlignRight": "Rechts"
          },
          "helpText": {
            "autoSlide": "Vorübergehend unbenutzt",
            "autoplayTimeout": "Dauer sollen bleiben Trotzdem",
            "speed": "gleiten Geschwindigkeit",
            "displayMode": "Bild angezeigt"
          },
          "tab": {
            "content": "Inhalt",
            "settings": "Einstellungen",
            "options": "Optionen"
          },
          "infoText": {
            "listingElement": "Probe Layout"
          }
        },
        "switch": {
          "groups": {
            "all": "Alle elements",
            "favorites": "Favorit Elemente"
          }
        }
      },
      "buyButton": {
        "label": "Buy Button",
        "infoText": {
          "tooltipSettingDisabled": "Probe Vorschau"
        },
        "config": {
          "label": {
            "buttonText": "Taste Text",
            "redirectLink": "Umleiten Link"
          },
          "placeholder": {
            "buttonText": "Eingeben Taste Text",
            "redirectLink": "/#"
          }
        },
        "component": {
          "label": {
            "actionBuy": "Add to cart",
            "taxInfo": "Steuerinformationen",
            "deliveryShippingFree": "Kostenloser Versand",
            "deliveryTime": "Verfügbar, Lieferzeit {name}",
            "variants": "Varianten",
            "productNumber": "Produktnummer:"
          }
        }
      }
    },
    "blocks": {
      "textImage": {
        "centerText": {
          "label": "Drei Spalten, Bilder und Text in Kästen"
        },
        "imageText": {
          "label": "Zwei Spalten, eingerahmtes Bild und Text"
        },
        "imageTextBubble": {
          "label": "Dreispaltig, beschriftet & gerundet"
        },
        "imageTextCover": {
          "label": "Zwei Spalten, Bild und Text in voller Größe"
        },
        "imageTextGallery": {
          "label": "Dreispaltig, Bild-/Textkarten"
        },
        "imageTextRow": {
          "label": "Dreispaltige, beschriftete Bilder"
        },
        "textOnImage": {
          "label": "Heldenbild"
        }
      }
    }
  }
}

en

{
  "sw-cms": {
    "elements": {
      "general": {
        "config": {
          "caption": {
            "mediaUpload": "Upload an image"
          },
          "label": {
            "verticalAlign": "Vertical align",
            "alignment": "Alignment",
            "verticalAlignTop": "Top",
            "verticalAlignCenter": "Center",
            "verticalAlignBottom": "Bottom",
            "displayMode": "Display mode",
            "displayModeStandard": "Original",
            "displayModeCover": "Cropped",
            "displayModeStretch": "Scaled",
            "displayModeContain": "Fixed height",
            "autoSlide": "Automatic transition",
            "autoplayTimeout": "Delay",
            "speed": "Animation duration",
            "horizontalAlign": "Horizontal align",
            "horizontalAlignLeft": "Left",
            "horizontalAlignCenter": "Center",
            "horizontalAlignRight": "Right"
          },
          "helpText": {
            "autoSlide": "Temporily unused",
            "autoplayTimeout": "duration should stay still",
            "speed": "sliding speed",
            "displayMode": "image displayed"
          },

          "tab": {
            "content": "Content",
            "settings": "Settings",
            "options": "Options"
          },
          "infoText": {
            "listingElement": "sample layout"
          }
        },
        "switch": {
          "groups": {
            "all": "All elements",
            "favorites": "Favourite elements"
          }
        }
      },
      "buyButton": {
        "label": "Buy Button",
        "infoText": {
          "tooltipSettingDisabled": "sample preview"
        },
        "config": {
          "label": {
            "buttonText": "Button Text",
            "redirectLink": "Redirect Link"
          },
          "placeholder": {
            "buttonText": "Enter Button Text",
            "redirectLink": "/#"
          }
        },
        "component": {
          "label": {
            "actionBuy": "Add to cart",
            "taxInfo": "tax info",
            "deliveryShippingFree": "Free shipping",
            "deliveryTime": "Available, delivery time {name}",
            "variants": "Variants",
            "productNumber": "Product number:"
          }
        }
      }
    },
    "blocks": {
      "textImage": {
        "centerText": {
          "label": "Three columns, boxed images & text"
        },
        "imageText": {
          "label": "Two columns, boxed image & text"
        },
        "imageTextBubble": {
          "label": "Three columns, captioned & rounded"
        },
        "imageTextCover": {
          "label": "Two columns, full-sized image & text"
        },
        "imageTextGallery": {
          "label": "Three columns, image/text cards"
        },
        "imageTextRow": {
          "label": "Three columns, captioned images"
        },
        "textOnImage": {
          "label": "Hero image"
        }
      }
    }
  }
}

main.js

import './module/sw-cms/blocks/text-image/custom-image-text-gallery';
import './module/sw-cms/elements/buy-button';

    in storefront no change keep as it it
dist/storefront/js/cms-theme
src

config
services.xml

<?xml version="1.0"?>

<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="CmsTheme\DataResolver\CustomImageTextGalleryCmsElementResolver"
                 class="CmsTheme\DataResolver\CustomImageTextGalleryCmsElementResolver">
            <tag name="shopware.cms.data_resolver" />
        </service>
    </services>
</container>

in public/admin no change

views/storefront
block
cms-block-custom-image-text-gallery.html.twig

{% block block_image_four_row %}
    {% set columns = 4 %}
    {% block block_image_four_row_left %}
        <div class="col-md-3">
            {% block block_image_four_row_left_image %}
                {% set element = block.slots.getSlot('left-image') %}
                {% block block_image_four_column_left_inner_image %}
                    {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
                {% endblock %}
            {% endblock %}
            {% block block_image_four_row_left_text %}
                {% set element = block.slots.getSlot('left-text') %}
                {% block block_image_four_column_left_inner_text %}
                    {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
                {% endblock %}
            {% endblock %}
            {% block block_image_four_row_left_button %}
                {% set element = block.slots.getSlot('left-button') %}
                {% block block_image_four_column_left_inner_button %}
                    {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
                {% endblock %}
            {% endblock %}
        </div>
    {% endblock %}

    {% block block_image_text_row_center_left %}
        <div class="col-md-3">
            {% block block_image_text_row_center_left_image %}
                {% set element = block.slots.getSlot('center-left-image') %}
                {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
            {% endblock %}
            {% block block_image_text_row_center_left_text %}
                {% set element = block.slots.getSlot('center-left-text') %}
                {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
            {% endblock %}
            {% block block_image_four_row_center_left_button %}
                {% set element = block.slots.getSlot('center-left-button') %}
                {% block block_image_four_column_center_left_inner_button %}
                    {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
                {% endblock %}
            {% endblock %}
        </div>
    {% endblock %}

    {% block block_image_text_row_center_right %}
        <div class="col-md-3">
            {% block block_image_text_row_center_right_image %}
                {% set element = block.slots.getSlot('center-right-image') %}
                {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
            {% endblock %}
            {% block block_image_text_row_center_right_text %}
                {% set element = block.slots.getSlot('center-right-text') %}
                {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
            {% endblock %}
            {% block block_image_four_row_center_right_button %}
                {% set element = block.slots.getSlot('center-right-button') %}
                {% block block_image_four_column_center_right_inner_button %}
                    {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
                {% endblock %}
            {% endblock %}
        </div>
    {% endblock %}

    {% block block_image_text_row_right %}
        <div class="col-md-3">
            {% block block_image_text_row_right_image %}
                {% set element = block.slots.getSlot('right-image') %}
                {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
            {% endblock %}
            {% block block_image_text_row_right_text %}
                {% set element = block.slots.getSlot('right-text') %}
                {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
            {% endblock %}
            {% block block_image_four_row_right_button %}
                {% set element = block.slots.getSlot('right-button') %}
                {% block block_image_four_column_right_inner_button %}
                    {% sw_include '@Storefront/storefront/element/cms-element-' ~ element.type ~ '.html.twig' ignore missing %}
                {% endblock %}
            {% endblock %}
        </div>
    {% endblock %}
{% endblock %}

element
cms-element-buy-button.html.twig
{% block sw_cms_el_buy_button %}

    <div class="sw-cms-el-buy-button">
        {% block sw_cms_element_buy_button_form_action %}
{#            {{ dump('test') }}#}
            <div class="sw-cms-el-buy-button__actions">
                    <a href="{{ element.config.link.value }}" class="sw-cms-el-buy-button__buy-action">
                        {{ element.config.name.value}}
                    </a>
            </div>
        {% endblock %}
    </div>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)