The Token module provides menu link tokens, allowing you to use them in Pathauto for example to have a node's path generated based on where you place it in a menu

The token module has some pretty custom code to make this work properly due to how menu links are saved (see #2670120: Patterns with node:menu-link tokens don't work on first node save for complete details). But basically in token.module there is an entity builder callback that's added that makes this all work, but it's only added if the current user has the 'administer menu' permission.

People using the Menu Admin per Menu module are likely not handing out the the 'administer menu' permission to its editors, but instead are giving out the individual menu permissions to its editors. As a result, when those editors attempt to save a page for the first time, the menu tokens don't work, and that node will get the default system path. The node must then be re-saved.

Comments

bkosborne created an issue. See original summary.

bkosborne’s picture

Here's the code from the Token module that is incompatible with this module:

/**
 * Implements hook_form_BASE_FORM_ID_alter() for node_form.
 *
 * Populates menu_link field on nodes from the menu item on unsaved nodes.
 *
 * @see menu_ui_form_node_form_submit()
 * @see token_entity_base_field_info()
 */
function token_form_node_form_alter(&$form, FormStateInterface $form_state) {
  if (!\Drupal::moduleHandler()->moduleExists('menu_ui')) {
    return;
  }
  /** @var \Drupal\node\NodeForm $form_object */
  if (!\Drupal::currentUser()->hasPermission('administer menu')) {
    // We're only interested in when the node is unsaved and the editor has
    // permission to create new menu links.
    return;
  }
  $form['#entity_builders'][] = 'token_node_menu_link_submit';
}

So one solution I thought of is to refactor this as such:

/**
 * Implements hook_form_BASE_FORM_ID_alter() for node_form.
 *
 * Populates menu_link field on nodes from the menu item on unsaved nodes.
 *
 * @see menu_ui_form_node_form_submit()
 * @see token_entity_base_field_info()
 */
function token_form_node_form_alter(&$form, FormStateInterface $form_state) {
  if (isset($form['menu']) && $form['menu']['#access']) {
    $form['#entity_builders'][] = 'token_node_menu_link_submit';
  }
}

I thought this would work because this module sets the #access attribute based on the correct permission. However, this module's weight is set to 1, higher than the 0 weight of Token, which means that this module's hook alter which sets the appropriate #access value is called too late.

chris burge’s picture

I don't see why Token is checking if a user has the 'administer menu' permission in the first place. Take a look at token_node_menu_link_submit(). If a user doesn't have menu permissions, then that user won't be able to add a menu item for the newly created node. That means that in token_node_menu_link_submit(), no replacement will happen because $form_state->isValueEmpty('menu') will return TRUE.

The permission check was added in #2670120: Patterns with node:menu-link tokens don't work on first node save but was never discussed. IMHO, the permission check should be removed in token_form_node_form_alter(). It doesn't provide any protection in the first place.

chris burge’s picture

jeroent’s picture

Status: Active » Closed (works as designed)

This seems to be fixed? If it's still an issue, please create a new issue. Thanks!