Skip to content

(Seemingly) Random Post Slugs

Notes (very short posts that normally don’t have a title) on this site sport URLs that end in a short, numerical “slug.” Each such slug is generated automatically (with a little help of Optimus), based on the post’s database ID, and thus unique—although there are other ways to cover uniqueness. (Thing is, I didn’t want to “expose” the post ID, and wanted to replace it with a “nicer-looking” number.)

Note: it’s certainly possible to generate and use an actual random string, e.g., with bin2hex( openssl_random_pseudo_bytes( 4 ) ), after ensuring it is unique.

I used to use the publish_post hook to update the generic WordPress slug—the actual ID, usually—to this new number. This approach had a bit of an unwanted side effect: because it required re-saving the note, it also triggered another round of save_post and publish_post actions, which lead to, e.g., webmentions being sent twice.

I’ve since discovered the wp_unique_post_slug filter, which gets applied not just before a post is first inserted into the database, but—on the condition the post’s slug is somehow empty, still—after as well. So, I’m now attaching my callback function to this filter hook instead!

/**
 * Automatically override the post slug for supported post types.
 */
add_filter( 'wp_unique_post_slug', function( $slug, $post_id, $post_status, $post_type ) {
  $supported_post_types = array( 'note' ) );

  if ( in_array( $post_type, $supported_post_types ) ) {
    if ( 0 === $post_id ) {
      // Returning an empty slug for unsaved entries will trigger this same
      // function later on!
      return '';
    }

    // Use `php vendor/bin/optimus spark` to generate `$prime`, `$inverse` and
    // `$random` integers.
    $optimus = new Jenssegers\Optimus\Optimus( 2123809381, 1885413229, 146808189 );
    $slug    = $optimus->encode( $post_id );
  }

  return $slug;
}, 10, 4 );

Note: above code (obviously) requires the Jenssegers\Optimus\Optimus class.