1

I want to render product content type in a custom block with a custom view mode. I have a field product_teaser in my article content type that reference the product that is I want to render in the custom block using advert view mode

The content type to be rendered: "product"

The view mode to be rendered with: "advert"

The product teaser only contains an image and a buy=now button I can easily place using twig. So placing only the image in the render of the custom block should be enough for this to work But I have been trying to render the image for a while and I could not do it.


This is my first approach to do this, Rendering the whole product advert.

  public function build() {
    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node instanceof \Drupal\node\NodeInterface) {
      $view_mode = 'advert';
      $product_id = $node->get('field_product_teaser')->getValue()[0]['target_id'];
      $product = \Drupal::entityTypeManager()->getStorage('node')->load($product_id);
      $view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
      $pre_render = $view_builder->view($product, $view_mode);
      $render_output = render($pre_render);
      return $render_output;
    }
    return [];
  }

Render output is an empty string for some reason. $pre_render has got view mode and node array having all the product fields, everything looks good except that render($pre_render) return an empty spaces string. This is the error being output from this approach "Argument 1 passed to Drupal\Core\Render\Element::isEmpty() must be of the type array, object given"


My second approach was to get the image URI of the product advert and render it manually

$build= array();      
    //Gets current node to check for which product to be displayed.
    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node instanceof \Drupal\node\NodeInterface) {
      $product_id = $node->get('field_product_teaser')->getValue()[0]['target_id'];
      $product = \Drupal::entityTypeManager()->getStorage('node')->load($product_id);
      $product_advert_url = $product->field_teaser->entity->url();
    }


    $build['image'] = [
      '#theme' => 'image_style',
      '#style_name' => 'thumbnail',
      '#uri' => $product_advert_url
    ]; 

    return $build;

This is the error being output from this approach "Class name must be a valid object or a string in Drupal\image\Entity\ImageStyle->buildUri()"


How to fix these errors ??, I prefer the first method because it will be easier if I needed to add anything to the product teaser later.

1 Answer 1

2

You can do this in a View block. Add a contextual filter for the content id and configure it to provide the default value "Content ID from URL":

enter image description here

The view mode Teaser would be in your case a custom view mode (for the content type "article") only containing the product teaser field, configured to render the target entity in a second view mode "advert" (now for the content type "product").


If you want to do this in code, then get the node from a context plugin (see this great answer from @Berdir https://drupal.stackexchange.com/a/188629/47547) and build the render array (if you use the view modes mentioned above you only need one line of code). Very important, never render in Drupal 8, always return unrendered arrays.

6
  • I tried to do it in a view, with no luck, the contextual filter was not working i am trying to do this condition in the filter (( Product id == article.field_product_teaser )) Nov 6, 2017 at 8:08
  • My suggestion is about a simple contextual filter for the article and then render it again, but in a different view mode only containing the product teaser field.
    – 4uk4
    Nov 6, 2017 at 8:19
  • I got the view setup to render max 3 adverts of products but it's not rendering any I think my contextual filter is wrong, I choose the " Content: Product teaser (field_product_teaser) " but I cannot figure out how to make it do {{ Product id == article.field_product_teaser }}, sry haven't dealt with contextual filters too much Nov 6, 2017 at 9:05
  • My suggestion was to configure the most basic contextual filter for the current node. What you are trying to do is to join both content types in a relationship. You might consider asking a question about this, I think someone here can help if you provide more details.
    – 4uk4
    Nov 6, 2017 at 9:26
  • I am sorry can you elaborate more on your suggestion, I cannot understand how should I configure the most basic contextual filter, could I use the contextual filter to do what I need? I added a relationship to get the field_product_teaser from the article data type but I am not sure how I could advance? Nov 6, 2017 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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