Quantcast
Channel: Issues for Drupal core
Viewing all 297657 articles
Browse latest View live

Multilingual Migrations for Non-Drupal Sources

$
0
0

Motivation

So there's a flurry of activity concerning multilingual Drupal content from D6 & D7 being properly migrated (#2208401: [META] Remaining multilingual migation paths), but I'm not seeing much if anything concerning non-Drupal imports for multilingual content. Point of fact, I'm having trouble coming up with good examples of how multilingual migrations are intended to work, let alone actual working examples using Drupal or other sources.

Proposed resolution

I'd like to use this thread to compile migration solutions or examples that successfully implement multilingual content. Ultimately, that would become a documentation page, or depending on how things go a feature request or module.

Groundwork

So since I had an immediate need and was looking for solutions I ended up finding #2313265: How import Multilingual Content with Migrate Module. While it originated Pre-D8, @digitaldonkey had a good solution for a POST_ROW_SAVE event in D8. I liked it, but it wasn't flexible enough for me to I took it and made it a little more broadly based. I updated the 'updateTranslations' function of the original:

/**
   * MigrateEvents::POST_ROW_SAVE event handler.
   *
   * @param MigratePostRowSaveEvent $event
   *   Instance of Drupal\migrate\Event\MigratePostRowSaveEvent.
   */
  public function updateTranslations(MigratePostRowSaveEvent $event) {

    $row =  $event->getRow();

    if ($row->hasSourceProperty('constants/available_languages')) {

      // These are defined in migration.yml.
      $available_languages = $row->getSource()['constants']['available_languages'];
      $default_language = $row->getDestination()['langcode'];

      // Unset default language from available languages.
      unset($available_languages[$default_language]);

      $migrated_entity = $event->destinationIdValues[0];
      $dest_config = $event->getMigration()->getDestinationConfiguration();
      $dest_plugin = explode(':', $dest_config['plugin']);

      if ($dest_plugin[0] == 'entity') {
        $entity = \Drupal::entityTypeManager()
          ->getStorage($dest_plugin[1])
          ->load($migrated_entity);

        foreach ($available_languages as $key => $lang_map) {

          $translated_entity = $entity->addTranslation($key);
          foreach ($lang_map as $field => $source) {
            $translated_entity->$field = $row->getSourceProperty($source);
          }
          $translated_entity->save();

        }

        $map = $event->getMigration()->getIdMap();
        $map->saveIdMapping($event->getRow(), array($migrated_entity));
      }
    }
  }

What this allows you to do is declare translations in your YAML file by adding available translations as constants. So your source would look something like

source:
  ...
  constants:
    available_languages:
      en:
      es:
        title: title_spanish

Where title is the name of the field you're entering and title_spanish would be the field coming in from the source. This is perfect for a lightweight translation of content from the same source. Note that it only works on entities and that the main langcode MUST be set in the process.

For bulkier translations that need processing or those coming from a different source, I put together a custom destination. This takes a separate migration and appends identically ID'd translations to it.


namespace Drupal\custom_migrate\Plugin\migrate\destination;

use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Core\Entity\DependencyTrait;
use Drupal\migrate\Plugin\MigratePluginManager;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;

/**
 * Provides Configuration Management destination plugin.
 *
 * Persist data to the config system.
 *
 * When a property is NULL, the default is used unless the configuration option
 * 'store null' is set to TRUE.
 *
 * @MigrateDestination(
 *   id = "entity_translation"
 * )
 */
class EntityTranslation extends DestinationBase implements ContainerFactoryPluginInterface, DependentPluginInterface {

  use DependencyTrait;

  /**
   * The config object.
   *
   * @var \Drupal\migrate\Plugin\MigrationInterface
   */
  protected $old_migration;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $language_manager;

  /**
   * The process plugin manager.
   *
   * @var \Drupal\migrate\Plugin\MigratePluginManager
   */
  protected $processPluginManager;

  /**
   * The migration plugin manager.
   *
   * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
   */
  protected $migrationPluginManager;

  /**
   * Constructs a Config destination object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin ID for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
   *   The migration entity.
   * @param \Drupal\Core\Language\ConfigurableLanguageManagerInterface $language_manager
   *   The language manager.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManager $process_plugin_manager, LanguageManagerInterface $language_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
    $this->migrationPluginManager = $migration_plugin_manager;
    $this->migration = $migration;
    $this->processPluginManager = $process_plugin_manager;
    $this->language_manager = $language_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $migration,
      $container->get('plugin.manager.migration'),
      $container->get('plugin.manager.migrate.process'),
      $container->get('language_manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function import(Row $row, array $old_destination_id_values = array()) {
    
    $migration_id = $this->configuration['migration'];
    $migration = $this->migrationPluginManager->createInstance($migration_id);

    // TODO: I think this only works right now if the keys and key labels match, so I'll need to expand later
    $source_id_values = $row->getSourceIdValues();

    $destination_ids = $migration->getIdMap()->lookupDestinationID($source_id_values);

    $dest_config = $migration->getDestinationConfiguration();
    $dest_plugin = explode(':', $dest_config['plugin']);

    $entity = \Drupal::entityTypeManager()
      ->getStorage($dest_plugin[1])
      ->load($destination_ids[0]);

    $lang = $row->getDestinationProperty('langcode');

    // TODO: Validate langcode against list of site languages

    $translated_entity = $entity->addTranslation($lang, $row->getDestination());
    $translated_entity->save();

    return $destination_ids;

  }

  /**
   * {@inheritdoc}
   */
  public function fields(MigrationInterface $migration = NULL) {
    // @todo Dynamically fetch fields using Config Schema API.
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $ids['config_name']['type'] = 'string';
    return $ids;
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    $provider = explode('.', $this->config->getName(), 2)[0];
    $this->addDependency('module', $provider);
    return $this->dependencies;
  }

}

It's still very rough, but once it's in place you can use it to translate entities by adding this destination:

destination:
  plugin: entity_translation
  migration: original_content

Where original_content is the targeted migration. Note that it's still very rough, but is certainly a step in the right direction. Once again, it will only work for entities and the langcode needs to be set in the process.


Allow logging for non-strings values

$
0
0

Currently the migrate\process\Log class is only able to log string values, not even NULL are accepted, this is pretty limiting because often the log plugin can be used for quick debug of complex migrations.

The solution is imho simple, if the value is not a string pass it through print_r and store the dumped value.

(patch coming shortly)

LanguageContentSettingsTaxonomyVocabulary source plugin should only add language column if it exists

$
0
0

Problem/Motivation

The relevant part of the error message from the original IS is that the language column is unknown.

Migration failed with source plugin exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'v.language&#03

Proposed resolution

Change the source plugin to check that the language column exists before adding it to the select. The language column is only there when the i18ntaxonomy module is enabled so we really should test for it.

Remaining tasks

Review
Commit

Following is the orginal IS:

I wrote this in the related issue, but it probably merits its own issue. I got the following errors when upgrading from D6.52 to D8.8.0:

Upgrading upgrade_d6_language_content_taxonomy_vocabulary_settings
 [error]  Migration failed with source plugin exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'v.language' in 'field list': SELECT v.vid AS vid, v.language AS language, map.sourceid1 AS migrate_map_sourceid1, map.source_row_status AS migrate_map_source_row_status
FROM
{vocabulary} v
LEFT OUTER JOIN d8.migrate_map_upgrade_d6_language_content_taxonomy_vocabulary_set map ON vid = map.sourceid1
WHERE (map.sourceid1 IS NULL) OR (map.source_row_status = :db_condition_placeholder_0); Array
(
    [:db_condition_placeholder_0] => 1
)
 
Upgrading d6_google_analytics_user_settings
Upgrading upgrade_d6_language_negotiation_settings
Upgrading d6_language_content_settings
Upgrading upgrade_d6_menu
Upgrading language_prefixes_and_domains
Upgrading upgrade_d6_menu_links
Upgrading d6_language_negotiation_settings
Upgrading upgrade_d6_node_revision_bild
Upgrading d6_taxonomy_vocabulary
Upgrading upgrade_d6_node_revision_bildspel
Upgrading d6_language_content_taxonomy_vocabulary_settings
 [error]  Migration failed with source plugin exception: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'v.language' in 'field list': SELECT v.vid AS vid, v.language AS language, map.sourceid1 AS migrate_map_sourceid1, map.source_row_status AS migrate_map_source_row_status
FROM
{vocabulary} v
LEFT OUTER JOIN d8.migrate_map_d6_language_content_taxonomy_vocabulary_settings map ON vid = map.sourceid1
WHERE (map.sourceid1 IS NULL) OR (map.source_row_status = :db_condition_placeholder_0); Array
(
    [:db_condition_placeholder_0] => 1
)
 

composer.json:

"require": {
        "composer/installers": "^1.2",
        "drupal/captcha": "^1.0@beta",
        "drupal/core-composer-scaffold": "^8.8",
        "drupal/core-project-message": "^8.8",
        "drupal/core-recommended": "^8.8",
        "drupal/devel": "^2.1",
        "drupal/google_analytics": "^3.0",
        "drupal/migrate_plus": "^5.0",
        "drupal/migrate_tools": "^5.0",
        "drupal/migrate_upgrade": "^3.1",
        "drupal/pathauto": "^1.6",
        "drupal/semanticviews": "^2.2",
        "drupal/simple_reservation": "*",
        "drupal/smtp": "^1.0@beta",
        "drush/drush": "^9.0"
    },

PHP 7.3.12
MySQL 5.7.28
Server nginx/1.14.0

Migrate d7 menu translation

$
0
0

Problem/Motivation

The d7 menu translations need a migration

Replace assert*() involving greater/less comparison operators with assert(Greater|Less)Than(OrEqual)

$
0
0

Problem/Motivation

As title

Proposed resolution

Regex for searching: assert.+\(count\(.+\) (>=|<=) \d+\)

example:

-    $this->assertTrue(count($cache_items) >= 2);
+    $this->assertGreaterThanOrEqual(2, count($cache_items));

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Private default image is inaccessible

SQL error if migration has too many ID fields

$
0
0

Problem/Motivation

Drupal\migrate\Plugin\migrate\id_map\Sql::ensureTables() creates a secondary index that includes all id fields for a migration. If too many fields are included (e.g. more than three VARCHAR(255) columns), the data size may exceed the maximum allowed in an index and result in an exception.

Uncaught PHP Exception Drupal\\Core\\Database\\DatabaseExceptionWrapper: "SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 3072 bytes: CREATE TABLE {migrate_map_migrationname} (\n`source_ids_hash` VARCHAR(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key', \n`sourceid1` VARCHAR(255) NOT NULL, \n`sourceid2` VARCHAR(255) NOT NULL, \n`sourceid3` VARCHAR(255) NOT NULL, \n`sourceid4` VARCHAR(255) NOT NULL, \n`sourceid5` VARCHAR(255) NOT NULL, \n`destid1` INT unsigned NULL DEFAULT NULL, \n`source_row_status` TINYINT unsigned NOT NULL DEFAULT 0 COMMENT 'Indicates current status of the source row', \n`rollback_action` TINYINT unsigned NOT NULL DEFAULT 0 COMMENT 'Flag indicating what to do for this item on rollback', \n`last_imported` INT unsigned NOT NULL DEFAULT 0 COMMENT 'UNIX timestamp of the last time this row was imported', \n`hash` VARCHAR(64) NULL DEFAULT NULL COMMENT 'Hash of source row data, for detecting changes', \nPRIMARY KEY (`source_ids_hash`), \nINDEX `source` (`sourceid1`(191), `sourceid2`(191), `sourceid3`(191), `sourceid4`(191), `sourceid5`(191))\n) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Mappings from source identifier value(s) to destination\xe2\x80\xa6'; Array\n(\n)\n" at /docroot/core/lib/Drupal/Core/Database/Connection.php line 686

I encountered this error using a Migrate Plus entity - whenever the entity was loaded it would attempt to re-create the table and throw an exception, making some site paths inaccessible. Resolution required deleting the configuration entity directly in the config db table.

Proposed resolutions

Three options were proposed.
- Catch the exception, log an error, and prevent other migration actions from executing if table could not be created.
- Limit the number of fields included in the secondary index so that the maximum index size is not exceeded.
- Create multiple secondary indexes, split to fit within the the index size limits (e.g. ['source1' => ['sourceid1','sourceid2','sourceid3'], 'source2' => ['sourceid4','sourceid5']])

Of those, the final option, creating multiple indexes is implemented. A while loop is used to continually increase the number of indexes until the map table is created.

Improve API for creating/updating configuration

$
0
0

Problem/Motivation

Core uses the ConfigInstaller service to create or update configuration. The ConfigInstaller::createConfiguration() is responsible for "installing" a collection of config and handles the case of existing vs new and simple config vs config entities. However, this function is not Public and contains a bit of installer-specific code.

Other contrib modules, such as Config Actions and Configuration Update Manager (used by Features) have the need to update configuration and have their own methods for this. In the case of Config Actions, code from ConfigInstaller::createConfiguration() was copied/pasted. In Configuration Update Manager the same underlying $entity_storage->createFromStorageRecord and $entity_storage->updateFromStorageRecord methods are used as in ConfigInstaller but missing some details.

Configuration Update Manager needs to preserve the "_core" key data, while core ConfigInstaller needs to determine if the config is being synced and handle the "trustData" and check if the config is Installable. Config Actions also uses trustData (and maybe shouldn't) but doesn't do anything to preserve the "_core" key.

Proposed resolution

Provide a new public method in ConfigInstaller for creating/updating a single config item. This method would be used within ConfigInstaller itself but would also be available for contrib modules that want to install or update configuration.

/**
 * @param \Drupal\Core\Config\StorableConfigBase $config_item
 *   the config item to be updated.
 * @param mixed $data
 *   the data to store into the config item.
 */
public function installConfigItem($config_item, $data)

Remaining tasks

This issue summary is a "work in progress"

User interface changes

API changes

Data model changes


FieldPluginBase::renderAsLink() should consider protocol-relative URL as external

$
0
0

Problem/Motivation

When using the Views UI to rewrite a field as a link and using a protocol-relative URL (the ones that start with "//"), it is considered as an internal URL and prefixed by "internal:/". This triggers the Core PathValidator that calls the PathProcessorManager::processInbound which can cause a lot of problems. In my case, file URL served by the CDN module become unusable due to their transformation that's not supposed to happen on display.

Proposed resolution

Use \Drupal\Component\Utility\UrlHelper::isExternal() to prevent this from happening.

Drupal 9 readiness meeting / 18 May 2020

$
0
0

Meeting will happen in #d9readiness on drupal.slack.com.

Hello and welcome to this Drupal 9 readiness meeting!

This meeting:
➤ Is for core and contributed project developers as well as people who have integrations and services related to core. Site developers who want to stay in the know to keep up-to-date for the easiest Drupal 9 upgrade of their sites are also welcome.
➤ Usually happens every Monday at 18:00 UTC.
➤ Is done over chat.
➤ Happens in threads, which you can follow to be notified of new replies even if you don’t comment in the thread. You may also join the meeting later and participate asynchronously!
➤ Has a public agenda anyone can add to: `https://www.drupal.org/project/drupal/issues/3136705`
➤ *Transcript will be exported and posted* to the agenda issue. For anonymous comments, start with a :bust_in_silhouette: emoji. To take a comment or thread off the record, start with a :no_entry_sign: emoji.

:zero: Who is here today? Comment in the thread below to introduce yourself.

:one: Do you have suggested topics you are looking to discuss? Post in this thread and we'll open threads for them as appropriate.

:two: TBD

Migrate D7 entity translation revision translations

$
0
0

Problem/Motivation

Migrate the revisions for d7 entity translation to d8. This is moved out of #2746541: [backport] Migrate D6 and D7 node revision translations to D8, which is now only about node translation, to reduce complexity.

This issue is intended to be completed after #2746541: [backport] Migrate D6 and D7 node revision translations to D8.

Proposed resolution

Add a new node type, et, to the drupal7 fixture that uses entity translation and has several revisions.

Use the node master plugins that are introduced in #2746541: [backport] Migrate D6 and D7 node revision translations to D8 and add a join to the entity_translation_revision table, if the table exists. Then the language must be selected accordingly. If the row uses node translation then the language is set to what is in the node table and if the row used entity_translation then the language is set to what is in the entity translation revision table.

Also, a tweak is done in the node source plugin to select the language.

Remaining tasks

The patch in #28 is merged with2746541-231.patch from the node translation revision issue so that it is available for testing.

For Testers

  • Use the lastest patch patch in this issue..
  • There are instructions in the Issue summary of the META issue #2208401: [META] Stabilise Migrate Drupal Multilingual module/li>

User interface changes

API changes

Data model changes

Release notes snippet

Wrap field-type settings in a fieldset

$
0
0

Problem/Motivation

This is a follow-up to #1953568: Make the bundle settings for entity reference fields more visible..

When configuring a field (such as /admin/structure/types/manage/article/fields/node.article.field_tags) there are several form elements used by all field types (Label, Help text, Required checkbox). Some field types, such as Entity reference and Link, have additional settings. We would like to make these additional settings, when present, easier to identify.

Proposed resolution

Whenever a field type adds settings to the configuration form, wrap those settings in a fieldset.

Standardize the fieldset label.

Remaining tasks

  • Add screenshots to the issue summary.
  • Decide whether the wrapper element should be added by the field-type plugin or by the parent form.
  • Decide on the standard label: something like "FIELD_TYPE settings" or "FIELD_TYPE options".

User interface changes

This will change the appearance of the field configuration form.

API changes

Whichever implementation we use, the documentation of the form elements returned by the field-type plugin will have to be updated.

Data model changes

None

list of menu item properties in hook_menu_links_discovered_alter() is incomplete

Encrypt Dependencies in 7.70

$
0
0

Sorry, please delete
Not a core 7.70 issue

Block view cachability metadata doesn't get copied in BlockView::preRender() when the block content is non-empty

$
0
0

Problem/Motivation

In \Drupal\block\BlockViewBuilder::preRender(), the block entity gets removed from the render array and replaced with a copy that doesn't depend on the block config entity.

If the block content is empty, then the cacheability metadata gets copied correctly using the \Drupal\Core\Cache\CacheableMetadata::merge() function. However, if the block content is not empty, the cacheability metadata isn't copied at all.

I noticed this, with @dawehner's help and guidance, after hours of debugging a view's display of type block that was missing a 'url' cache context, causing an empty block to be cached in the render cache if another page where one of the view's arguments could not be determined from the URL and resulted in an empty block.

Proposed resolution

Move the code that properly merges the cacheability metadata from the codepath where the block's content is empty to the main codepath for \Drupal\block\BlockViewBuilder::preRender()

Remaining tasks

  1. Write a patch
  2. Find exact steps to reproduce.
  3. Add test(s) to patch.
  4. Review, feedback.
  5. RTBC, commit.

User interface changes

None.

API changes

I honestly don't know enough about Drupal 8's render API to know if there are any, but I think no (?)

Data model changes

None.


Add a generic entity route context

$
0
0

Similarly to NodeRouteContext, a generic entity route context should be available that supplies a context on routes which are identified as a link template for an entity type.

Add the migration from D7 Picture to Responsive Image

Use context for giving feed to aggregator block (rather than configuration)

$
0
0

This is a spin off of #2377757: Expose Block Context mapping in the UI (and depends on that issue in order to work, so "Postponed")

Problem/Motivation

Context is frequently used to pass an entity to a block, as this allows you to do cool things like (a) place a block that shows the feed for the entity currently being displayed, or (b) show the feed for a referenced entity, as well as just (c) showing the feed for a specifically selected entity.

Using configuration only allows you to do (c) but not (a) or (b).

0) Apply the patch from #2377757: Expose Block Context mapping in the UI
1) Apply the latest patch
2) drush si
3) drush en aggregator
4) admin/config/services/aggregator
5) Add a feed to http://rss.cbc.ca/lineup/topstories.xml (Canada FTW)
6) admin/structure/block
7) Add the "Aggregator feed" block

Proposed resolution

Modify the aggregator block to use context rather than configuration.

Remaining tasks

  1. RTBC
  2. Get someone to commit it!

User interface changes

After installing Aggregator, we visit the block layout admin w/o creating a feed yet and we are treated to this:

If we attempt to configure this block without having created a Feed yet, we get this:

This is kind of ridiculous because there are no feeds, and we're placing a block that cannot even function yet. Once we create feeds we get:


for 1 feed and:


for N feeds respectively.

Summary of HEAD:

We have the ability to place aggregator feed blocks before they're useful. This can lead to misconfigured blocks that don't function.

After Patch:

Leveraging the context system brings some uniform benefits to the UI, first on the list is that before you've created any feed entities, the block layout system won't even give you the erroneous option of placing feed blocks:

After we've created feeds, the block system shows us that we can actually use the block:

If we've only created a single feed, the block doesn't prompt the user for unnecessary configuration, it knows there's only one possible feed to use, and it just auto-configures that single value:

Once multiple Feeds have been created, the user interface expands accordingly:

and

API changes

None.

ContentTranslationController::add() breaks if the latest translation affected revision id is NULL

$
0
0

Dear Drupal Core maintainers,

I'm facing an issue when adding a new translation for a published content. This content has no revisions, they have been deleted by a contrib module node_revision_delete.

This issue is not related to node_revision_delete but it's due to a weakness when resolving the latest translation affected revision identifier in add method of ContentTranslationController:

  public function add(LanguageInterface $source, LanguageInterface $target, RouteMatchInterface $route_match, $entity_type_id = NULL) {
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $route_match->getParameter($entity_type_id);

    // In case of a pending revision, make sure we load the latest
    // translation-affecting revision for the source language, otherwise the
    // initial form values may not be up-to-date.
    if (!$entity->isDefaultRevision() && ContentTranslationManager::isPendingRevisionSupportEnabled($entity_type_id, $entity->bundle())) {
      /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
      $storage = $this->entityTypeManager()->getStorage($entity->getEntityTypeId());
      $revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $source->getId());
      if ($revision_id != $entity->getRevisionId()) {
        $entity = $storage->loadRevision($revision_id);
      }
    }

    // @todo Exploit the upcoming hook_entity_prepare() when available.
    // See https://www.drupal.org/node/1810394.
    $this->prepareTranslation($entity, $source, $target);

The getLatestTranslationAffectedRevisionId method signature is :

  /**
   * Returns the latest revision affecting the specified translation.
   *
   * @param int|string $entity_id
   *   The entity identifier.
   * @param string $langcode
   *   The language code of the translation.
   *
   * @return int|string|null
   *   A revision ID or NULL if no revision affecting the specified translation
   *   could be found.
   */
  public function getLatestTranslationAffectedRevisionId($entity_id, $langcode);

So if getLatestTranslationAffectedRevisionId method returns NULL (which is the case when no revisions exist for a specific content), it ends up to a NULL $entity variable which breaks later the prepareTranslation method.

New option for Views page displays to use the admin theme

$
0
0

Problem/Motivation

Admin paths are defined now in route definitions (see https://www.drupal.org/node/2224207). But in Views UI, the route is build via UI and you'll need to code to mark a view route as admin route. This is very painful.

Use case: As a site moderator, I'm able to use a View, located at /articles/moderate, with VBO to bulk approve/decline articles. I want to access this moderation tool using the admin theme in the same way I'm using the node edit page.

Proposed resolution

Add a new page setting "Always use admin theme" in the page display that allows site builders to make that page an admin one, similar to https://www.drupal.org/project/page_manager.

Remaining tasks

None.

User interface changes

See the screenshots:

API changes

None.

Data model changes

New page display option: always_use_admin_theme

Viewing all 297657 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>