-/53

Uploadlimiet verhogen WordPress

Plaats in je .htaccess:

    SecRequestBodyNoFilesLimit 131072000
    SecRequestBodyLimit 131072000
Bekijk Snippet

PHP Out of memory issue bij deployen van Magento omgeving

Voeg het volgende voor je command: 
php -d memory_limit=2G bin/magento ....

Dus bijv:
php -d memory_limit=2G bin/magento setup:static-content:deploy -f
Bekijk Snippet

Filtering van Smart View plugin om te filteren met exacte match in plaats van contains / indexOf

Plaats deze snippet in je script.js (na DOMContentLoaded) om de filtering te overschrijven met een exacte match in plaats van een contains.
Dit is nodig indien je filteropties hebt als (IT en Facilitair), want bij het aanvinken van IT vindt hij ook Facilitair) (facilitair.contains(it))

JAVASCRIPT Code

javascript
	// Overschrijf de checkFilter methode van een 'contains' check naar 'exacte match'
QuickFilter.prototype.checkFilter = function(t, e) {
    var l;
    if (!e || "" === e) return !1;
    let i = null == (l = this._allFilters[t]) ? void 0 : l.toString().toLowerCase();
    if (i) {
        let s = i.split(","),
            n = e.toLowerCase().split(",");
        return s.some((filterValue) => n.some((dataValue) => filterValue.trim() === dataValue.trim()));
    }
    return !1;
};
Bekijk Snippet

Javascript toevoegen in Magento (Checkout) met PHP variabelen

Om PHP variabelen te gebruiken in JS in de Magento Checkout (of elders in je shop), kun je het beste zo de code organiseren.

PHP Code

php
Plaats dit in je .phtml file die je via XML inlaadt in de checkout
om de php variablen op te halen -> dit is de JS file waar het gebruikt word -> Gladior_CurrencySymbol/js/gladior-currency

/**
* Gladior Currency Symbol Config
* Outputs configuration as JavaScript variable
*
* @var $block \Gladior\CurrencySymbol\Block\JsConfig
*/
?>
<?php if ($block->isEnabled() && $block->getCustomSymbol()): ?>
<script type="text/x-magento-init">
{
    "*": {
        "Gladior_CurrencySymbol/js/gladior-currency": {
            "enabled": true,
            "currencyCode": "<?php echo $block->escapeJs($block->getCurrencyCode()); ?>",
            "defaultSymbol": "<?php echo $block->escapeJs($block->getDefaultSymbol()); ?>",
            "customSymbol": "<?php echo $block->escapeJs($block->getCustomSymbol()); ?>"
        }
    }
}
</script>
<?php endif; ?>

JAVASCRIPT Code

javascript
define(['jquery'], function ($) {
    'use strict';
 
    return function (config) {
        if (!config || !config.enabled || !config.customSymbol) return;config
        console.log(config.enabled);
    }
}
Bekijk Snippet

[InvalidArgumentException] Could not find a matching version of package

Krijg je een foutmelding als:

masterfire@moc7:~/masterfire.nl$ php8.1 /usr/local/bin/composer require mageplaza/magento-2-italian-language-pack:dev-master
  [InvalidArgumentException]
  Could not find a matching version of package mageplaza/magento-2-italian-language-pack. Check the package spelling, your version constraint and that the packag
  e is available in a stability which matches your minimum-stability (dev).


Dan moet je de update gaan uitvoeren met de nieuwste versie van de composer:
Download hier en plaats in je /root folder als composer.phar
https://getcomposer.org/download/
Bekijk Snippet

Volgorde (sub)menu items Magento menu

Voeg de eerste stuk snippet toe aan app/code/Gladior/Menu/Block/Menu.php
Vervang de loop van de submenu's in het menu door de tweede snippet in app/code/Gladior/Menu/frontend/templates/main-menu.phtml

PHP Code

php
    /**
     * Get sorted subcategories for a parent category
     * @param int|string $parentId
     * @return \Magento\Catalog\Model\ResourceModel\Category\Collection
     */
    public function getSortedSubcategories($parentId)
    {
        $currentStore = $this->_storeManager->getStore();
        $subcategories = $this->_categoryCollection->create()
            ->addAttributeToSelect('*')
            ->addFieldToFilter('is_active', 1)
            ->addFieldToFilter('include_in_menu', 1)
            ->addAttributeToFilter('parent_id', $parentId)
            ->setOrder('position', 'ASC')
            ->setStore($currentStore);
        
        return $subcategories;
    }





<?php foreach ($block->getSortedSubcategories($category->getId()) as $subcategory) :
                $rawUrl = $block->getUrl($subcategory->getData('url_path'));
                $url = trim($rawUrl, '/');
            ?>
                <li class="menu-item sub-menu-item<?php echo $subcategory->hasChildren() ? ' has-children' : ' no-children';  ?>">
                    <a href="<?php echo $url; ?>" class="item-link sub-item-link" id="category-<?php echo $subcategory->getId(); ?>">
                        <span class="item-name sub-item-name"><?php echo $subcategory->getName(); ?></span>
                    </a>
                    <?php if ($subcategory->hasChildren()) : ?>
                        <ul class="sub-sub-menu">
                            <div class="menu-step-back mobile"></div>
                            <?php foreach ($block->getSortedSubcategories($subcategory->getId()) as $subsubcategory) :
                                $rawUrl = $block->getUrl($subsubcategory->getData('url_path'));
                                $url = trim($rawUrl, '/');
                            ?>
                                <li class="menu-item sub-sub-menu-item">
                                    <a href="<?php echo $url; ?>" class="item-link sub-sub-item-link">
                                        <span class="item-name sub-sub-item-name"><?php echo $subsubcategory->getName(); ?></span>
                                    </a>
                                </li>
                            <?php endforeach; ?>
                        </ul>
                        <div class="child-toggle mobile"></div>
                    <?php endif; ?>
                </li>
            <?php endforeach; ?>
Bekijk Snippet

Instellen Redis caching voor een Magento installatie

Als je voor een Magento installatie Redis cache hebt ingesteld, moet je het volgende controleren:

php bin/magento config:show system/full_page_cache/caching_application
   Geeft dit 1 terug: Magento gebruikt Redis caching nog niet, omdat de database instelling nog op "1" (Built-in) staat.

Oplossing:
Je moet de full page cache instelling wijzigen naar Redis. Dit kun je via de command line doen:
php bin/magento config:set system/full_page_cache/caching_application 2
php bin/magento cache:flush

Vanaf nu gebruikt Magento je Redis configuratie voor full page cache in plaats van het bestandssysteem!
Bekijk Snippet

Mapgroottes laten zien van Magento installatie

Om per map te kunnen zien wat de grootte is van onderliggende mappen, gebruik de volgende commands:
du -h -d1 var
du -h -d1 pub
Bekijk Snippet

Cannot process definition to array for type tinytext

Er zijn twee verschillende foutmeldingen:

1. "Cannot process definition to array for type enum / tinytext"
 
Ga naar de database tabel: 	wp_icl_translation_status
Zoek entry: 			review_status
 
'enum' moet omgezet worden naar 'int'

=============
 
2. "Cannot process definition to array for type tinytext"
 
Ga naar database tabel: 	wp_comments (Indexen)
Selecteer de volgende Indexen:	comment_author, comment_date, comment_date_gmt
Verander de volgende waarden:	
comment_author 	  -> VARCHAR (lengte: 100)
comment_date 	    -> CURRENT_TIMESTAMP
comment_date_gmt  -> CURRENT_TIMESTAMP
Bekijk Snippet

Kopie maken van Magento X WordPress integratie

In het geval van een Magento X Wordpress koppeling, moet je als volgt een kopie maken:

1. Koppel de juiste database in je wp-config.php aanpassen
2. Zorg er voor dat de 4 store URLS van Magento in core_config eindigen op /shop/
3. Zorg er voor dat de 2 URL's van Wordpress niet eindigen op /shop/
4. Het pad dat je M2I plugin moet invullen is /home/gebruiker/store/shop/
Bekijk Snippet

Alias zetten php8.1 php

In je rootfolder, ga een leven omhoog:
cd ..
totdat je met 'ls -a' de file .bashrc ziet staan.

Deze open je met:
  nano .bashrc

Vul hier in:
  alias php="php8.1"

Ctrl + X om op te slaan
Druk op Enter
Bekijk Snippet

Veilig inline scripting toestaan in Magento

Overschrijf in je  thema de manier waarop de scripts worden ingeladen op deze manier.

PHP Code

php
<?php
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
?>
<?php $secureRenderer->renderTag('script', ['type' => 'text/javascript'], "\nconsole.log('I am a whitelisted script');\n", false); ?>

of 


<?php
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
?>
<?= $secureRenderer->renderTag(
    'script',
    ['type' => 'text/javascript'],
    <<<JS
    ... hier je JavaScript ...
    JS,
    false
); ?>
Bekijk Snippet

Basisopstelling voor een AJAX load event

In je .function.php plak je de content van de PHP snippet.
Maak een .js file aan: /scripts/the_ajax_script.js en plak hierin de content van de JavaScript snippet.

HTML Code

html
<div class="pure-g">
    <div class="pure-u-1-4">
        <button id="ajax_trigger">Klik hier!</button>
        <span id="ajax_placeholder">Gladior</span>
    </div>
    <div class="pure-u-3-4">
        <div id="ajax_response"></div>
    </div>
</div>

PHP Code

php
/**
 * Nieuwe AJAX load request aanmaken
 */

// Stap 1: Registreer je script file, waarop je de AJAX actie wilt uitvoeren
function gladior_enqueue_ajax_script()
{

    // Enqueue the JavaScript file on the frontend.
    wp_enqueue_script(
        'gladior_ajax_script_handle', // Handle for the script.
        get_template_directory_uri() . '/scripts/the_ajax_script.js', // Path to the script file.
    );

    // Localize script to pass the AJAX URL to JavaScript
    wp_localize_script('gladior_ajax_script_handle', 'the_ajax_object', [
        'ajax_url' => admin_url('admin-ajax.php'),
        '_nonce_to_verify' => wp_create_nonce('_nonce_to_verify'),
    ]);
}
// Hook the function to the 'wp_enqueue_scripts' action.
add_action('wp_enqueue_scripts', 'gladior_enqueue_ajax_script');




function function_to_execute()
{
    $data = json_decode(file_get_contents('php://input'));
    wp_verify_nonce($data->_nonce_to_verify, '_nonce_to_verify') || wp_die("Invalid nonce " . $data->_nonce_to_verify);

    $content = $data->content ? $data->content : 'No content provided';
    wp_send_json_success(array(
        'output_content' => $content,
        'data' => $data,
    ));
}

add_action('wp_ajax_function_to_execute', 'function_to_execute');
add_action('wp_ajax_nopriv_function_to_execute', 'function_to_execute');

JAVASCRIPT Code

javascript
async function gladior_ajax_request_function(body) {
  body.base_url = window.location.href.replace(RegExp("page/[0-9]/"), "");
  try {
    const response = await fetch(
      `${the_ajax_object.ajax_url}?action=function_to_execute`,
      {
        method: "POST",
        body: JSON.stringify({
            _nonce_to_verify: the_ajax_object._nonce_to_verify,
            ...body
        }),
      }
    );
    const data = await response.json();
    return data.data;
  } catch (error) {
    return error;
  }
}

document.addEventListener("DOMContentLoaded", async function () {
  const placeholder = document.getElementById("ajax_placeholder");
  const outputContainer = document.getElementById("ajax_response");
  if (!outputContainer) return;

  // Functie om de content te updaten (beide keuzes nodig)
  // maak een async functie updateTheContent met een integer parameter
  async function updateTheContent(variable = placeholder?.innerHTML) {
    // Toon loading animatie
    outputContainer.innerHTML = "Loading...";

    const res = await gladior_ajax_request_function({
        _nonce_to_verify: the_ajax_object._nonce_to_verify,
        content: variable,
    });

    if (outputContainer && res.output_content) {
      outputContainer.innerHTML = res.output_content;
    }
  }

  // Als je al een initiële update wilt doen.
  await updateTheContent();


  // Voeg het updateTheContent toe aan alle navigatie items
  const trigger = document.getElementById("ajax_trigger");
    trigger.addEventListener("click", async () => {
        await updateTheContent();
    });
});
Bekijk Snippet

Magento WordPress integratie – Widgets uitschakelen in WYSIWYG

Als je Wordpress erg traag wordt van alle Widgets die hij wil inladen vanuit

Voeg de snippet toe in je functions.php , om er voor te zorgen dat de Widgets niet wordt ingeladen. Zorgt namelijk voor enorme snelheidsverlies bij veel categories.

PHP Code

php
add_action('init', function () {
    // Loop through all callbacks for media_buttons
    global $wp_filter;
 
    if ( isset( $wp_filter['media_buttons'] ) ) {
        foreach ( $wp_filter['media_buttons']->callbacks as $priority => $callbacks ) {
            foreach ( $callbacks as $id => $callback ) {
 
                // Check if the callback belongs to M2I_Editor_Button
                if (
                    is_array($callback['function']) &&
                    is_object($callback['function'][0]) &&
                    get_class($callback['function'][0]) === 'M2I_Editor_Button'
                ) {
                    unset($wp_filter['media_buttons']->callbacks[$priority][$id]);
                }
 
            }
        }
    }
});
Bekijk Snippet

IP Adres blokkeren htaccess Magento 2

Plaats de volgende regels bovenin in je /pub/.htaccess bestand:

Order Allow,Deny
Allow from all
Deny from 34.141.10.24
Deny from 34.159.247.222
Bekijk Snippet

Van csv bestand via PHP post_types aanmaken en ACF velden vullen

PHP Code

php
if (get_current_user_id() === 1) : 
	/**
     * Import EQA Opleidingen from CSV into CPT 'eqa-opleiding'
     * Usage: put this in a one-off mu-plugin, a WP-CLI command, or run in a secure admin context.
     */

    if ( ! defined('ABSPATH') ) { exit; }

    // === CONFIG ===

    $fileloc = dirname(__DIR__, 1);
    $csvFile = $fileloc . '/pe-opleidingen.csv'; // adjust path
    $post_type = 'pe-opleiding';
    $taxonomy  = 'pe-type'; // ACF taxonomy attached to this post_type

    // Map logical field names to ACF field KEYS (recommended).
    // TODO: replace field_XXXXXXXX with your actual ACF field keys.
    $acf_keys = [
        'systeemid'         => 'systeemid', // number
        'opleidingskenmerk' => 'opleidingskenmerk', // text
        'link'              => 'link', // link
        'toegekend'         => 'pe_of_eqa_toegekend_op', // date
        'geldig'            => 'pe_of_eqa_geldig_tot', // date
        'opleidingsvorm'    => 'opleidingsvorm', // wysiwyg
        'opl_omschrijving'  => 'opl_omschrijving', // wysiwyg
        'peuren'            => 'pe_uren', // number
        'duurdagen'         => 'duur_dagen', // number
        'kosten'            => 'kosten', // number
        'startdata'         => 'startdata', // wysiwyg
        // taxonomy is handled via wp_set_object_terms()
    ];

    // === HELPERS ===
    /**
     * Try to detect delimiter based on header line.
     */
    function detect_delimiter($line) {
        $candidates = [",", ";", "\t", "|"];
        $counts = [];
        foreach ($candidates as $d) {
            $counts[$d] = substr_count($line, $d);
        }
        arsort($counts);
        return key($counts);
    }

    /**
     * Normalize header labels to canonical keys.
     */
    function normalize_header($label) {
        $label = trim(mb_strtolower($label));
        // allow small variations/spaces
        $label = preg_replace('/\s+/', '', $label);
        return $label;
    }

    /**
     * Parse a date string into ACF Date Picker format 'Ymd'.
     * Returns null if cannot parse or empty.
     */
    function to_acf_date($value) {
        $value = trim((string)$value);
        if ($value === '') return null;

        // Try common formats
        $formats = ['Y-m-d', 'd-m-Y', 'd/m/Y', 'Y/m/d', 'd.m.Y', 'Ymd'];
        foreach ($formats as $fmt) {
            $dt = DateTimeImmutable::createFromFormat($fmt, $value);
            if ($dt instanceof DateTimeImmutable) {
                return $dt->format('Ymd');
            }
        }

        // Last resort: strtotime
        $ts = strtotime($value);
        if ($ts !== false) {
            return date('Ymd', $ts);
        }

        return null;
    }

    /**
     * Read the first line safely (handling BOM).
     */
    function fopen_no_bom($path) {
        $h = fopen($path, 'r');
        if (! $h) return false;
        // Remove UTF-8 BOM if present
        $bom = fread($h, 3);
        if ($bom !== "\xEF\xBB\xBF") {
            // Not a BOM; rewind to start
            rewind($h);
        }
        return $h;
    }

    /**
     * Find existing post by unique meta 'systeemid'.
     */
    function find_post_by_systeemid($systeemid, $post_type) {
        $q = new WP_Query([
            'post_type'      => $post_type,
            'posts_per_page' => 1,
            'post_status'    => 'any',
            'meta_query'     => [
                [
                    'key'   => 'systeemid',
                    'value' => $systeemid,
                ],
            ],
            'fields'         => 'ids',
            'no_found_rows'  => true,
        ]);
        return $q->have_posts() ? (int)$q->posts[0] : 0;
    }

    // === RUN ===
    if (! file_exists($csvFile)) {
        wp_die('CSV not found at: ' . esc_html($csvFile));
    }

    $handle = fopen_no_bom($csvFile);
    if ($handle === false) {
        wp_die('Unable to open CSV.');
    }

    // Peek first line to detect delimiter
    $firstLine = fgets($handle);


    if ($firstLine === false) {
        fclose($handle);
        wp_die('CSV is empty.');
    }
    $delimiter = detect_delimiter($firstLine);

    // Build header from first line
    $headerRaw = str_getcsv($firstLine, $delimiter);
    $headerMap = [];
    foreach ($headerRaw as $i => $label) {
        $count++;
        $norm = normalize_header($label);
        $headerMap[$i] = $norm;
    }

    // Expected canonical keys (normalized):
    $required = ['systeemid','naam','opleidingskenmerk','link','toegekend','geldig','petype', 'opleidingsvorm', 'opl_omschrijving', 'peuren', 'duurdagen', 'kosten', 'startdata'];
    $missing  = array_diff($required, $headerMap);
    if ($missing) {
        // Try to be forgiving if your header used small differences like "systeemidnaam" earlier:
        // If you for some reason have combined headers, adjust here or ensure the CSV header matches the list above.
        // For now, enforce correctness:
        fclose($handle);
        wp_die('CSV header missing columns: ' . implode(', ', $missing));
    }

    $created = 0;
    $updated = 0;

    // Iterate rows
    while (($row = fgetcsv($handle, 0, $delimiter)) !== false) {
        if (count($row) === 1 && trim($row[0]) === '') {
            continue; // skip empty lines
        }

        $item = [];
        foreach ($row as $i => $value) {
            $key = $headerMap[$i] ?? 'col_'.$i;
            $item[$key] = is_string($value) ? trim($value) : $value;
        }

        // Basic validation
        if (($item['naam'] ?? '') === '') {
            continue; // skip rows without a title
        }

        $systeemid = $item['systeemid'] ?? '';
        $existing_id = $systeemid !== '' ? find_post_by_systeemid($systeemid, $post_type) : 0;

        $postarr = [
            'post_type'   => $post_type,
            'post_title'  => $item['naam'],
            'post_status' => 'publish',
        ];

        if ($existing_id) {
            $postarr['ID'] = $existing_id;
            $post_id = wp_update_post($postarr, true);
        } else {
            $post_id = wp_insert_post($postarr, true);
        }

        if (is_wp_error($post_id)) {
            error_log('Failed to save post for systeemid '.$systeemid.': '.$post_id->get_error_message());
            continue;
        }

        // === ACF fields ===
        // Number: systeemid


        // === ACF fields — TEXT ===
        if (isset($item['opleidingsvorm'])) {
            update_field($acf_keys['opleidingsvorm'], sanitize_text_field($item['opleidingsvorm']), $post_id);
        }
        if (isset($item['opleidingskenmerk'])) {
            update_field($acf_keys['opleidingskenmerk'], sanitize_text_field($item['opleidingskenmerk']), $post_id);
        }

        // === ACF fields — WYSIWYG ===
        foreach (['opl_omschrijving','startdata'] as $wysiwygKey) {
            if (array_key_exists($wysiwygKey, $item)) {
                $val = is_string($item[$wysiwygKey]) ? trim($item[$wysiwygKey]) : $item[$wysiwygKey];
                if ($val !== '' && $val !== null) {
                    update_field($acf_keys[$wysiwygKey], $val, $post_id);
                }
            }
        }

        // Numbers: peuren, duurdagen, kosten
        foreach (['systeemid','peuren','duurdagen','kosten'] as $numKey) {
            if (!empty($item[$numKey])) {
                update_field($acf_keys[$numKey], (float) $item[$numKey], $post_id);
            }
        }

        // Link: expects array(url, title, target)
        if (!empty($item['link'])) {
            $linkArr = [
                'url'    => esc_url_raw($item['link']),
                'title'  => $item['naam'],    // or a static label like "Bekijk"
                'target' => '_blank',         // adjust if you use same window
            ];
            update_field($acf_keys['link'], $linkArr, $post_id);
        }

        // Dates: to ACF date format 'Ymd'
        foreach (['toegekend','geldig','verlengd'] as $dateKey) {
            $val = isset($item[$dateKey]) ? to_acf_date($item[$dateKey]) : null;
            if ($val) {
                update_field($acf_keys[$dateKey], $val, $post_id);
            } else {
                // Optional: clear if empty
                // update_field($acf_keys[$dateKey], null, $post_id);
            }
        }

        // Taxonomy: niveau (can be multiple; split by comma if present)
        if (!empty($item['petype'])) {
            $termsRaw = array_map('trim', preg_split('/[,|;]+/', $item['petype']));
            $termsRaw = array_filter($termsRaw, fn($t) => $t !== '');
            if ($termsRaw) {
                // Ensure terms exist; create as needed
                $term_ids = [];
                foreach ($termsRaw as $termName) {
                    $existing = term_exists($termName, $taxonomy);
                    if ($existing === 0 || $existing === null) {
                        $created_term = wp_insert_term($termName, $taxonomy);
                        if (!is_wp_error($created_term)) {
                            $term_ids[] = (int)$created_term['term_id'];
                        }
                    } elseif (is_array($existing) && isset($existing['term_id'])) {
                        $term_ids[] = (int)$existing['term_id'];
                    }
                }
                if ($term_ids) {
                    wp_set_object_terms($post_id, $term_ids, $taxonomy, false);
                }
            }
        }

        if ($existing_id) { $updated++; } else { $created++; }
    }

    fclose($handle);

    printf(
        "Done. Created: %d, Updated: %d\n",
        $created,
        $updated
    );
endif;
Bekijk Snippet

Slider met alleen CSS

Zorg dat je een HTML structuur hebt zoals in de Snippet:
<div class="your_class_name">
 <div class="g_card">1</div>
   ....
</div>

Nu kun je eenvoudig de responsiveness aangeven met: 
.g_slide(3);  Hierin in 3 natuurlijk de perPage.

HTML Code

html
<div class="container py-4">
	<div class="your_class_name">
		<div class="g_card">1</div>
		<div class="g_card">2</div>
		<div class="g_card">3</div>
		<div class="g_card">4</div>		
		<div class="g_card">5</div>
		<div class="g_card">6</div>
		<div class="g_card">7</div>		
		<div class="g_card">8</div>
		<div class="g_card">9</div>
		<div class="g_card">10</div>
	</div>
</div>

CSS Code

css
@default_per_page: 3;

.g_slide {
	.g_slide();
}

.g_slide(@per_page: @default_per_page) {
	@per_page_percent: (100% / @per_page);
	@gap_adjustment: (1 - (1rem / @per_page));
	.d-flex;
	flex-wrap: nowrap; // Prevent wrapping

	width: 100%;
	gap: 1em;	
	
	overflow-x: auto;
	scroll-behavior: smooth;
	anchor-name: --slide-container;
	scroll-snap-type: x mandatory;
	scroll-marker-group: after;
	&::-webkit-scrollbar {
		.d-none;
	}
	&::scroll-marker-group {
		.d-flex;
		.justify-center;
		gap: 0.5em;
		margin-top: 0.5em;
	}
	
	&::scroll-button(right), &::scroll-button(left) {
		.btn;
		content: '>';
		position: fixed;
		position-anchor: --slide-container;
		position-area: right center;
		translate: -50%;
		&:disabled {
			opacity: 0.5;
			cursor: auto;
		}
	}
	&::scroll-button(left) {
		content: '<';
		position-area: left center;
		translate: 50%;
	}
	
	.g_card {
		scroll-snap-align: start;
		width: ~"calc(@{per_page_percent} - @{gap_adjustment})";
		flex-shrink: 0; 
		@media screen and (max-width: @screen_sm) {
			width: 100%;
			flex: 0 0 100%;
		}
		&::scroll-marker {
			content: '';
			height: 0.75em;
			width: 0.75em;
			background-color: @grey_clr;
			border-radius: 50%;
			&:target-current {
				background-color: @main_clr;
			}
		}
	}
}
.g_card {
	.bg-grey;
	.bradius;
	.center;
	min-height: 500px;
}


.your_class_name {
	.g_slide(3);
	@media screen and (max-width: @screen_lg) {
		.g_slide(2); // 2 slides per page on smaller screens
	}
}
Bekijk Snippet

CSS Classes uitbreiding Basisthema Cis

CSS Code

css
.setbradius(@radius: @default_border_radius) {
    border-radius: @radius;
    overflow: hidden;
}

.bradius {
    border-radius: 1em;
    overflow: hidden;
}

.h-100 {
    height: 100%;
}
.w-100 {
    width: 100%;
}

.center { 
    .d-flex;
    .align-center;
    .justify-center;
}

.grid-gap-base(@size: 5, @decrement: 0.5) when (@size >=0.5) {
  .grid-gap-base(@size - @decrement);
  // Convert decimal to dash format for class names
  @class-name: replace(~"@{size}", "\.", "-");
  .colgap-@{class-name} {
    column-gap: ~"@{size}rem";
  }
  .rowgap-@{class-name} {
    row-gap: ~"@{size}rem";
  }
}

.grid-gap-base();
Bekijk Snippet

Responsive grid-template-columns

CSS Code

css
grid-template-columns: repeat(auto-fit, minmax(225px, 1fr));
Bekijk Snippet

Bots uitsluiten van crawlen htaccess

Heb je veel last van verkeer van een crawl bot, zoals bijv.
    18-214-124-6.crawl.amazonbot.amazon
    44-208-193-63.crawl.amazonbot.amazon
    3-213-85-234.crawl.amazonbot.amazon
    23-21-175-228.crawl.amazonbot.amazon

Sluit deze bot dan uit via .htaccess
    # Blokkeer de Amazonbot
    RewriteCond %{HTTP_USER_AGENT} Amazonbot [NC]
    RewriteRule .* - [F,L]
Bekijk Snippet

Wishlist en product compare verwijderen

Bestand aanmaken:
/app/design/frontend/Gladior/GladiorTheme/Magento_Catalog/layout/default.xml


    
         
        
        
        
        
        

        
        

        
        
    
Bekijk Snippet

Downloadable products weghalen

Maak een bestand aan:
/app/design/frontend/Gladior/GladiorTheme/Magento_Customer/layout/customer_account.xml



    
        
        
            
        
    
Bekijk Snippet

Collapsible laten werken met werkelijke hoogte van in te klappen element

Door de scrollHeight op te halen van het element dat je wilt inklappen, wordt deze altijd zo groot als het element is.

JAVASCRIPT Code

javascript
	var coll = document.getElementsByClassName("collapsible");
	var i;
	for (i = 0; i < coll.length; i++) {
		coll[i].addEventListener("click", function() {
			var content = this.nextElementSibling;
			content.classList.toggle("inactive");
			if(content.classList.contains("inactive")){
				content.style.maxHeight = null;
			}else{
				content.style.maxHeight = content.scrollHeight + "px";
			}
		});
	}
Bekijk Snippet

Op basis van IP adres JS uitvoeren (Marker.io)

PHP Code

php
function get_user_ip() {   
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        if (strpos($ip, ',') !== false) {
            $ip = explode(',', $ip)[0];
        }
        return trim($ip);
    } else {
        return $_SERVER['REMOTE_ADDR'];
    }
}
$userIP = get_user_ip();

JAVASCRIPT Code

javascript
const allowedIPs = [
    '77.60.182.90',
    '77.60.182.91'
];

const userIP = '<?php echo $userIP; ?>';
// console.log('IP is: ' + userIP);
if (allowedIPs.includes(userIP)) {
    // laad iets in, bijv. Marker.io
}
Bekijk Snippet

jQuery terug inladen in WordPress thema

PHP Code

php
function reregister_jquery()
{
        wp_enqueue_script('jquery-core', includes_url('/js/jquery/jquery.min.js'), array(), null, false);
        wp_enqueue_script('jquery-migrate', includes_url('/js/jquery/jquery-migrate.min.js'), array('jquery-core'), null, false);
        wp_enqueue_script('jquery');
}
Bekijk Snippet

Magento Cronjobs / Indexers

Met de volgende commands kun je de diverse zaken omtrend Magento cronjobs analyseren.

> ps aux
Toont alle actieve processen op de server — dus alles wat op dat moment draait: PHP-scripts, cronjobs, system services (zoals Redis, MySQL), enzovoort.

> kill -id van crontaak-
Vastgelopen taken kun je killen middels:
 
> php bin/magento indexer:status
Geeft weer of de Magento-indexen up-to-date zijn, of dat er nog herindexatie nodig is.

> crontab -l
Toont welke cronjobs zijn ingesteld voor de gebruiker waarmee je bent ingelogd.
Bekijk Snippet

Site Health / Sitediagnose verbergen voor gebruikers zonder @gladior.com account

PHP Code

php
function hide_site_health_for_specific_users() {
    // Definieer de string die in het emailadres moet voorkomen
    $email_string = '@gladior.com'; // Pas dit aan naar de gewenste string
    
    // Controleer of de gebruiker is ingelogd
    if (!is_user_logged_in()) {
        return;
    }
    
    // Haal de huidige gebruiker op
    $current_user = wp_get_current_user();
    $user_email = $current_user->user_email;
    
    // Controleer of de string voorkomt in het emailadres
    if (strpos($user_email, $email_string) === false) {
        // Verwijder de Site Health menu items
        remove_submenu_page('tools.php', 'site-health.php');
        
        // Blokkeer directe toegang tot de pagina
        add_action('current_screen', 'block_site_health_access');
    }
}

/**
 * Blokkeert directe toegang tot de Site Health pagina
 */
function block_site_health_access() {
    $screen = get_current_screen();
    
    if ($screen && $screen->id === 'site-health') {
        // Redirect naar dashboard met foutmelding
        wp_redirect(admin_url('index.php?site-health-blocked=1'));
        exit;
    }
}

function site_health_blocked_notice() {
    if (isset($_GET['site-health-blocked'])) {
        echo '<div class="notice notice-error is-dismissible">
                <p><strong>Toegang geweigerd:</strong> U heeft geen toegang tot de Site Health pagina.</p>
              </div>';
    }
}

// Hook de functies aan de juiste WordPress acties
add_action('admin_menu', 'hide_site_health_for_specific_users', 999);
add_action('admin_notices', 'site_health_blocked_notice');

function hide_site_health_by_capability() {
    // Alleen administrators kunnen Site Health zien
    if (!current_user_can('manage_options')) {
        remove_submenu_page('tools.php', 'site-health.php');
        add_action('current_screen', 'block_site_health_access');
    }
}
add_action('admin_menu', 'hide_site_health_by_capability', 999);
Bekijk Snippet

Script inladen WordPress

PHP Code

php
// Javascript
if (!wp_script_is('script_segment_layout')) {
    wp_enqueue_script('module_script_slider', get_stylesheet_directory_uri() . '/scripts/slider-script.js');
}


// Stylesheet
if (!wp_script_is('slider_segment_layout')) {
    wp_enqueue_style('module_css_slider', get_stylesheet_directory_uri() . '/styles/assets/splide.css');
}
Bekijk Snippet

Timeout functie

JAVASCRIPT Code

javascript
function checkForElement() {
  const element = document.querySelector('#element_id .element_class');
  if (element) {
    console.log('found');
  } else {
    setTimeout(checkForElement, 100); // Controleer opnieuw na 100 milliseconden
  }
}

// Start de controle
checkForElement();
Bekijk Snippet

Magento verwijder links uit Klantaccount (Downloads en Nieuwsbriefabbonementen)

Voeg toe aan je thema: 
/webshop.nl/app/design/frontend/Gladior/GladiorTheme/Magento_Customer/layout/customer_account.xml

Met de inhoud als volgt:




    
        
                    
            
                
                    customer/account/logout
                    Log out
                
            
        
        
        

    

Bekijk Snippet

Magento PDF uploads mogelijk maken

Installeer deze module: https://github.com/experius/Magento-2-Module-Experius-WysiwygDownloads

composer require experius/module-wysiwygdownloads
  > indien problemen met de dependencies, gebruikt --ignore-platform-reqs
    composer require experius/module-wysiwygdownloads --ignore-platform-reqs
Bekijk Snippet

Magento User aanmaken via CLI

php bin/magento admin:user:create --admin-user=GladiorTemp --admin-password=MissionPossible2025 --admin-email=service+2025@gladior.com --admin-firstname=Mission --admin-lastname=Possible
Bekijk Snippet

Initials Helper / Initialen splitsen met punt

JAVASCRIPT Code

javascript
function initialsHelper(element) {
  console.log(element);
  const initials = element ? document.getElementById(element) : document.getElementById("voorletters");
  const char = [
    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
    "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
    "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
  ];
  
  // Bijhouden van de vorige waarde om backspace/delete te detecteren
  let previousValue = '';
  let isBackspacing = false;

  // Directe key event listeners voor backspace/delete detectie
  initials?.addEventListener("keydown", (e) => {
    // Detecteer backspace (8) of delete (46) toetsen
    if (e.keyCode === 8 || e.keyCode === 46) {
      isBackspacing = true;
    }
  });

  initials?.addEventListener("keyup", (e) => {
    // Reset de backspace vlag na keyup
    if (e.keyCode === 8 || e.keyCode === 46) {
      isBackspacing = false;
    }
  });

  // Helper functie om initialen juist te formatteren
  const formatInitials = () => {
    // Als gebruiker aan het backspacen is, niets doen
    if (isBackspacing) {
      return;
    }

    // Als de waarde korter is geworden, waarschijnlijk door backspace
    if (initials.value.length < previousValue.length) {
      previousValue = initials.value;
      return;
    }
    
    // Verwijder dubbele punten (..)
    let value = initials.value.replace(/\.{2,}/g, '.');
    
    // Verwijder spaties
    value = value.replace(/\s/g, '');
    
    // Zorg ervoor dat elke letter wordt gevolgd door één punt
    let formatted = '';
    for (let i = 0; i < value.length; i++) {
      if (char.includes(value[i])) {
        // Als het een letter is, voeg hoofdletter toe
        formatted += value[i].toUpperCase();
        
        // Voeg een punt toe als het volgende karakter niet al een punt is
        if (i + 1 >= value.length || value[i + 1] !== '.') {
          formatted += '.';
        }
      } else if (value[i] === '.' && formatted.length > 0 && formatted[formatted.length - 1] !== '.') {
        // Voeg punt toe als laatste karakter nog geen punt is
        formatted += '.';
      }
    }
    
    // Update de waarde alleen als het echt veranderd is
    if (formatted !== initials.value) {
      initials.value = formatted;
    }
    
    previousValue = initials.value;
  };

  // Input event handler
  const handleInput = () => {
    // Wacht een kort moment voor het formatteren
    setTimeout(formatInitials, 10);
  };

  // Gebruik input event voor normale invoer
  initials?.addEventListener("input", handleInput);
  
  // Voor oudere browsers of specifieke apparaten
  initials?.addEventListener("change", handleInput);
  
  // Bewaar initiële waarde
  if (initials) {
    previousValue = initials.value;
  }
}
Bekijk Snippet

Magento versie upgrade

Meer info hier Klik

Voer de volgende commando's uit om Magento te upgraden.

php bin/magento maintenance:enable

composer require magento/product-community-edition=2.3.3 --no-update
composer update
php bin/magento setup:upgrade
php bin/magento setup:di:compile

php bin/magento maintenance:disable
Bekijk Snippet

Magento fout enum na upgrade

Wanneer een upgrade niet werkt in een Magento X Wordpress omgeving die vertaald wordt door PolyLang krijg je de voglende melding:

"Cannot process definition to array for type enum / tinytext"

Ga naar de database tabel: 	wp_icl_translation_status
Zoek entry: 			review_status 

'enum' moet omgezet worden naar 'int'

=============

Cannot process definition to array for type tinytext

Ga naar database tabel: 	wp_comments (Indexen)
Selecteer de volgende Indexen:
comment_author, comment_date, comment_date_gmt

Verander de volgende waarden:	
comment_author 	  -> VARCHAR (lengte: 100)
comment_date 	    -> CURRENT_TIMESTAMP
comment_date_gmt  -> CURRENT_TIMESTAMP
Bekijk Snippet

Magento Productiemodus Cache legen

Staat een Magento in productie modus:

Modus checken:
php bin/magento deploy:mode:show


Na een wijziging geen ca:cl, maar:
rm -rf var/view_preprocessed/* rm -rf pub/static/frontend/* 
php bin/magento cache:clean
php bin/magento setup:static-content:deploy -t Gladior/Avinter -f -s

Om ook de admin te verversen:
php bin/magento setup:static-content:deploy en_US nl_NL
Bekijk Snippet

Magento App Cache Frontend Pool

Warning: Undefined array key "frontend" in /home/ishoprugnl/ishop.rug.nl/vendor/magento/framework/App/Cache/Frontend/Pool.php on line 90
 
oplossing in app/etc/env.php 
'cache' => [     
'frontend' => [
 
        ]
    ]
];
Bekijk Snippet

Magento API aanroepen via Postman

Eerst token verkrijgen via POST
https://webshop.stulz-benelux.com/rest/V1/integration/admin/token

In Header tab:
Content-Type : application/json

In Body tab:
selecteer 'raw'
{
    "username" : ""
    "password" : ""
}

Send.
Je krijgt nu een token.

======

Maak een nieuwe GET - request aan
In Authorization > Selecteer Bearer Token
Viel hier de zojuist verkregen token in. (zonder aanhalingstekens)

https://webshop.stulz-benelux.com/rest/default/V1/orders/1  of
https://webshop.stulz-benelux.com/rest/default/V1/customers/1
Bekijk Snippet

Magento attirbuut waarde gevuld, extra CSS class toevoegen

PHP Code

php
<?php foreach($_productCollection as $_product) : 
  $palletPrice = $_product->getData('pallet_prijs');
  $cssExtraClass = $palletPrice ? 'pallet-actie' : '';
?>

<li class="item <?= $cssExtraClass;?>">List-item</li>
Bekijk Snippet

Kruisje unicode

CSS Code

css
&:before {
   content: "\2715";
}
Bekijk Snippet

Javascript inladen in Magento module

JavaScript inline inladen in module.
https://gitlab.indenty.nl/magento/OciPunchout/-/commit/b1a965af837ea9586e6fccb42b12f366f08ae91f

====================

In je .phtml bestand:

Hetgeen in de JS Snippet

====================

Dan in je require-config.js

var config = {
    map: {
        '*': {
            'oci_post': 'Gladior_OciPunchout/js/post'
        }
    }
};

====================

En dan in je module:

define([] , function ($) {
    return function () {
        document.getElementById("oci-submitbutton").style.display="none";
        document.getElementById("oci-checkout").submit()
    };
});

JAVASCRIPT Code

javascript
<script type="text/x-magento-init">
    {
        "*": {
            "oci_post": {}
        }
    }
</script>
Bekijk Snippet

IP adres blokkeren op server (triplehosting)

Als server er uit vlieg, kun je kijken naar een IP adres met heel veel connecties.

0. Zet httpd uit onder > Service Monitor
1. Message System
2. Kijk naar een ticket met titel 'Warning: The system load average is 47.31'
3. Kijk naar een IP adres met veel connecties
4. Wil je hem blokkeren? 
5. Ga in Direct Admin naar > Extra Featues > ConfigServer Security & Firewall
6. Quick Deny > Vul hier het IP adres in met reden
7. Start nu pas de httpd weer op (anders werkt de block niet)
Bekijk Snippet

Icon-before (1cap hoogte)

CSS Code

css
.icon-before {
	height: 1cap;
	aspect-ratio: 1;
	background-repeat: no-repeat;
	background-position: center;
	.d-block;
	.transition();
	
	&.share {
    	.share(@escaped_secondary_clr);
		&:hover,
		&:focus {
		  .share(@escaped_main_clr);
		}
  	}
	&.facebook {
    .facebook(@escaped_secondary_clr);

    &:hover,
    &:focus {
      .facebook(@escaped_main_clr);
    }
  }
}
Bekijk Snippet

Hostfile aanpassen voor IP manipulatie

Open Kladblok als administrator.
In Windows 10 the hosts file is located at:

C:\Windows\System32\Drivers\etc\hosts
Bekijk Snippet

Google Tag Manager (GTM) inladen optimalisatie

JAVASCRIPT Code

javascript
<script>
function loadGTM() {
    // GTM code hier
}

const events = ['scroll', 'mousemove', 'click', 'touchstart'];

function interaction() {
    events.forEach(event => window.removeEventListener(event, interaction));
    clearTimeout(timeout);
    loadGTM();
}

const timeout = setTimeout(loadGTM, 5000);
events.forEach(event => window.addEventListener(event, interaction));
</script>
Bekijk Snippet

Styling van filters (checkbox)

CSS Code

css
label.checkbox {
    padding-left: 1em;
    &:before {
        position: absolute;
        transition: all 0.2s ease-in-out;
        content: '';
        height: 0.75em;
        width: 0.75em;
        left: 0;
        top: 50%;
        translate: 0 -50%;
        background-color: var(--grey);
        border: 1px solid var(--yellow);
        border-radius: 50%;
    }
}
input[type="checkbox"] {
    height: 0;
    width: 0;
    &:checked {
        &~label {
            &:before {
                background-color: var(--yellow);
                border: 1px solid var(--yellow);      
            }
        }
    }
}
Bekijk Snippet

Email validatie (AFAS) Regex

Email check regex
OUD: pattern="[^@\s]+@[^@\s]+\.[^@\s]{2,}


Hij checkt nu op minimaal 2 karakters achter de .

dus a@a.a is fout
maar a@a.aa is goed



=== UPDATE 12-9-2023 ===
pattern="[A-Za-z0-9!#$&.+-=_]+@[A-Za-z0-9.-]+\.[^@\s]{2,}"

Hier wordt extra gecheckt op dat het stuk voor het @-teken enkel de karakters !#$&.+-=_ bevat.
Een ~ wordt bijv. niet geaccepteerd door AFAS
Bekijk Snippet

ElasticSearch instellingen (locatie)

Elastic Search instellen:

Stores > Configuration > Catalog > Catalog > Catalog Search
Bekijk Snippet

Cookiebot styling met LESS CSS variabelen

CSS Code

css
@main_clr #748375;

@secondary_clr #EEF0EC;

@escaped_secondary_clr escape(~@{secondary_clr});

@root_font_family Avenir, Avenir, Sans-serif;

@grey_clr #525157;

@light_clr #FFF;

@escaped_light_clr escape(~@{light_clr});

 

.bg-properties(@size contain) {

  background-repeat no-repeat;

  background-position center;

  background-size @size;

}

 Voor Less compiler httpslesscss.orgless-preview 

 

 

 COOKIEBOT STYLING 
 
body {
  #CybotCookiebotDialogHeader {
    background-color @main_clr;
  }
  #CybotCookiebotDialogPoweredbyLink {
    width 250px;
        background-position center left;
    height 48px;
    .bg-properties();
    background-image url('wp-contentuploads202205WRANGU-logo-white_text-Use-on-dark-background-only.png');
  }
  #CybotCookiebotDialogPoweredbyImage {
    opacity 0;
  }
  #CybotCookiebotDialog {
    border-radius 1em;
    outline 1000vh solid fadeout(@main_clr, 80%);
    .CybotCookiebotScrollContainer {
      border unset;
    }
    .CookieCard {
      button {
        &after {
          content unset;
        }
      }
    }
  }
  #CybotCookiebotDialogPoweredbyCybot {
        path {
      fill white;
        }
  }
  #CybotCookiebotDialog,
  #CybotCookiebotDialogBodyUnderlay {
     {
      font-family @root_font_family;
    }
  }
  #CybotCookiebotDialogNav {
    .CybotCookiebotDialogNavItemLink {
      &hover {
        color @secondary_clr;
      }
      &.CybotCookiebotDialogActive {
        color @main_clr;
        border-color @main_clr;
      }
    }
  }
  #CybotCookiebotDialogHeader {
    border-color @grey_clr;
  }
  #CybotCookiebotDialogNav {
    border-color @grey_clr;
  }
  #CybotCookiebotDialogTabContent {
    .CybotCookiebotDialogBodyLevelButtonSlider {
      background-color @grey_clr;
    }
    input {
      &checked {
        &+.CybotCookiebotDialogBodyLevelButtonSlider {
          background-color @secondary_clr;
        }
      }
    }
  }
  #CybotCookiebotDialogFooter {
    #CybotCookiebotDialogBodyButtonAccept, #CybotCookiebotDialogBodyLevelButtonAccept,
    #CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll {
      .bg-secondary;
      border-color @secondary_clr;
      &after {
        background-image url(dataimagesvg+xml,%3Csvg xmlns='httpwww.w3.org2000svg' width='11.708' height='11.708' viewBox='0 0 11.708 11.708'%3E%3Cpath id='Path_3565' data-name='Path 3565' d='M5.854,0,4.79,1.064,8.819,5.094H0V6.614H8.819L4.79,10.644l1.064,1.064,5.854-5.854Z' fill='@{escaped_light_clr}'%3E%3Csvg%3E%0A);
      }
    }
     #CybotCookiebotDialogBodyLevelButtonCustomize,#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection,
     .CybotCookiebotDialogBodyButton {
      border-color @light_clr;
      background-color @light_clr;
      color @secondary_clr;
      &after {
        background-image url(dataimagesvg+xml,%3Csvg xmlns='httpwww.w3.org2000svg' width='11.708' height='11.708' viewBox='0 0 11.708 11.708'%3E%3Cpath id='Path_3565' data-name='Path 3565' d='M5.854,0,4.79,1.064,8.819,5.094H0V6.614H8.819L4.79,10.644l1.064,1.064,5.854-5.854Z' fill='@{escaped_secondary_clr}'%3E%3Csvg%3E%0A);
      }
      .CybotCookiebotDialogArrow {
        display none;
      }
    }
    .CybotCookiebotDialogBodyButton {
      padding .75em 3em .75em 1.5em;
      border-radius 1em;
      border-width 1px;
      font-weight 700;
    }
    position relative;
    margin-top 3em;
  }
}
 
 END COOKIEBOT STYLING 
Bekijk Snippet

Cookiebot styling met CSS variabelen

CSS Code

css
<style>
  /* COOKIEBOT STYLING */
:root {
  --main_clr: #714B94;
  --secondary_clr: #93C01A;
  --grey_clr: #abb8c3;
  --light_clr: #fff;
  }
  
body {
    #CybotCookiebotDialogHeader {
        background-color: var(--main_clr);
    }

    #CybotCookiebotDialogPoweredbyLink {
        width: 250px;
        background-position: center left !important;
        height: 48px;
        background-repeat: no-repeat;
        background-size: contain;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='168.601' height='49.74' viewBox='0 0 168.601 49.74'%3E%3Cpath d='M62.316,32.456c4.552,0,6.419.526,8.4,2.278C72.7,36.6,73.7,39.4,73.7,43.37V60.878H65.874V42.493c0-2.857-1.165-3.965-4.025-3.965H55.08V60.878H47.257V32.456Z' transform='translate(-31.736 -21.796)' fill='%23033b40'%3E%3C/path%3E%3Cpath d='M316.635,32.456h7.822V60.878h-15.35c-4.552,0-6.422-.526-8.4-2.278-1.983-1.867-2.976-4.667-2.976-8.636V32.456h7.819V50.722c0,2.569,1.4,4.085,3.738,4.085h7.352Z' transform='translate(-199.944 -21.796)' fill='%2393c01a'%3E%3C/path%3E%3Cpath d='M424.207,38.521h-13.89c-3.5,0-4.32.467-4.32,2.509a2.511,2.511,0,0,0,1.284,2.334c.526.351,1.4.467,3.794.467h4.611c6.243,0,9.805,2.92,9.805,8.114,0,3.387-1.811,6.77-4.376,8.054-1.169.642-3.151.874-6.6.874H398.354V54.8h13.89a18.85,18.85,0,0,0,4.2-.235,2.055,2.055,0,0,0,1.4-2.158,2.656,2.656,0,0,0-1.341-2.449c-.586-.295-1.4-.351-3.387-.351h-4.783c-3.622,0-5.313-.411-7-1.636a8.737,8.737,0,0,1-3.387-7.236,8.688,8.688,0,0,1,3.1-6.829c1.341-1.049,3.092-1.46,6.478-1.46h16.691Z' transform='translate(-267.246 -21.792)' fill='%2393c01a'%3E%3C/path%3E%3Cpath d='M147.838,78.8l7.107-7.107h17.765a10.658,10.658,0,0,0,0-21.316H165.6a3.553,3.553,0,0,1,0-7.107h7.107a17.764,17.764,0,0,1,0,35.529Z' transform='translate(-99.283 -29.059)' fill='%2393c01a'%3E%3C/path%3E%3Cpath d='M165.6,7.107a10.658,10.658,0,0,0,0,21.316h7.107a3.553,3.553,0,0,1,0,7.107H165.6A17.765,17.765,0,0,1,165.6,0h24.871l-7.107,7.107Z' transform='translate(-99.282 0)' fill='%23033b40'%3E%3C/path%3E%3Crect width='7.819' height='7.107' transform='translate(0 0.002)' fill='%23033b40'%3E%3C/rect%3E%3Crect width='7.819' height='28.422' transform='translate(0 10.66)' fill='%23033b40'%3E%3C/rect%3E%3Cpath d='M497.932,103.379c.432,0,.589-.109.589-.407s-.14-.4-.589-.4h-.821v.807Zm-.821,1.677h-.635v-2.98h1.442a1.762,1.762,0,0,1,.916.165l.375.681a.792.792,0,0,1-.579.8c.351.133.5.383.526.863a.865.865,0,0,0,.1.47h-.691l-.021-.056-.032-.158-.025-.224c-.056-.565-.291-.744-.958-.744h-.421Zm-1.821-1.491a2.48,2.48,0,1,0,2.52-2.52,2.508,2.508,0,0,0-2.52,2.52m5.541,0a3.062,3.062,0,1,1-3.011-3.039,3.044,3.044,0,0,1,3.011,3.039' transform='translate(-332.23 -67.51)' fill='%23033b40'%3E%3C/path%3E%3C/svg%3E");
    }

    #CybotCookiebotDialogPoweredbyImage {
        opacity: 0;
    }

    #CybotCookiebotDialog {
        border-radius: 1em;

        .CybotCookiebotScrollContainer {
            border: unset;
        }

        .CookieCard {
            button {
                &::after {
                    content: unset;
                }
            }
        }
    }

    #CybotCookiebotDialogPoweredbyCybot {
        path {
            fill: white;
        }
    }

    #CybotCookiebotDialog,
    #CybotCookiebotDialogBodyUnderlay {
        * {
            font-family: "archivo", "Open Sans", Helvetica, Arial, sans-serif;
        }
    }

    #CybotCookiebotDialogNav {
        .CybotCookiebotDialogNavItemLink {
            &:hover {
                color: var(--secondary_clr);
            }

            &.CybotCookiebotDialogActive {
                color: var(--main_clr);
                border-color: var(--main_clr);
            }
        }
    }

    #CybotCookiebotDialogHeader {
        border-color: var(--grey_clr);
    }

    #CybotCookiebotDialogNav {
        border-color: var(--grey_clr);
    }

    #CybotCookiebotDialogTabContent {
        .CybotCookiebotDialogBodyLevelButtonSlider {
            background-color: var(--grey_clr);
        }

        input {
            &:checked {
                &+.CybotCookiebotDialogBodyLevelButtonSlider {
                    background-color: var(--secondary_clr);
                }
            }
        }
    }

    #CybotCookiebotDialogFooter {

        #CybotCookiebotDialogBodyButtonAccept,
        #CybotCookiebotDialogBodyLevelButtonAccept,
        #CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll {
            background-color: var(--secondary_clr);
            border-color: var(--secondary_clr);
        }

        #CybotCookiebotDialogBodyLevelButtonCustomize,
        #CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection,
        .CybotCookiebotDialogBodyButton {
            border-color: var(--light_clr);
            background-color: var(--light_clr);
            color: var(--secondary_clr);

            .CybotCookiebotDialogArrow {
                display: none;
            }
        }

        .CybotCookiebotDialogBodyButton {
            padding: .75em 1.5em;
            border-radius: 1em;
            border-width: 1px;
            font-weight: 700;
        }

        position: relative;
        margin-top: 3em;
    }
}

/* END COOKIEBOT STYLING */
</style>
Bekijk Snippet

Composer forceren

Als een normale composer update niet werkt, kun je via een hogere PHP versie updaten.
Dit doe je zo:

which composer
- /usr/local/bin/composer

En dan:
php8.1 /usr/local/bin/composer update amasty/module-abandoned-cart-email-subscription-package
Bekijk Snippet

Block ophalen uit Magento

PHP Code

php
$submenu = $this->getLayout()->createBlock('Magento\Cms\Block\Block')->setBlockId('default-submenu')->toHtml();
Bekijk Snippet

Afbeelding inladen

Een snippet die laat zien hoe je een goede afbeelding plaatst die ook de mindere grote variant toont op kleine schermen.

HTML Code

html
<picture>
  <source media="(max-width: 768px)" srcset="<?= $afbeelding['sizes']['medium'];?>">
  <img src="<?= $afbeelding['url']; ?>" alt="<?= $afbeelding['alt'];?>" aria-label="" loading="lazy" width="300" height="150">
</picture>

CSS Code

css
.image {
  .cover-img;
}
Bekijk Snippet