1

I have a matrix block called team that has an assets field within it that has all of the companies headshots. However, there are more than 30 images, but the design is to only have 6 showing on load, and then on click of a load more button the next 6 will show, etc.

However, I'm not sure how to achieve this within a matrix block as all the examples I've seen elsewhere are for pages and sections. But I just need to load the images from within the matrix block.

Below is my code for the images. Can someone help?

{% for headshot in block.headshots %}
<figure class="team__headshots">
  {% if headshot | length %}
  {% set transformedImages = craft.imager.transformImage(headshot,
      [
          { width: 180, ratio: 4/5 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  {% set tabletl = craft.imager.transformImage(headshot,
      [
          { width: 142, ratio: 4/5 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  {% set tabletp = craft.imager.transformImage(headshot,
      [
          { width: 230, ratio: 4/5 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  {% set mobile = craft.imager.transformImage(headshot,
      [
          { width: 360, ratio: 4/5, jpegQuality: 65 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          position: headshot.focalPoint,
          interlace: true
      }
  ) %}
  <picture>
  <source srcset="{{ craft.imager.srcset(mobile) }}" media="(max-width: 767px)">
  <source srcset="{{ craft.imager.srcset(tabletp) }}" media="(min-width: 768px) and (max-width: 991px)">
  <source srcset="{{ craft.imager.srcset(tabletl) }}" media="(min-width: 992px) and (max-width: 1199px)">
  <img class="img-responsive"
       src="{{ transformedImages[0].url }}"
       sizes="(min-width: 768px) 33.3vw, 50vw"
       alt="{% if headshot.altTag|length %}{{ headshot.altTag }}{% else %}{{ headshot.title }}{% endif %}"
       width="100%">
  </picture>
  {% endif %}
  <div class="team__headshots-overlay">
    <div class="team__headshots-captions">
      <h4>{{ headshot.title }}</h4>
      <p>{{ headshot.jobTitle }}</p>
    </div>
  </div>
</figure>
{% endfor %}
2

Your block.headshots is not an array of all images, you have to understand what craft does in order to work properly with it.

block.headshots and all other relations (Matrix elements, images, category links...) are all elementCriteriaModels so instead of having an array of objects - your block.headshots is just a single object that has an iterator interface.

So when you execute {% for headshot in block.headshots %} it performs the .find() function and returns an array. Unfortunately I'm not on my computer currently so I can't provide the exact code so maybe the syntax of something of the following might be wrong, but if you know how to search entries with craft.entries.find() click you can correct it, here you have more examples elementCriteriaModel. Your code should look like

{% for headshot in block.headshots.find({limit: 10}) %}

It does not matter if you are searching pages (entries), assets, matrix blocks, sections, categories or whatever.. Craft does always the same, building an elementCriteriaModel that is executed as soon as you loop through it.

edit: your controller to load the assets could look like this

public function actionLoadAssets(){
    $this->requireAjaxRequest();
    $response = array(
        'success'   => false,
        'message'   => ''
    );

    // config how many entries should be loaded
    $config = craft()->globals->getSetByHandle('config');
    $limit = $config['countReloadImages'];
    // offset.. how many did we load already
    $offset = craft()->request->getPost('offset');
    // which block is it
    $matrixIndex = craft()->request->getPost('matrixIndex');
    // entryId
    $entryId = craft()->request->getPost('entryId');

    if($entry = craft()->elements->getElementById($entryId)){
        // search for the correct field -> we just insert an offset
        // this is untested, maybe you have to play around with the correct number
        // I'm not sure if you can just send the id of the matrixfield and use 'id' => $matrixIndex
        // you could to try it out...
        $matrix = $entry->team->find([
            'offset'    => $matrixIndex
        ]);
        $html = '';
        if($matrix && ($assets = $matrix->headshot->find(['offset' => $offset, 'limit' => $limit]))){
            // build a template to render the images, you'll return the html
            $html = $this->renderTemplate('some tempalte here', array(
                'asset' => $assets
            ));
        }
        // you could include your logic if you found less entries than configured ($limit) and return a "hide reload button"
        $response['html'] = $html;
        $response['success'] = true;
    }else{
        $response['message'] = Craft::t('could not find entry with Id ' . $entryId);
    }

    return $response;
}

Edit2: I found a better solution:

public function actionLoadMore(){
    $criteria = craft()->elements->getCriteria(ElementType::Asset);
    // id of your field headtshot
    $field = craft()->fields->getFieldById(5);

    $criteria->relatedTo = array(
        'sourceElement' => //your matrix ID,
        'field'         => $field->id
    );
    $criteria->offset = //your offset;
    $criteria->limit = //your limit;
    $assets = $criteria->find();

    // render template -> return html look at the first example
}
| improve this answer | |
  • Thanks Robin, that's extremely detailed, so I appreciate the effort you've put in. However, I didn't realise that I'd need to create a plugin for it. Seems a lot to do for a load more button. So I'll need to continue to investigate if there's any simpler options maybe via javascript instead. – mention79 Oct 21 '17 at 12:23
  • well its only one function. You only need to create a plugin with pluginfactory.io and insert it. – Robin Schambach Oct 21 '17 at 12:29
  • Ok thanks, will give it a go. But it's not something I've done before, so hard to get my head around. But I'm always willing to learn. So will try. – mention79 Oct 21 '17 at 12:32
  • Ok I see... The first time with craft might be a little bit confusing. It took me a long time until I understood it (especially the routings sometimes) but once you learn how it works, things will get much easier. For example searching entries in twig (like you want) will be clearer. Btw I found a better solution to search for the images, the logic for finding the assets is in my 2. edit. – Robin Schambach Oct 21 '17 at 12:43
  • I've found a javascript way that works too. jsfiddle.net/cse_tushar/6FzSb – mention79 Oct 21 '17 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.