docs: function generateSlug(Model, base, options) {
          var slug,
              slugTryCount = 1,
              baseName = Model.prototype.tableName.replace(/s$/, ''),
              // Look for a matching slug, append an incrementing number if so
              checkIfSlugExists, longSlug;
  
          checkIfSlugExists = function checkIfSlugExists(slugToFind) {
              var args = {slug: slugToFind};
  
              // status is needed for posts
              if (options && options.status) {
                  args.status = options.status;
              }
  
              return Model.findOne(args, options).then(function then(found) {
                  var trimSpace;
  
                  if (!found) {
                      return slugToFind;
                  }
  
                  slugTryCount += 1;
  
                  // If we shortened, go back to the full version and try again
                  if (slugTryCount === 2 && longSlug) {
                      slugToFind = longSlug;
                      longSlug = null;
                      slugTryCount = 1;
                      return checkIfSlugExists(slugToFind);
                  }
  
                  // If this is the first time through, add the hyphen
                  if (slugTryCount === 2) {
                      slugToFind += '-';
                  } else {
                      // Otherwise, trim the number off the end
                      trimSpace = -(String(slugTryCount - 1).length);
                      slugToFind = slugToFind.slice(0, trimSpace);
                  }
  
                  slugToFind += slugTryCount;
  
                  return checkIfSlugExists(slugToFind);
              });
          };
  
          slug = security.string.safe(base, options);
  
          // the slug may never be longer than the allowed limit of 191 chars, but should also
          // take the counter into count. We reduce a too long slug to 185 so we're always on the
          // safe side, also in terms of checking for existing slugs already.
          if (slug.length > 185) {
              // CASE: don't cut the slug on import
              if (!_.has(options, 'importing') || !options.importing) {
                  slug = slug.slice(0, 185);
              }
          }
  
          // If it's a user, let's try to cut it down (unless this is a human request)
          if (baseName === 'user' && options && options.shortSlug && slugTryCount === 1 && slug !== 'ghost-owner') {
              longSlug = slug;
              slug = (slug.indexOf('-') > -1) ? slug.substr(0, slug.indexOf('-')) : slug;
          }
  
          if (!_.has(options, 'importing') || !options.importing) {
              // This checks if the first character of a tag name is a #. If it is, this
              // is an internal tag, and as such we should add 'hash' to the beginning of the slug
              if (baseName === 'tag' && /^#/.test(base)) {
                  slug = 'hash-' + slug;
              }
          }
  
          // Some keywords cannot be changed
          const slugList = _.union(config.get('slugs').reserved, urlService.utils.getProtectedSlugs());
          slug = _.includes(slugList, slug) ? slug + '-' + baseName : slug;
  
          // if slug is empty after trimming use the model name
          if (!slug) {
              slug = baseName;
          }
  
          // Test for duplicate slugs.
          return checkIfSlugExists(slug);
      }