I've created some nodes programmatically and set the path alias. But when I then go into edit the node the 'Generate automatic URL alias' option is still checked, even though my alias is shown in the 'URL alias' textfield underneath, so consequently gets overwritten on save.

Also, when editing the node using the Entity module and entity_metadata_wrapper(), the alias is generated again and my alias is overwritten because of this problem.

When I load a node using node_load() I expect to see $node->path['pathauto'] but I don't, so I can't seem to disable it this way. Anyone got any advice?

Comments

oknate’s picture

$node->path['pathauto'] = FALSE;

kkeiper1103’s picture

Nate,

I'm trying the above and it's not turning off the automatic aliases. My situation is pretty much that I'm using pathauto for future pages, had a bunch of pages that needed migrated from a legacy site, along with the url slugs they used, and now pathauto is interfering with those old urls by replacing them.

I created a new file in my theme (will eventually delete), wherein Drupal is bootstrapped and then I'm loading all nodes of type secondary or promotion page, via this code:

if( $_SERVER['SERVER_ADDR'] == "127.0.0.1" )
{
    define('DRUPAL_ROOT', '/path/to/local/drupal/site');
}
else 
{
	define('DRUPAL_ROOT', '/path/to/remote/drupal/site');
}


require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

// now that drupal has been bootstrapped, lets work with the nodes

$results = db_query("SELECT nid FROM {node} WHERE type = 'secondary_page' OR type = 'promotion_page';");

foreach($results as $row)
{
    $node = node_load($row->nid);
    
    $node->path['pathauto'] = FALSE;
    
    node_save($node);
}

I've verified that it loads the nodes by creating an array and pushing each loaded node onto the array, then var_dump'ing it. It shows all the nodes that need the automatic urls turned off, so I know it's getting the nodes, but when it saves, if I refresh, the admin page still tells me that it's using automatic URLs.

Any more suggestions?

asparaguscat’s picture

You need to delete the existing aliases from the url_alias table as well as turning off pathauto for the node.

function my_module_update_7001() {
  $nodes = node_load_multiple(array(), array('type' => 'my_node_type'));
  foreach ($nodes as $node) {
    $deleted = db_delete('url_alias')
    ->condition('source', 'node/' . $node->nid)
    ->execute();
    $node->path = array('alias' => 'my_new_alias', 'pathauto' => 0);
    node_save($node);
  }
}

I don't know how this will interact with your entity metadata, but I found that setting pathauto to 0 didn't work until I deleted the old aliases too.

MastaP’s picture

Is there any way of programmatically unchecking 'Generate automatic URL alias' option for all nodes WITHOUT saving?
Because saving could invoke other mechanism, and updates the modified date etc.

The reason we are looking into this is to stop the relationship between the Title and the path after a day...

bfodeke’s picture

This is what I ended up implementing that doesn't change the updated time. It essentially is only run when any page is updated.

/**
 * Implementation of hook_node_presave($node)
 *
 * Turning off Generate URLS if a page already has a
 * generated alias
 */
function hook_node_presave($node){
	// If a page already has an alias,
	// don't generate a new one on save
	if(!empty($node->path['alias'])){
		$node->path['pathauto'] = FALSE;
	}
}
robertoperuzzo’s picture

In $node (Object) there isn't a $node->path property.

The only thing I may advice to you is this:
the 'Generate automatic URL alias' option is checked if the node alias value is equal to the result of pathauto pattern only, i.e.

[node-title] -> this is the 'pattern' for node-type=page
My test page -> this is the title of my page

if and only if the alias value is 'my-test-page', then the 'Generate automatic URL alias' is checked, otherwise it doesn't.

Jieyyal’s picture

You can go to check pathauto.module pathauto_field_attach_form()

if (!isset($entity->path['pathauto'])) {
    if (!empty($id)) {
      module_load_include('inc', 'pathauto');
      $uri = entity_uri($entity_type, $entity);
      $path = drupal_get_path_alias($uri['path'], $langcode);
      $pathauto_alias = pathauto_create_alias($entity_type, 'return', $uri['path'], array($entity_type => $entity), $bundle, $langcode);
      $entity->path['pathauto'] = ($path != $uri['path'] && $path == $pathauto_alias);
    }
    else {
      $entity->path['pathauto'] = TRUE;
    }
  }

This shows that this option only detect whether the entity alias stored in database is the same as pathauto generates.

If not, Then it will be FALSE. Or it will show TRUE.

For you I think you just don't want using pathauto function.

Tip1:Turn pathauto module off will help you.

Tip2:Go to /admin/config/search/path/patterns, Delete the alias pattern for the specify entity type.

You can choose one of the tips, that should work.

Thx

dsbrianwebster’s picture

The code by bfodeke will definitely work and may be preferable depending on how strict you need to be with disabling alias generation.

We wanted to share an alternate approach that's a little less restrictive. For us, the two issues with the node_presave approach were...

1) "Generate automatic URL alias" checkbox stays checked until second save.

We wanted the checkbox to be off after the first save since a path already exists.

2) Automatic URL alias functionality is lost after first save.

If "Generate automatic URL alias" is manually re-checked, this would not do anything. We still wanted automatic alias generation to work if someone explicitly checked the box. (An example: In the event of a total rewrite of the entity title, auto generation could be nicer than manually typing the new path.)

---

With the above issues and goals in mind, we wrote a custom after_build function to check for a path pid. If one exists “Generate automatic URL alias" will be unchecked.

End result: "Generate automatic URL alias" checkbox will always be UNCHECKED if a path exists for that node/entity OR if the user has explicitly re-checked it.

The code...

/**
 * Implements hook_form_alter().
 */
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
  $form['#after_build'][] = 'MYMODULE_after_build';
}

/**
 * Custom after build function
 */
function MYMODULE_after_build($form, &$form_state) {
  // Unchecks Generate automatic URL alias if path exists
  if (isset($form['path']['pathauto']) && $form['path']['pid']['#value']) {
    $form['path']['pathauto']['#checked'] = FALSE;
  } 
  return $form;
}
akhilavnair’s picture

  • Go to 'admin/config/search/path/settings'
  • In Update action section, select Do nothing. Leave the old alias intact. option.
  • And save the configuration.

This way you can uncheck 'Generate automatic URL alias' option for all nodes instead of any form alters (using Path auto module - version 7.x-1.2).

kirkkala’s picture

Anyone looking to do this with Drupal 8 the following db query seem to do the job

UPDATE key_value SET value = 'i:0;' WHERE collection = 'pathauto_state.node' AND value = 'i:1;';
aposudevsky’s picture

UPDATE `key_value` SET VALUE = 'i:0;' WHERE collection = 'pathauto_state.node' AND NAME IN (
SELECT `name` FROM (
SELECT kv.name 
FROM `key_value` kv 
LEFT JOIN `node` n 
ON n.nid = kv.name
WHERE kv.collection = 'pathauto_state.node' AND n.type = '[YOUR_CONTENT_TYPE]' 
) kv1);

hope this helps somebody

maddentim’s picture

It did! :-) 

Thanks for sharing!

ahebrank’s picture

Here's a `drush scr` script I use to update the state for entities. See https://gist.github.com/ahebrank/be91b2bba61496ea5b31d4d38e6687a3 

<?php

// PARAMETER EXAMPLES
// ------------------
// desired status for entities in bundle
// // must be 1 or 0
// $pathauto_status = 1;

// // entity and type
// $entity = 'taxonomy_term';
// $bundle = 'offices_and_subunits';

// ------------------
// drush creates some extra script parameters -- we just want the last three
if (count($_SERVER['argv']) !== 6) {
  die("Need arguments: [STATE (1 or 0)] [ENTITY] [BUNDLE]");
}
list($drush, $scr, $script, $pathauto_status, $entity, $bundle) = $_SERVER['argv'];
$pathauto_status = (int)$pathauto_status;

$base_table = $entity;
$bundle_key = 'type';
$id_key = 'id';

// terms are abnormal entities
if ($entity == 'taxonomy_term') {
  $base_table = 'taxonomy_term_data';
  $bundle_key = 'vid';
  $id_key = 'tid';
}

if (!($pathauto_status === 1 || $pathauto_status === 0)) {
  die('$pathauto_status must be 1 or 0');
}

$db = \Drupal::database();
$result = $db->select($base_table)
  ->fields($base_table, [$id_key])
  ->condition($bundle_key, $bundle)
  ->execute();
$ids = $result->fetchCol();

echo "Found " . count($ids) . " " . $entity . "(s) of type " . $bundle . "\n";

$updated = $db->update('key_value')
  ->fields([
      'value' => 'i:' . $pathauto_status . ';',
    ])
  ->condition('collection', 'pathauto_state.' . $entity)
  ->condition('name', $ids, 'IN')
  ->execute();

echo "Updated pathauto state for " . $updated . " " . $entity . "(s).\n";
echo "You may want to regenerate aliases for this entity.\n";
jimconte’s picture

I put this method together based on Pathauto internals.

You can select your entities using an Entity Query, passing the $entity and $state = PathautoState::SKIP to disable.

  protected function setPathautoState(EntityInterface $entity, $state) {
    $collection = 'pathauto_state.' . $entity->getEntityTypeId();
    $state_key = PathautoState::getPathautoStateKey($entity->id());
    if ($state == PathautoState::CREATE) {
      $pattern = \Drupal::service('pathauto.generator')->getPatternByEntity($entity);
      if (empty($pattern)) {
        return; // don't set if there's no pattern
      }
    }
    \Drupal::keyValue($collection)->set( $state_key, $state );
    print("{$collection} {$state_key} {$state}\n"); // debug
  }