Artikel Slider aus Kategorie / zufällig sortiert (Conexco)

Hi zusammen, ich bin gerade dabei meinen Oxid Shop nach Shopware zu migrieren und habe mir jetzt schon 3 Plugins, die ich auch im Oxid hatte, selbst geschrieben. Jetzt fehlt mir nur noch die Möglichkeit, den Artikelslider auf der Startseite mit zufälligen Artikeln aus der Kategorie “NEU” zu füttern. Habt Ihr mir hierzu einen Ansatz, wie ich den bisherigen Artikelslider von Conexco entsprechend erweitern oder kopieren kann? Das Ergebnis stelle ich hier gerne zur Verfügung. Vielen Dank und viele Grüße, Chris

Gut, das Tutorial für die eigenen Einkaufsweltkomponenten bin ich soweit durch. Jetzt müsste ich quasi eine Kopie der Einstellungsmöglichkeiten für den Standardslider finden, werde allerdings nicht fündig. Wo befinden sich die Standardkomponenten bzw. nach welcher Datei muss ich suchen?

Hi zusammen, jetzt habe ich das Widget schon so weit, dass es in den Einkaufswelten entsprechend angezeigt wird. ExtJS Template ist auch drin. Aber wie lasse ich mir die Standardeinstellungen aus dem eigentlichen Slider in den Einstellungen anzeigen. Die muss man doch irgendwie vererben können, oder? Hier mal die biserhige Version: RandomsliderWidget

So, jetzt habe ich in der Datenbank nachgesehen und die anderen Widgets haben in der entsprechenden Spalte ein getArticles, nur mein neues Widget hat das nicht und die entsprechenden Eingabefelder werden auch nicht in den Einstellungen angezeigt. Irgendwie komme ich an der Stelle nicht weiter. Wäre schön, wenn hier jemand meinen Monolog beendet. Den oberen Download habe ich auf den neuesten Stand gebracht. Vielen Dank und viele Grüße, Chris

Hi, mach das doch einfach im Template selber. {$sCharts=$sCharts|@shuffle}(Ungetestet) Damit kannst Du das Array der Elemente in /widgets/listing/top_seller.tpl einmal durchmixen bevor der Include von widgets/recommendation/slide_articles.tpl kommt. //Edit: Sorry ich sollte mal besser lesen. Das hilft natürlich nur, wenn man entsprechend die Topseller zufällig sortieren will. LG

Dankeschön erstmal, sowas geht natürlich auch ganz gut, erfüllt aber meine Anforderungen nicht ganz, denn der Slider soll aus ner Kategorie gefüttert werden und auf eine bestimmte Anzahl begrenzt werden… Na, vielleicht findet sich noch jemand.

So, jetzt bin ich soweit, dass ich diesen Fehler hier bekomme: SyntaxError: Unexpected token : at http://meinserver.de/engine/Library/ExtJs/ext-all.js?201409241139:21:5361 at Object.Ext.globalEval (http://meinserver.de/engine/Library/ExtJs/ext-all.js?201409241139:21:5369) at Ext.Ajax.request.success (http://meinserver.de/backend/base?file=bootstrap&loggedIn=1424331388:477:5) at Object.Ext.apply.callback (http://meinserver.de/engine/Library/ExtJs/ext-all.js?201409241139:21:67496) at Ext.define.onComplete (http://meinserver.de/engine/Library/ExtJs/ext-all.js?201409241139:21:422670) at Ext.define.onStateChange (http://meinserver.de/engine/Library/ExtJs/ext-all.js?201409241139:21:422314) at XMLHttpRequest.<anonymous> (http://meinserver.de/engine/Library/ExtJs/ext-all.js?201409241139:21:17406)

Hier mal meine BOotstrap.php


<?php /**
 * Shopware 4
 * Copyright © shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 */

class Shopware_Plugins_Backend_RandomsliderWidget_Bootstrap extends Shopware_Components_Plugin_Bootstrap
{

    public $component;

    public function getInfo()
    {
        return array(
            'version' => $this-&gt;getVersion(),
            'label' =&gt; $this-&gt;getLabel(),
            'link' =&gt; 'http://www.dreamride.de',
            'description' =&gt; 'Artikel Slider aus bestimmter Kategorie / Zufallsartikel'
        );
    }

    public function getLabel()
    {
        return 'Artikel Slider / Kategorie';
    }

    public function getVersion()
    {
        return "1.0.1";
    }

    /**
     * The install function of the plugin.
     *
     * @return bool
     */
    public function install()
    {
        // Save the new component
        $this-&gt;component = $this-&gt;createComponent();

        // Create the necessary fields for the component
        $this-&gt;createComponentFields();

        // Register all necessary events to handle the data.
        $this-&gt;registerEvents();

        // Don't forget to return true ;)
        return true;
    } 
    
    /**
     * Create and return the new emotion component with custom xtype.
     *
     * @return \Shopware\Models\Emotion\Library\Component
     */
    public function createComponent()
    {
        return $this-&gt;createEmotionComponent(array(
            'name' =&gt; 'Artikel Slider / Kategorie',
            'xtype' =&gt; 'emotion-randomarticleslider-widget',
            'template' =&gt; 'component_randomarticleslider',
            'cls' =&gt; 'emotion-randomarticleslider-widget',
            'description' =&gt; 'Artikel Slider aus bestimmter Kategorie / Zufallsartikel'
        ));
    }
     
    /**
     * Create a hidden input field for the emotion component configuration.
     * The hidden field will be used to store the data of the custom ExtJS Component.
     * Data will be stored as a JSON string.
     */
    public function createComponentFields()
    {

        $this-&gt;component-&gt;createHiddenField(array(
            'name' =&gt; 'randomarticleslider_widget_store',
            'allowBlank' =&gt; true
        ));

    }

    /**
     * Register on the emotion filter event to handle
     * the saved data before passing it to the template.
     */
    public function registerEvents()
    {
        $this-&gt;subscribeEvent(
            'Shopware_Controllers_Widgets_Emotion_AddElement',
            'onEmotionAddElement'
        );
    }

    /**
     * Event handler for the emotion filter event.
     * It decodes the stored JSON string and passes the values to the emotion data.
     *
     * @param Enlight_Event_EventArgs $arguments
     * @return mixed
     */
    public function onEmotionAddElement(Enlight_Event_EventArgs $arguments)
    {
        $data = $arguments-&gt;getReturn();
        $articles = array();

        if (isset($data['randomarticleslider_widget_store']) &amp;&amp;
            !empty($data['randomarticleslider_widget_store'])) {
            $articles = json_decode($data['randomarticleslider_widget_store'], true);
        }

        $data['articles'] = $articles;

        return $data;
    }      

    public function uninstall()
    {
        return true;
    }
}

Und noch das entsprechende JS:

[code]Ext.define(‘Shopware.apps.Emotion.view.components.RandomarticlesliderWidget’, {
extend: ‘Shopware.apps.Emotion.view.components.Base’,
alias: ‘widget.emotion-randomarticleslider-widget’,

/**
 * Snippets for the component.
 * @object
 */
snippets: {
    'select_article': '{s name=select_article}Select article(s){/s}',
    'article_administration': '{s name=article_administration}Article administration{/s}',
    'name': '{s name=name}Article name{/s}',
    'ordernumber': '{s name=ordernumber}Ordernumber{/s}',
    'actions': '{s name=actions}Action(s){/s}',

    article_slider_max_number: '{s name=article_slider_max_number}Maximum number of articles{/s}',
    article_slider_title: '{s name=article_slider_title}Title{/s}',
    article_slider_arrows: '{s name=article_slider_arrows}Display arrows{/s}',
    article_slider_numbers: '{s name=article_slider_numbers}Display numbers{/s}',
    article_slider_scrollspeed: '{s name=article_slider_scrollspeed}Scroll speed{/s}',

    article_slider_rotation: '{s name=article_slider_rotation}Rotate automatically{/s}',
    article_slider_rotatespeed: '{s name=article_slider_rotatespeed}Rotation speed{/s}'
},

/**
 * Initiliaze the component.
 *
 * @public
 * @return void
 */
initComponent: function() {
    var me = this;
    me.callParent(arguments);
    me.add(me.createArticleFieldset());
    me.setDefaultValues();
    me.getGridData();

    me.articleType = me.down('emotion-components-fields-article-slider-type');
    if(!me.articleType.getValue()) {
        me.maxCountField.hide();
        me.articleFieldset.hide();
    }
    if(me.articleType.getValue() === 'selected_article') {
        me.maxCountField.hide();
        me.articleFieldset.show();
        me.rotateSpeed.show().enable();
        me.rotation.show().enable();
    } else {
        me.maxCountField.show();
        me.articleFieldset.hide();
        me.rotateSpeed.hide().disable();
        me.rotation.hide().disable();
    }
    me.articleType.on('change', me.onChange, me);

    me.refreshHiddenValue();
},

onChange: function(field, newValue) {
    var me = this;

    if(newValue !== 'selected_article') {
        me.maxCountField.show();
        me.articleFieldset.hide();
        me.rotateSpeed.hide().disable();
        me.rotation.hide().disable();
    } else {
        me.maxCountField.hide();
        me.articleFieldset.show();
        me.rotateSpeed.show().enable();
        me.rotation.show().enable();
    }
},

/**
 * Sets default values if the article slider
 * wasn't saved previously.
 *
 * @public
 * @return void
 */
setDefaultValues: function() {
    var me = this,
        numberfields = me.query('numberfield'),
        checkboxes = me.query('checkbox');

    Ext.each(numberfields, function(field) {
        if(field.getName() === 'article_slider_max_number') {
            me.maxCountField = field;
            if(!field.getValue()) {
                field.setValue(25);
            }
        }

        if(field.getName() === 'article_slider_rotatespeed') {
            me.rotateSpeed = field;
        }

        if(!field.getValue()) {
            field.setValue(500);
        }
    });

    Ext.each(checkboxes, function(field) {
        if(field.getName() === 'article_slider_rotation') {
            me.rotation = field;
        }
    });
},

/**
 * Creates the fieldset which holds the article administration. The method
 * also creates the article store and registers the drag and drop plugin
 * for the grid.
 *
 * @public
 * @return [object] Ext.form.FieldSet
 */
createArticleFieldset: function() {
    var me = this;

    me.articleSearch = Ext.create('Shopware.form.field.ArticleSearch', {
        layout: 'anchor',
        anchor: '100%',
        multiSelect: false,
        returnValue: 'name',
        hiddenReturnValue: 'number',
        listeners: {
            scope: me,
            valueselect: me.onAddArticleToGrid
        }
    });

    me.articleStore = Ext.create('Ext.data.Store', {
        fields: ['position', 'name', 'ordernumber', 'articleId']
    });

    me.ddGridPlugin = Ext.create('Ext.grid.plugin.DragDrop');

    me.articleGrid = Ext.create('Ext.grid.Panel', {
        columns: me.createColumns(),
        autoScroll: true,
        store: me.articleStore,
        height: 300,
        viewConfig: {
            plugins: [me.ddGridPlugin],
            listeners: {
                scope: me,
                drop: me.onRepositionArticle
            }
        }
    });

    return me.articleFieldset = Ext.create('Ext.form.FieldSet', {
        title: me.snippets.article_administration,
        layout: 'anchor',
        defaults: { anchor: '100%' },
        items: [me.articleSearch, me.articleGrid]
    });
},

/**
 * Helper method which creates the column model
 * for the article administration grid panel.
 *
 * @public
 * @return [array] computed columns
 */
createColumns: function() {
    var me = this, snippets = me.snippets;

    return [{
        header: '⚌',
        width: 24,
        hideable: false,
        renderer : me.renderSorthandleColumn
    }, {
        dataIndex: 'name',
        header: snippets.name,
        flex: 1
    }, {
        dataIndex: 'ordernumber',
        header: snippets.ordernumber,
        flex: 1
    }, {
        xtype: 'actioncolumn',
        header: snippets.actions,
        width: 60,
        items: [{
            iconCls: 'sprite-minus-circle',
            action: 'delete-article',
            scope: me,
            handler: me.onDeleteArticle
        }]
    }];
},

/**
 * Event listener method which will be triggered when one (or more)
 * article are added to the article slider.
 *
 * Creates new models based on the selected articles and
 * assigns them to the article store.
 *
 * @public
 * @event selectMedia
 * @param [object] field - Shopware.MediaManager.MediaSelection
 * @param [array] records - array of the selected media
 */
onAddArticleToGrid: function(field, returnVal, hiddenVal, record) {
    var me = this, store = me.articleStore;

    var model = Ext.create('Shopware.apps.Emotion.model.ArticleSlider', {
        position: store.getCount(),
        name: returnVal,
        ordernumber: hiddenVal,
        articleId: record.get('id')
    });
    store.add(model);

    field.searchField.setValue();
    me.refreshHiddenValue();

},

/**
 * Event listener method which will be triggered when the user
 * deletes a article from article administration grid panel.
 *
 * Removes the article from the article store.
 *
 * @event click#actioncolumn
 * @param [object] grid - Ext.grid.Panel
 * @param [integer] rowIndex - Index of the clicked row
 * @param [integer] colIndex - Index of the clicked column
 * @param [object] item - DOM node of the clicked row
 * @param [object] eOpts - additional event parameters
 * @param [object] record - Associated model of the clicked row
 */
onDeleteArticle: function(grid, rowIndex, colIndex, item, eOpts, record) {
    var me = this;
    var store = grid.getStore();
    store.remove(record);
    me.refreshHiddenValue();
},

/**
 * Event listener method which will be fired when the user
 * repositions a article through drag and drop.
 *
 * Sets the new position of the article in the article store
 * and saves the data to an hidden field.
 *
 * @public
 * @event drop
 * @return void
 */
onRepositionArticle: function() {
    var me = this;

    var i = 0;
    me.articleStore.each(function(item) {
        item.set('position', i);
        i++;
    });
    me.refreshHiddenValue();
},

/**
 * Refreshes the mapping field in the model
 * which contains all articles in the grid.
 *
 * @public
 * @return void
 */
refreshHiddenValue: function() {
    var me = this,
        store = me.articleStore,
        cache = [];

    store.each(function(item) {
        cache.push(item.data);
    });
    var record = me.getSettings('record');
    record.set('mapping', cache);
},

/**
 * Refactor sthe mapping field in the global record
 * which contains all article in the grid.
 *
 * Adds all articles to the article administration grid
 * when the user opens the component.
 *
 * @return void
 */
getGridData: function() {
    var me = this,
        elementStore = me.getSettings('record').get('data'), articleSlider;

    Ext.each(elementStore, function(element) {
        if(element.key === 'selected_articles') {
            articleSlider = element;
            return false;
        }
    });

    if(articleSlider &amp;&amp; articleSlider.value) {
        Ext.each(articleSlider.value, function(item) {
            me.articleStore.add(Ext.create('Shopware.apps.Emotion.model.ArticleSlider', item));
        });
    }
},

/**
 * Renderer for sorthandle-column
 *
 * @param [string] value
 */
renderSorthandleColumn: function() {
    return '<div style="cursor: move;">⚌</div>';
}

});[/code]

Sieht für mich laut Doku richtig aus. Hat denn keiner ne Idee, weshalb die ExtJS Komponenten nicht geladen werden?

Vielen Dank und viele Grüße,

Chris

So, ne kleine Idee bin ich nun weiter, ich komme wieder in die Einkaufswelt und kann das Element in den Grid ziehen. Jetzt frage ich mich, weshalb diese Meldung in der Konsole kommt: me.articeType is null Ist das denn nicht richtig, bzw. was wid denn bei me.down eigentlich verlangt? me.articleType = me.down('emotion-components-fields-article-slider-type'); So, da wird das entsprechende ExtJS Template mit dem Slider Type abgefragt. Wie kann ich das denn da reintüten, bzw. den Wert füllen? Wenn ich nämlich den Part mit me.articleType auskommentiere, wird der Rest der Komponenten geladen.

Könnte sich hier nicht mal ein ExtJs Profi etwas engagieren, ich denke, das Plugin könnte viele interessieren, zumal man dann ja auf der Startseite Artikel aus einer beliebigen Kategorie darstellen lassen könnte.

Ich hänge an dieser Stelle leider immer noch in der Luft. Ich bekomme den Artikelslider Type einfach nicht in die Komponenten reingeladen. Da ist ja bei ExtBase das Leiden anfänglich noch kleiner als bei ExtJs…

bekommst du denn deine Zip mit der Ordnerstruktur überhaupt geladen, wenn du es über den PluginManager einspielst, oder kommt einfach keine Rückmeldung mehr und du kannst erst wieder auf die restlichen Plugins zugreifen, wenn du per FTP dein Plugin löschst. Habe ein ähnliches Problem mit einem Einkaufswelt Widget, ich habe 4.3.2 da funktioniert das in der Wiki angegebene Vimeo Plugin erst gar nicht, und eine 4.3.2 Version scheint das nicht zu sein.

Moinsen Zwilla, ja, ich bekomme mein Plugin so geladen, es gibt keinerlei Rückmeldung und es lässt sich auch ohne Weiteres im Pluginmanager installieren und erscheint auch in der Einkaufswelt. Wieso, was ist mit der Struktur denn nicht in Ordnung? Ich habe gerade den Download in diesem Thread neu aufgespielt. Kannst Dir ja gerne mal ansehen. Danke fürs Unterbrechen meines Monologs :slight_smile:

ok, ziehe ich mir mal rein, ich habe das gleiche Problem, kann meines auch laden, nur dann passiert nix mehr, selbst die anderen Plugins sind dann weg. Melde mich zurück.

cls ist der Klassenname der CSS Klasse, also der Wrapper um das eigentliche Plugin, deswegen dürfen die auch gleich heißen. Bei Extbase (da programmiere ich ziemlich viel mit) ist das auch so der Fall. Somit könntest Du der Extension separates CSS mitgeben, cls könnte wohl auch leer bleiben. Ja, das ist richtig, aber bei der Übergabe der Variablen an das Template sind wir ja noch gar nicht, da ja die Werte des Slidertypes noch nicht in den Komponenten erscheinen. Daran hänge ich gerade leider immer noch und es gibt weit und breit keine Hilfe. Das Template wird ja nicht erweitert, sondern lediglich der bereits existierende Slider mit entsprechenden Daten gefüttert, dies erst noch abzufrage gilt. Aber Dein Konstrukt dürfte so auch funktionieren.

Welche Shopware Version hast du? //{block name="backend/emotion/view/components/RandomarticlesliderWidget"} class Shopware\_Plugins\_Backend\_RandomsliderWidget\_Bootstrap extends Shopware\_Components\_Plugin\_Bootstrap Passt das zusammen?

4.3.2

Die Blöcke kannst Du auch weglassen, aber prinzipiell passt das zusammen, ja! Siehst, ja, das Ding lässt sich auch installieren, nur der Artikeltyp wird nicht geladen, deswegen gibts auch nen JavaScript Error in der Konsole. Frage: wie bekomme ich die Slidertypen als ExtJs Komponente dort reingeladen…

Also das auf Seite 1 hinterlegte Zip, bekomme ich nur geladen, wenn ich die Struktur ändere, ansonsten den Fehler mit dem Name Space. Wenn ich dann sie Struktur angepasst habe, und es hochgeladen habe dann kommt erst nach dem ich auf die Erweiterungen (links) klicke die Meldung das der NameSpace falsch ist. Wie kannst du das überhaupt laden? Oder schiebst du das via FTP hoch?

Ich schiebe das über FTP hoch und kanns ohne Probleme aktivieren. Muss natürlich nicht in den Frontend, sondern in den Backend Ordner unterhalb von Community!