diff --git a/block-languages/benenson-blocks.pot b/block-languages/benenson-blocks.pot
index 00e5518..eac41b4 100644
--- a/block-languages/benenson-blocks.pot
+++ b/block-languages/benenson-blocks.pot
@@ -848,6 +848,87 @@ msgstr ""
msgid "Add a repeatable logo block"
msgstr ""
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:139
+msgid "Are you sure you want to delete this logo from the slider?"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:200
+#: src/scripts/blocks/slider/DisplayComponent.js:217
+msgid "Show Arrows"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:205
+msgid "Number of logos to show per slide"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:212
+#: src/scripts/blocks/slider/DisplayComponent.js:238
+msgid "Slide Options"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:214
+msgid "Slide URL"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:219
+msgid "Open link in new tab"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:247
+msgid "Add a logo below."
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:261
+msgid "Delete Logo"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:262
+msgid "Logo settings"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:277
+msgid "Pevious Logo"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:279
+msgid "Add Logo"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/DisplayComponent.js:281
+msgid "Next Logo"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/index.js:27
+msgid "Logo slider"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/index.js:31
+#: src/scripts/blocks/slider/index.js:38
+msgid "Slider"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/index.js:32
+#: src/scripts/blocks/slider/index.js:39
+msgid "Carousel"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/index.js:33
+#: src/scripts/blocks/slider/index.js:40
+msgid "Scroller"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/index.js:69
+#: src/scripts/blocks/slider/DisplayComponent.js:287
+#: src/scripts/blocks/slider/index.js:59
+msgid "Next"
+msgstr ""
+
+#: src/scripts/blocks/logo-slider/index.js:70
+#: src/scripts/blocks/slider/DisplayComponent.js:288
+#: src/scripts/blocks/slider/index.js:60
+msgid "Previous"
+msgstr ""
+
#: src/scripts/blocks/media-aside/DisplayComponent.js:103
msgid "(Insert Link text)"
msgstr ""
@@ -1060,10 +1141,6 @@ msgstr ""
msgid "Do you wish to delete this slide? This action is irreversible"
msgstr ""
-#: src/scripts/blocks/slider/DisplayComponent.js:217
-msgid "Show Arrows"
-msgstr ""
-
#: src/scripts/blocks/slider/DisplayComponent.js:223
msgid "Has Content"
msgstr ""
@@ -1085,10 +1162,6 @@ msgid ""
"you to navigate through each slide."
msgstr ""
-#: src/scripts/blocks/slider/DisplayComponent.js:238
-msgid "Slide Options"
-msgstr ""
-
#: src/scripts/blocks/slider/DisplayComponent.js:240
msgid "Slide Title"
msgstr ""
@@ -1116,16 +1189,6 @@ msgstr ""
msgid "This is irreversible."
msgstr ""
-#: src/scripts/blocks/slider/DisplayComponent.js:287
-#: src/scripts/blocks/slider/index.js:59
-msgid "Next"
-msgstr ""
-
-#: src/scripts/blocks/slider/DisplayComponent.js:288
-#: src/scripts/blocks/slider/index.js:60
-msgid "Previous"
-msgstr ""
-
#: src/scripts/blocks/slider/DisplayComponent.js:294
msgid "Add a slide below."
msgstr ""
@@ -1162,18 +1225,6 @@ msgstr ""
msgid "Toggle Content"
msgstr ""
-#: src/scripts/blocks/slider/index.js:38
-msgid "Slider"
-msgstr ""
-
-#: src/scripts/blocks/slider/index.js:39
-msgid "Carousel"
-msgstr ""
-
-#: src/scripts/blocks/slider/index.js:40
-msgid "Scroller"
-msgstr ""
-
#: src/scripts/blocks/tweet/index.js:109
msgid "(Action Title)"
msgstr ""
diff --git a/src/scripts/app.js b/src/scripts/app.js
index 22a140f..66f29dc 100755
--- a/src/scripts/app.js
+++ b/src/scripts/app.js
@@ -11,6 +11,7 @@ import categorySlider from './modules/category-slider';
import modalEmbed from './modules/modal-embed';
import inlineEmbed from './modules/inline-embed';
import sliderBlock from './modules/slider-block';
+import logoSlider from './modules/logo-slider';
import subcatDrops from './modules/subcategory-dropdown';
import categoryExpander from './modules/category-expander';
import fluidText from './modules/fluid-text';
@@ -31,6 +32,7 @@ const App = () => {
modalEmbed();
inlineEmbed();
sliderBlock();
+ logoSlider();
subcatDrops();
categoryExpander();
scrollTo();
diff --git a/src/scripts/blocks.js b/src/scripts/blocks.js
index a99adc8..0b32e10 100755
--- a/src/scripts/blocks.js
+++ b/src/scripts/blocks.js
@@ -26,6 +26,7 @@ import './blocks/download';
import './blocks/key-facts';
import './blocks/category-list';
import './blocks/logo-list';
+import './blocks/logo-slider';
import './blocks/link';
import './blocks/media-aside';
diff --git a/src/scripts/blocks/logo-slider/DisplayComponent.js b/src/scripts/blocks/logo-slider/DisplayComponent.js
new file mode 100644
index 0000000..324640a
--- /dev/null
+++ b/src/scripts/blocks/logo-slider/DisplayComponent.js
@@ -0,0 +1,289 @@
+import classnames from 'classnames';
+
+const randId = () => Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);
+
+const { __ } = wp.i18n;
+const { Component, Fragment } = wp.element;
+const { applyFilters } = wp.hooks;
+const {
+ PanelBody, Button, TextControl, ToggleControl, RangeControl,
+} = wp.components;
+const {
+ InspectorControls, RichText, BlockIcon, URLInputButton,
+} = wp.editor;
+const { PostMediaSelector } = benenson.components;
+
+class DisplayComponent extends Component {
+ static emptySlide = {
+ id: '',
+ title: '',
+ imageId: '',
+ imageUrl: '',
+ imageLink: '',
+ newTab: false,
+ };
+
+ constructor(...props) {
+ super(...props);
+
+ this.state = {
+ selectedSlide: 0,
+ group: this.props.attributes.perSlide,
+ };
+ }
+
+ componentDidMount() {
+ const { attributes, setAttributes } = this.props;
+
+ if (!attributes.sliderId) {
+ setAttributes({
+ sliderId: randId(),
+ });
+ }
+ }
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.attributes.perSlide !== this.props.attributes.perSlide) {
+ this.setState({
+ group: this.props.attributes.perSlide,
+ });
+ }
+ }
+
+ /**
+ * Higher order component that takes the attribute key,
+ * this then returns a function which takes a value,
+ * when called it updates the attribute with the key.
+ * @param key
+ * @returns {function(*): *}
+ */
+ createUpdateAttribute = key => value => this.props.setAttributes({ [key]: value });
+
+ createUpdateSlideAttribute =
+ index =>
+ key =>
+ value =>
+ this.props.setAttributes({
+ slides: [
+ ...this.props.attributes.slides
+ .slice(0, Math.max(0, index)),
+ {
+ ...this.props.attributes.slides[index],
+ [key]: value,
+ },
+ ...this.props.attributes
+ .slides.slice(index + 1, this.props.attributes.slides.length),
+ ],
+ });
+
+ createUpdateImage =
+ index =>
+ ({
+ id: imageId = false,
+ source_url: imageUrl = false,
+ media_details: {
+ sizes,
+ } = {},
+ } = {}) => {
+ this.props.setAttributes({
+ slides: [
+ ...this.props.attributes.slides
+ .slice(0, Math.max(0, index)),
+ {
+ ...this.props.attributes.slides[index],
+ imageId,
+ imageUrl,
+ sizes,
+ },
+ ...this.props.attributes
+ .slides.slice(index + 1, this.props.attributes.slides.length),
+ ],
+ });
+ };
+
+ addSlide = () => {
+ const { attributes, setAttributes } = this.props;
+
+ setAttributes({
+ slides: [...attributes.slides, {
+ ...DisplayComponent.emptySlide,
+ id: randId(),
+ }],
+ });
+
+ this.setState({
+ selectedSlide: attributes.slides.length,
+ group: attributes.slides.length + 1,
+ });
+ };
+
+ deleteSlide = (index) => {
+ const { attributes, setAttributes } = this.props;
+
+ if (index === attributes.slides.length - 1) {
+ this.setState({
+ selectedSlide: index - 1,
+ group: (index - 1) > attributes.perSlide ? attributes.slides.length : attributes.perSlide,
+ });
+ }
+
+ this.props.setAttributes({
+ slides: [
+ ...attributes.slides.slice(0, Math.max(0, index)),
+ ...attributes.slides.slice(index + 1, attributes.slides.length),
+ ],
+ });
+ };
+
+ initiateDelete = () => {
+ if (confirm(__('Are you sure you want to delete this logo from the slider?'))) { // eslint-disable-line no-restricted-globals, no-alert
+ this.deleteSlide(this.state.selectedSlide);
+ }
+ };
+
+ selectSlide = index => this.setState({
+ selectedSlide: index,
+ });
+
+ createSelectSlide = index => () => this.selectSlide(index);
+
+ movePrev = () => {
+ const { selectedSlide, group } = this.state;
+
+ const slideOrder = [...this.props.attributes.slides];
+ const temp = slideOrder[selectedSlide];
+ slideOrder[selectedSlide] = slideOrder[selectedSlide - 1];
+ slideOrder[selectedSlide - 1] = temp;
+
+ this.props.setAttributes({
+ slides: slideOrder,
+ });
+
+ this.setState({
+ selectedSlide: selectedSlide - 1,
+ group: (selectedSlide - 1) < this.props.attributes.perSlide ? this.props.attributes.perSlide : group - 1, // eslint-disable-line max-len
+ });
+ };
+
+ moveNext = () => {
+ const { selectedSlide, group } = this.state;
+ const slideOrder = [...this.props.attributes.slides];
+ const temp = slideOrder[selectedSlide];
+ slideOrder[selectedSlide] = slideOrder[selectedSlide + 1];
+ slideOrder[selectedSlide + 1] = temp;
+
+ this.props.setAttributes({
+ slides: slideOrder,
+ });
+
+ this.setState({
+ selectedSlide: selectedSlide + 1,
+ group: (selectedSlide + 1) === (this.props.attributes.slides.length - this.props.attributes.perSlide) ? this.props.attributes.perSlide : group + 1, // eslint-disable-line max-len
+ });
+ };
+
+ render() {
+ const { attributes, setAttributes } = this.props;
+ const { selectedSlide, group } = this.state;
+
+ const currentSlide = attributes.slides[selectedSlide];
+ const updateSlide = this.createUpdateSlideAttribute(selectedSlide);
+
+ const quantityOptions = applyFilters('benenson.block.logoSlider.quantityOptions', {
+ min: 1,
+ max: 10,
+ });
+
+ const controls = (
+ Change milestone position:{ __('Add a logo below.', 'benenson') }
+
+