3

I have a view (my_view) with the following displays:

  1. master
  2. page_1

I am looking for a way to programmatically duplicate page_1.

    $view = Views::getView('my_view');
    $storage = $view->storage;
    $display = &$storage->getDisplay('page_1');
    // Create a new display. 
    // Remove some exposed filters from the new display.
    // save the view.

How can I achieve this?

  • After you have programmatically duplicated the view, what do you want to do with it? Do you want to display its output only? I notice in you code, you have the comment, save the view. Do you mean you want to save it such that when you go back to the UI of that view, you have a new display, one that was created programmatically? – user1359 Feb 19 at 19:57
1

The View entity comes with a handy function for duplicating an existing display, ->duplicateDisplayAsType().

->duplicateDisplayAsType() requires 2 arguments--ID of the display to duplicate & new display's type. First one is self-explanatory--if you want to duplicate something, you need to know what you want to duplicate (visit a View and look at the URL for the unique ID). For the second arg, a View Display needs to be of a certain type--page, block, feed, etc.

Finally, we have something like below:

$commentView = \Drupal::entityTypeManager()->getStorage('view')->load('comment');

// ->duplicateDisplayAsType() returns the new display's ID so it's not 100% necessary
//   to assign the return val to a variable.
$new_page = $commentView->duplicateDisplayAsType('page_published', 'page');
$new_block = $commentView->duplicateDisplayAsType('page_published', 'block');

$commentView->save();

Above, I am using the default 'Comments' view and duplicating the 'page_published' Display as both a new page and new block. Try copy pasting the above code into a Controller and triggering the controller method once and visit the View to see your new Displays.

Finally, as with most entity operations, you'll want to ->save() it afterwards.

Note: Using (presumably) \Drupal\views\Views::getView() will return a ViewExecutable--aka a configured View which is used for generating the actual output. You cannot edit the View's config via ViewExecutable. Above, I am using the entityTypeManager() to query for a View so I can retrieve the actual Entity so we can modify its configuration. The above code can act as boilerplate--try switching out values to achieve your desired goal.

EDIT: To answer your question more definitively, the above example code could be translated to match your code snippet:

$view = \Drupal::entityTypeManager()->getStorage('view')->load('my_view');
$new_page = $view->duplicateDisplayAsType('page_1', 'page');

$view->save();

Edit 2: Sorry, I didn't answer your second part--how do we modify the display after duplicating. This may not be the most efficient way so someone please tell me if there is a better way to do it. Luckily you want to only remove a filter. Because filters are not yet OOP, they're just giant arrays with specific keys you need to set. This part does get a bit more complicated.

There is one thing you need to keep in mind though--the default display will apply its display_options across all displays unless you override them in the 'defaults' array on the specific display configuration. You can override defaults for each display_option so you can still inherit defaults for some properties while overriding others.

For comments, specifically, the filters are all placed on the 'default'. Out of the box, the Comments view only comes with the page_published display. Let's say we want to duplicate the page_published display, copy over the filters from the original display, remove its default filters, and then array_pop() one of the filters off our new display. So starting from scratch again:

$view = \Drupal::entityTypeManager()->getStorage('view')->load('comment');
$new_display_id = $view->duplicateDisplayAsType('page_published', 'page');
// Must use the getter--the display property is protected
// We assign by reference because there is no setter--we cannot set the display
//   options again after modifying but we can modify the referenced var to change
//   the original values
$new_display = &$view->getDisplay($new_display_id);
$default_display = &$view->getDisplay('default');
// Copy the filters from the 'default' to the new display
$new_display['display_options']['filters'] = $default_display['display_options']['filters'];
$new_display['display_options']['filter_groups'] = $default_display['display_options']['filter_groups'];

// Tell Views not to use the defaults for these two specific properties
$new_display['display_options']['defaults'] = [
  'filters' => FALSE,
  'filter_groups' => FALSE,
];

// For demonstration purposes, we remove 1 filter from our copied over filters
array_pop($new_display['display_options']['filters']);

$view->save();

You should see a page exactly like the page_published except it should be missing 1 filter.

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.