Hi All,

I am having a problem developing a Module that depends on Pathauto and uses several of its hooks. I implement hook_pathauto in order to add extra settings in the Pathauto configuration screen and it works great. For the replacement patterns, I use the standard node tokens. The following is the code:

function printwebpathauto_pathauto( $operation )
{
    if( $operation == 'settings' )
    {
        // Initialize  New Object. 
        $Settings = new stdClass( );
        
        $Settings->bulkname = t( 'Bulk Generate Printer Friendly Web Aliases.' );
        $Settings->bulkdescr = t( 'Generates printer friendly Web aliases for URLs that do not already have aliases.' );
        $Settings->groupheader = t( 'Printer Friendly Web Settings' );
        $Settings->module = 'printwebpathauto';
        $Settings->patterndescr = t( 'Pattern for Default printer friendly Web URLs' );
        $Settings->patternitems = new stdClass( );
        $Settings->placeholders = new stdClass( );
        $Settings->token_type = 'node'; // Use Standard Node Tokens.
        
        // Get All Possible Token Place Holders Patterns.
        $patterns = token_get_list( 'node' ); // Get Standard Node Tokens.
        $PlaceHolders = $Settings->placeholders;
        foreach( $patterns as $patternType => $pattern )
        {
            if( $patternType != 'global' )
            {
                foreach( $pattern as $patternName => $patternDescription )
                {
                    $patternName = '[' . $patternName . ']';
                    $PlaceHolders->$patternName = $patternDescription;
                }
            }
        }
        
        $nodeTypes = node_get_types( 'names' );
        $PatternItems = $Settings->patternitems;
        foreach( $nodeTypes as $nodeType => $nodeName )
        {
            $PatternItems->$nodeType = t(
                'Pattern for @NodeName printer friendly Web URLs' ,
                array(
                    '@NodeName' => ucwords( $nodeName )
                )
            );
        }
        
        // Return.
        return $Settings;
    }
}

I also implement hook_nodeapi in order to create a new alias, based on the above, when a new node is created. The following is the code:

function printwebpathauto_nodeapi( &$Node , $operation , $teaser , $page )
{
    if( $operation == 'insert' )
    {
        // Get Token Place Holders Patterns.
        $placeholders = pathauto_get_placeholders( 'node' , $Node );
        
        // Define URL To Generate Alias For.
        $url = 'print/' . $Node->nid;
        
        // Generate Alias.
        pathauto_create_alias(
            'printwebpathauto' ,
            'insert' ,
            $placeholders ,
            $url ,
            $Node->nid ,
            $Node->type ,
            $Node->language
        );
    }
}

Here is the problem: Taxonomy related tags, such as [vocab] and [termpath], and their -raw alternatives are not being replaced at all! Most of this code is based on the standard example code found in Pathauto itself yet it is not working at all! How can I fix it? Any help would be appreciated greatly.

So if I define a pattern like so: blog/print/[termpath-raw]/[title-raw] --> The result for a content with a title of 'Test' would be --> blog/print/Test. The [termpath-raw] is completley ignored, even though the content is part of a vocabulary.

Thanks in advance,

Comments

Typer85’s picture

*BUMP*

Anyone?

jefkin’s picture

I actually became interested in using pathauto this way based on your example code.

I'm not sure about how you went about your setup with the Objects and stuff, and that's the part that seems the most likely to have a hidden failure, but I based my work on the file: sites/all/modules/pathauto/pathauto_node.inc, and just used array's until the end, with a typecast to object.

My usage is obviously different from yours, but I think there maybe be something you could pick up from my example?

I have a module that is handling contact-us forms for a site with 2 different types of nodes (products) that users might want to contact us about. So I restrict to those two nodes.

I managed to get it to work by first of all defining a menu entry, and getting the basic form loading with the un-pretty url like this:

"/mail-us/{$node->nid}"

Which our client doesn't want because that tempts some people (not very bright ones I gather) to ask about other #'s that may or may not be properties ... so we needed a better solution.

We opted for /mail-us/# to be the real processing menu url, but using url aliases to hide it from the user so the user could ask for say "/aboutPrinters/Canon-Fx3" or "/aboutLaptops/Dell-4025" (the actual site has nothing to do with either Laptops or Printers, and I just made up the Canon Fx3 and Dell 4025 :] ... but I think the parallel holds).

So these are slightly edited versions of the functions in our module:

/*
** cw_contactus_nodeapi() - hook_nodeapi(): callback for nodeapi, This
**                          function allows us to perform some special
**    actions at stages of the node's life, like presave, revision deletion,
**    and others.  Check drupal API for more info about the actions
**    available and what $a3 and $a4 vars may stand for for each $op
**    available.
**
**  @args                 Defined for hook_nodeapi()
**  @param  ref   $node   The reference node obj to act on.
**  @param  str   $op     To show a teaser or not.
**  @param  mixd  $a3     ?? defined by op in api.drupal.org ??
**  @param  mixd  $a4     ?? defined by op in api.drupal.org ??
**  @return null
**
**  @side-effects Various depending on $op see context below.
*/
function cw_contactus_nodeapi(&$node, $op, $a3, $a4)
{
  if (('cw_printer' != $type = $node->type)  && // all other node types 
      ('cw_laptop'  != $type))                  // get on out of here.
  {
    return;
  }
  switch ($op)
  {
    case 'insert':
    {   
      /*  
      ** We create aliases here:
      **
      ** get the place holder patterns, then define the url then generate
      */
      $placeholders = pathauto_get_placeholders('node', $node);
      $nid          = $node->nid;
      $url          = "mail-us/$nid";

      pathauto_create_alias('cw_contactus', 'insert',  $placeholders, $url,
                            $nid, $type, $node->language);
      break;
    }
    case 'delete':
    {
      /*
      ** we might want to clean up node aliases here?
      */
      path_set_alias("mail-us/{$node->nid}");
      break;
    }
    case 'update':
    {
      /*
      ** someone might want to do something for updates, but I don't like
      ** changing published urls automatically, let the user decide.
      */
      break;
    }
  }
}

/*
** cw_contactus_pathauto() -- optional pathauto hook describes a pathauto
**                            instance for the cw_contactus.
**
**  @param  string  $op   What needs to be done.
*/
function cw_contactus_pathauto($op = '')
{
  $pathauto = null;

  switch ($op)
  {
    case 'settings':
    {
      $header     = t('CW Node Contact Us path settings');
      $pattern    = t('Default contact path pattern.');
      $bulk       = t(  'Bulk generate aliases for CW Printer and Laptop '
                      . 'nodes that are not aliased');
      $bulkDesc   = t(  'Generate aliases for all existing CW Printer and '
                      . 'Laptop nodes which do not already have '
                      . 'aliases.');
      $patterns   = token_get_list('node');
      $languages  = array ( );

      foreach ($patterns as $type => $pattern_set)
      {
        if ($type != 'global')
        {
          foreach ($pattern_set as $pattern => $description)
          {
            $placeholders["[$pattern]"] = $description;
          }
        }
      }
      if (module_exists('locale'))
      {
        $languages  = array  ( '' => t('Language neutral') )
                    + locale_language_list('name');
      }
      foreach (node_get_types('names') as $node_type => $node_name)
      {
        if (('cw_printer' == $node_type) or ('cw_laptop' == $node_type))
        {
          if ((variable_get('language_content_type_'. $node_type, 0)) &&
              (count($languages)))
          {
            $patternitems[$node_type] =
                  t(  'Default path pattern for @node_type (applies to all '
                    . '@node_type node types with blank patterns below)',
                    array ( '@node_type'=>$node_name ));

            foreach ($languages as $lang_code => $lang_name)
            {
              if (!empty($lang_code))
              {
                $patternitems[$node_type . '_' . $lang_code] =
                          t('Pattern for all @node_type paths in @language',
                            array ( '@node_type'=>$node_name
                                ,   '@language' =>$lang_name ));
              }
              else
              {
                $patternitems[$node_type . '_' . $lang_code] =
                      t('Pattern for all language neutral @node_type paths',
                        array ( '@node_type'=>$node_name ));
              }
            }
          }
          else
          {
            $patternitems[$node_type] =
                                      t('Pattern for all @node_type paths',
                                        array ( '@node_type'=>$node_name ));
          }
        }
      }
      $settings = array ( 'module'        =>'cw_contactus'
                      ,   'token_type'    =>'node'
                      ,   'groupheader'   =>$header
                      ,   'patterndescr'  =>$patern
                      ,   'patterndefault'=>t('contactus/[title-raw]')
                      ,   'bulkname'      =>$bulk
                      ,   'bulkdescr'     =>$bulkDesc
                      ,   'placeholders'  =>$placeholders
                      ,   'patternitems'  =>$patternitems
                      , );
      $pathauto = (object) $settings;
      break;
    }
    default:
    {
      break;
    }
  }
  return $pathauto;
}

/*
** cw_contactus_pathauto_bulkupdate() - Process all printer and laptop nodes
**                                      updating (really just adding) any
**    url aliases that are missing. using the provided patterns.
**
** Generate aliases for all nodes without aliases.
*/
function cw_contactus_pathauto_bulkupdate()
{
  $pattern_types = array ( ); // collect patterns

  // If there's a default pattern we assume all types might be updated.
  if (trim(variable_get('pathauto_cw_contactus_pattern', '')))
  {
    $pattern_types = array ( 'cw_printer', 'cw_laptop' );
  }
  else
  {
    $languages = array ( ); // Check first for a node specific pattern...

    if (module_exists('locale'))
    {
      $languages  = array ( '' => t('Language neutral'))
                  + locale_language_list('name');
    }
    foreach (array_keys(node_get_types('names')) as $type)
    {
      $var = "pathauto_cw_contactus_{$type}_pattern";

      if (trim(variable_get($var, '')))
      {
        $pattern_types[$type] = $type;
        continue;
      }
      // ...then for a node-language pattern.
      $var = "language_content_type_$type";

      if (variable_get($var, 0) && $languages)
      {
        foreach ($languages as $lang_code => $lang_name)
        {
          $var = "pathauto_cw_contactus_{$type}_{$lang_code}_pattern";

          if (trim(variable_get($var, '')))
          {
            $pattern_types[$type] = $type;
            continue 2; // what? why not just drop out
          }
        }
      }
    }
  }
  $count = 0;

  if (count($pattern_types))
  {
    $string = db_placeholders($pattern_types, 'varchar');
    $query  = "

SELECT        n.nid,      n.vid,      n.type,     n.title,  n.uid
            , n.created,  n.language, alias.src,  alias.dst
  FROM        {node}      n
    LEFT JOIN {url_alias} alias
      ON      CONCAT('mail-us/', CAST(n.nid AS CHAR)) = alias.src

  WHERE       alias.src IS NULL
    AND       n.type    IN ($string)";

    $max    = variable_get('pathauto_max_bulk_update', 50);
    $result = db_query_range($query, $pattern_types, 0, $max);

    $placeholders = array ( );

    while ($node_ref = db_fetch_object($result))
    {
      $node       = node_load($node_ref->nid, NULL, TRUE);
      $node->src  = $node_ref->src; // this is probably junk
      $node->dst  = $node_ref->dst; // this too

      if (module_exists('taxonomy'))
      {
        // Must populate the terms for the node here for the category
        // placeholders to work
        $node->taxonomy = array_keys(taxonomy_node_get_terms($node));
      }
      $placeholders = pathauto_get_placeholders('node', $node);
      $src          = "mail-us/{$node->nid}";
      $alias        = pathauto_create_alias('cw_contactus', 'bulkupdate',
                                            $placeholders, $src, $node->nid,
                                            $node->type, $node->language);
      if ($alias)
      {
        $count++;
      }
    }
  }
  drupal_set_message(
    format_plural(
      $count,
      'Bulk generation of nodes completed, one alias generated.',
      'Bulk generation of nodes completed, @count aliases generated.'));
}

I hope this helps you and maybe some others out there.

Jeff

Typer85’s picture

Sorry for the late reply but I sort of gave up hope that anyone would actually reply. I kind of believed that using an Object might be the problem at first as well so I literally copied and pasted the code for the default content node provided by Pathauto and just made the appropiate changes specific to my module. To my dismay it still did not work!

The code for the default content node provided by Pathauto uses an Array that is typecasted to an Object when the function returns so it seems your suggestion about not using an Object did not work for me. I am going crazy here and starting to give up all hope.

Is your module generating correct URLS when using taxonomy terms? I see very little differences from your code and mine in regards to creating an alias when a node is created so I am just curious if I am the one having this problem or perhaps this is a problem with Pathauto that we don't know about.

Thanks a lot for your support. If you have any other suggestions, I would surely appreciate it.

Thanks in advance,

jefkin’s picture

I've been using my module in a production environment since I last posted it. :0

Sorry I wasn't of more help for you.

Jeff