permalinks | Dmytro Shteflyuk's Home https://kpumuk.info In my blog I'll try to describe about interesting technologies, my discovery in IT and some useful things about programming. Tue, 08 Sep 2015 00:23:09 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 Generating permalink from string in Ruby https://kpumuk.info/ruby-on-rails/generating-permalink-from-string-in-ruby/ https://kpumuk.info/ruby-on-rails/generating-permalink-from-string-in-ruby/#comments Mon, 14 May 2007 15:27:39 +0000 http://kpumuk.info/ruby-on-rails/generating-permalink-from-string-in-ruby/ If you are creating Ruby on Rails application like a blog, you most probably want to generate URLs using post titles. It’s good practice, because search engines like keywords in URL, and it looks more human-readable. Just compare: http://example.com/posts/10 and http://example.com/posts/generating-permalinks-from-string (yeah, it’s long, but self-descriptive). Anyways, this is small post about converting a title […]

The post Generating permalink from string in Ruby first appeared on Dmytro Shteflyuk's Home.]]>
If you are creating Ruby on Rails application like a blog, you most probably want to generate URLs using post titles. It’s good practice, because search engines like keywords in URL, and it looks more human-readable. Just compare: http://example.com/posts/10 and http://example.com/posts/generating-permalinks-from-string (yeah, it’s long, but self-descriptive). Anyways, this is small post about converting a title to a permalink.

First thing I love in Ruby is an ability to extend classes with my own methods. I could just add method to_permalink to any string and then everywhere I could write something like @post.title.to_permalink. It’s amazing!

Here is my version of to_permalink method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class String
  def to_permalink
    result = strip_tags
    # Preserve escaped octets.
    result.gsub!(/-+/, '-')
    result.gsub!(/%([a-f0-9]{2})/i, '--\1--')
    # Remove percent signs that are not part of an octet.
    result.gsub!('%', '-')
    # Restore octets.
    result.gsub!(/--([a-f0-9]{2})--/i, '%\1')

    result.gsub!(/&.+?;/, '-') # kill entities
    result.gsub!(/[^%a-z0-9_-]+/i, '-')
    result.gsub!(/-+/, '-')
    result.gsub!(/(^-+|-+$)/, '')
    return result.downcase
  end

  private
 
    def strip_tags
      return clone if blank?
      if index('<')
        text = ''
        tokenizer = HTML::Tokenizer.new(self)

        while token = tokenizer.next
          node = HTML::Node.parse(nil, 0, 0, token, false)
          # result is only the content of any Text nodes
          text << node.to_s if node.class == HTML::Text
        end
        # strip any comments, and if they have a newline at the end (ie. line with
        # only a comment) strip that too
        text.gsub(/<!--(.*?)-->[\n]?/m, '')
      else
        clone # already plain text
      end
    end
end

How it’s working? First thing you would see is a private method strip_tags. Yes, I know about ActionView::Helpers::TextHelper::strip_tags, and this is almost 100% copy of Rails version (the only difference is that my version always returns clone of the original string). I just don’t want to rely on the Rails library.

Then my method replaces all special characters with dashes (only octets like %A0 would be kept), and trims dashed from the beginning and the end of the string. Finally full string will be lowercased.

Of course, in your application you should check collisions (several posts which have the same title should have unique permalinks, for example you could append numbers starting from 1: hello, hello-1, hello-2, etc). This is not my goal to cover all difficulties you could face, it’s small post, do you remember?

Just for your pleasure, here are the RSpec tests for this method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
describe 'String.to_permalink from extensions.rb' do
  it 'should replace all punctuation marks and spaces with dashes' do
    "!.@#$\%^&*()Test case\n\t".to_permalink.should == 'test-case'
  end

  it 'should preserve _ symbol' do
    "Test_case".to_permalink.should == 'test_case'
  end
 
  it 'should preserve escaped octets and remove redundant %' do
    'Test%%20case'.to_permalink.should == 'test-%20case'
  end

  it 'should strip HTML tags' do
    '<a href="http://example.com">Test</a> <b>case</b>'.to_permalink.should == 'test-case'
  end

  it 'should strip HTML entities and insert dashes' do
    'Test&nbsp;case'.to_permalink.should == 'test-case'
  end

  it 'should trim beginning and ending dashes' do
    '-. Test case .-'.to_permalink.should == 'test-case'
  end

  it 'should not use ---aa--- as octet' do
    'b---aa---b'.to_permalink.should == 'b-aa-b'
  end
 
  it 'should replace % with -' do
    'Hello%world'.to_permalink.should == 'hello-world'
  end

  it 'should not modify original string' do
    s = 'Hello,&nbsp;<b>world</b>%20'
    s.to_permalink.should == 'hello-world%20'
    s.should == 'Hello,&nbsp;<b>world</b>%20'

    s = 'Hello'
    s.to_permalink.should == 'hello'
    s.should == 'Hello'
  end
end

It’s funny, right?

The post Generating permalink from string in Ruby first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/ruby-on-rails/generating-permalink-from-string-in-ruby/feed/ 5
WordPress Plugins: sCategory Permalink – select category for permalink generation https://kpumuk.info/wordpress/wordpress-plugins-scategory-permalink-select-category-for-permalink-generation/ https://kpumuk.info/wordpress/wordpress-plugins-scategory-permalink-select-category-for-permalink-generation/#comments Sat, 18 Nov 2006 09:12:39 +0000 http://kpumuk.info/projects/wordpress/wordpress-plugins-scategory-permalink-select-category-for-permalink-generation/ I’m starting publishing custom WordPress plugins used in this blog, and today it will be “sCategory Permalink”. I like permalink option of WordPress %category% (and using it here), but it has one great limitation – when this option is selected, WordPress uses category with lowest ID for permalink generation! Just imagine following scenario: you have […]

The post WordPress Plugins: sCategory Permalink – select category for permalink generation first appeared on Dmytro Shteflyuk's Home.]]>
I’m starting publishing custom WordPress plugins used in this blog, and today it will be “sCategory Permalink”. I like permalink option of WordPress %category% (and using it here), but it has one great limitation – when this option is selected, WordPress uses category with lowest ID for permalink generation! Just imagine following scenario: you have category “Development” (common for all posts related to software building), and several specific categories, for example “PHP”, “AJAX”, “JavaScript”. You have Development category ID greater than any of other categories IDs, therefor specific categories used for URL generation. But one day you decided to start learning Ruby on Rails and post about this in your blog. It’s the problem, because when you will create category “Ruby on Rails”, its ID will be greater then ID of “Development”. Now you have to take decision: to abandon posting in both categories at the same time, or to update “Development” category ID. Lastest can be done in two ways: remove category from WordPress administration area and re-add it (and then you need to go through all of your posts and add needed to this category), or update ID in database (there are several tables related on category ID). But now you can relax! Just download and install plugin!

Installation

  1. Download and unpack plugin files to wp-content/plugins/scategory_permalink directory.

  2. Enable “sCategory Permalink” plugin on your Plugins page in Site Admin.

  3. Go to the Options/Permalinks page in Site Admin and use %scategory% option in Custom text field (you can look here for other options). In this blog I’m using /%scategory%/%postname%/.

  4. Now on Write Post page near the categories checkboxes radio button will appear:
    sCategory Permalink
    Select radio button near category which will be used in permalink.

  5. Have fun!

Download

You could always download latest version of the plugin here.

The post WordPress Plugins: sCategory Permalink – select category for permalink generation first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/wordpress/wordpress-plugins-scategory-permalink-select-category-for-permalink-generation/feed/ 17
Zend Framework: Router for subdirectory-based site https://kpumuk.info/php/zend-framework-router-for-subdirectory-based-site/ https://kpumuk.info/php/zend-framework-router-for-subdirectory-based-site/#comments Wed, 08 Mar 2006 10:36:57 +0000 http://kpumuk.info/php/zend-framework-router-for-subdirectory-based-site/ I started discovering of Zend Framework and was confronted with a problem. When I’ve placed my test sample into site’s subdirectory (http://localhost/test/), default router tried to find TestController which is not exists of course and routed me to IndexController/noRoute. It’s not good for me. I decided to create my own router. There some inconsistence in […]

The post Zend Framework: Router for subdirectory-based site first appeared on Dmytro Shteflyuk's Home.]]>
I started discovering of Zend Framework and was confronted with a problem. When I’ve placed my test sample into site’s subdirectory (http://localhost/test/), default router tried to find TestController which is not exists of course and routed me to IndexController/noRoute. It’s not good for me. I decided to create my own router.

There some inconsistence in Zend Framework (maybe because this is first release). To create my own router I need to develop class which implements Zend_Controller_Router_Interface interface:

1
2
3
4
5
6
7
8
9
10
11
interface Zend_Controller_Router_Interface
{
    /**
     * Processes an HTTP request and routes to a Zend_Controller_Dispatcher_Action object.  If
     * no route was possible, an exception is thrown.
     *
     * @throws Zend_Controller_Router_Exception
     * @return Zend_Controller_Dispatcher_Action|boolean
     */

    public function route();
}

Zend_Controller_Front uses this interface in following way:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Zend_Controller_Front
{
  // ...
  /**
   * Dispatch an HTTP request to a controller/action.
   */

  public function dispatch()
  {
    // ...
    $action = $this->getRouter()->route($this->getDispatcher());
    // ...
  }
}

Fine joke from Zend Framework’s developers. Front controller passes dispatcher to router, but router interface does not receive it. :-) Simplest way to avoid PHP error message is to define parameter which has default value null. Here my router class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/** Zend_Controller_Router_Interface */
require_once 'Zend/Controller/Router/Interface.php';

/** Zend_Controller_Dispatcher_Interface */
require_once 'Zend/Controller/Dispatcher/Interface.php';

/** Zend_Controller_Router_Exception */
require_once 'Zend/Controller/Router/Exception.php';

/** Zend_Controller_Dispatcher_Action */
require_once 'Zend/Controller/Dispatcher/Action.php';

class SubDirectoryRouter implements Zend_Controller_Router_Interface
{
  public function route(Zend_Controller_Dispatcher_Interface $dispatcher = null)
  {
    // SubDirectoryRouter: what's the path to where we are?
    $pathIndex = dirname($_SERVER['SCRIPT_NAME']);

    // SubDirectoryRouter: remove $pathIndex from $_SERVER['REQUEST_URI']
    $path = str_replace($pathIndex, '', $_SERVER['REQUEST_URI']);
    if (strstr($path, '?')) {
      $path = substr($path, 0, strpos($path, '?'));
    }
    $path = explode('/', trim($path, '/'));

    /**
     * The controller is always the first piece of the URI, and
     * the action is always the second:
     *
     * http://zend.com/controller-name/action-name/
     */

    $controller = $path[0];
    $action     = isset($path[1]) ? $path[1] : null;

    /**
     * If no controller has been set, IndexController::index()
     * will be used.
     */

    if (!strlen($controller)) {
      $controller = 'index';
      $action = 'index';
    }

    /**
     * Any optional parameters after the action are stored in
     * an array of key/value pairs:
     *
     * http://www.zend.com/controller-name/action-name/param-1/3/param-2/7
     *
     * $params = array(2) {
     *              ["param-1"]=> string(1) "3"
     *              ["param-2"]=> string(1) "7"
     * }
     */

    $params = array();
    for ($i=2; $i<sizeof($path); $i=$i+2) {
      $params[$path[$i]] = isset($path[$i+1]) ? $path[$i+1] : null;
    }

    $actionObj = new Zend_Controller_Dispatcher_Action($controller, $action, $params);

    if (!$dispatcher->isDispatchable($actionObj)) {
      /**
       * @todo error handling for 404's
       */

      throw new Zend_Controller_Router_Exception('Request could not be mapped to a route.');
    } else {
      return $actionObj;
    }
  }
}

Sample usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require('Zend.php');

Zend::loadClass('Zend_Controller_Action');
Zend::loadClass('Zend_Controller_Front');
Zend::loadClass('Zend_Filter');
Zend::loadClass('Zend_InputFilter');
Zend::loadClass('Zend_View');

Zend::loadClass('SubDirectoryRouter');

$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('controllers');

$router = new SubDirectoryRouter();
$controller->setRouter($router);

$controller->dispatch();

To make it work you need to place SubDirectoryRouter to the SubDirectoryRouter.php file and put it under include path.

The post Zend Framework: Router for subdirectory-based site first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/php/zend-framework-router-for-subdirectory-based-site/feed/ 12