toscho.design

WordPress-Plugin: Canonical Permalink

Ich habe schon darauf hingewiesen: WordPress nimmt numerische Anhänge sehr großzügig entgegen.

Ein paar dieser ungewollten Requests kann man per .htaccess umleiten; aber Francesco Schwarz hat jetzt auf ein Problem hingewiesen, das man so früh nicht abfangen kann: An jede Seiten- oder Artikeladresse kann man frei irgendwelche Zahlen anhängen.

In der .htaccess freilich kann man noch nicht wissen, ob so ein Anhang legal ist: Manche Seiten könnten auf mehrere Unterseiten aufgeteilt worden sein.

So könnte /seitenname/2/ erlaubt sein, /seitenname/3/ aber nicht, weil es keine dritte Seite gibt. Auch /seitenname/1/ ist natürlich Unfug: Diese Ausgabe ist mit der ersten Seite identisch.

Also muß ein Plugin her.

Zum Gucken und für Verbesserungshinweise noch der Quellcode:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?php
/*
Plugin Name: Canonical Permalink
Plugin URI: http://toscho.de/2010/wordpress-plugin-canonical-permalink/
Description: Removes illegal numeric suffixes from the request URI.
Version: 0.3
Author: Thomas Scholz
Author URI: http://toscho.de
Created: 04.04.2010
*/

/**
 * WordPress allows URIs with any numeric suffix, e.g.:
 * /canonical-page-or-postname/12345/
 * This functions performs a simple check and redirects
 * to the canonical URI if neccessary.
 *
 * @return void
 */
function canonical_request()
{
    global $page, $post;

    // post, page, attachment, preview
    if ( ! is_singular() or is_preview() )
    {
        return;
    }

    $permalink = get_permalink();

    // We don't have access to the number of sub pages here.
    // So we have to hack.
    $max_pages = substr_count(
        $post->post_content, '<!--nextpage-->') + 1;

    if ( 1 < $page and $page <= $max_pages )
    {
        /*
         * Handle different permalink settings, eg:
         * /%year%/%postname%.html or
         * /%year%/%postname%/
         */
        $rev_perma_struct = strrev(get_option('permalink_structure'));

        if ( '/' != $rev_perma_struct[0] )
        {
            $permalink .= "/$page";
        }
        else
        {
            $permalink .= "$page/";
        }
    }

    $host_uri       = 'http'
                    . ( empty ( $_SERVER['HTTPS'] ) ? '' : 's' )
                    . '://' . $_SERVER['HTTP_HOST'];
    $canonical_path = str_replace($host_uri, '', $permalink);

    if ( ! empty ( $_GET ) )
    {
        global $wp;
        // Array
        $allowed = $wp->public_query_vars;

        $out_arr = array();

        foreach ( $_GET as $k => $v )
        {
            if ( in_array($k, $allowed ) )
            {
                $out_arr[] = $k . ( empty ( $v ) ? '' : "=$v" );
            }
        }

        if ( ! empty ( $out_arr ) )
        {
            $canonical_path .= '?' . implode('&', $out_arr);
        }
    }

    if ( $canonical_path == $_SERVER['REQUEST_URI'] )
    {
        return;
    }
    // Debug current result:
    #print '<pre>' . var_export($canonical_path, TRUE) . '</pre>';

    // Change it or return 'false' to stop the redirect.
    $canonical_path = apply_filters(
        'toscho_canonical_path',
        $canonical_path
    );

    if ( FALSE != $canonical_path )
    {
        header('Location: ' . $permalink, true, 301);
        die("<a href='$permalink'>$permalink</a>");
    }

    return;
}
add_action('wp', 'canonical_request');

9 Kommentare

  1. Sergej Müller am 12.04.2010 · 10:52

    Thomas, wenn ich dir einen Tipp geben dürfte: is_single() or is_page() durch is_singular() ersetzen. Gibt allerdings auch bei is_attachment() ein TRUE zurück (ist aber in diesem Fall nicht verkehrt).

  2. Thomas Scholz am 12.04.2010 · 14:57

    @Sergej Müller: Stimmt, das ist besser. Habe es umgeschrieben.

  3. thomas am 04.05.2010 · 23:22

    hi thomas....

    using your plugin doesn't make fun at pages or articles using .

    Paged links like: blog.example.com/hallo-welt/2

    give me the result: blog.example.com/hallo-welt2/

    ...and just let me see my did not found commenting site ....sic!

    using wp 2.9.2

  4. Erik am 10.05.2010 · 20:03

    thomas: I think $permalink .= "$page/" should be $permalink .= "/$page" instead.

  5. Thomas Scholz am 10.05.2010 · 21:05

    @Erik: If the permalink already has a trailing slash, I shouldn’t add one. Anyway, I’ve updated the plugin. Try version 0.3.

  6. thomas am 16.05.2010 · 00:39

    sorry,
    ich war 'ne Woche weg auf'm Dorf mit abenteuerlicher Internetverbindung....

    Ich werde das Plug sobald ich 'n bischen Zeit hab Morgen / Übermorgen wieder versuchen....

    Der Fehler kann im Übrigen damit zusammenhängen das ich - also mein Fehler! - bei den Einstellungen der Permalinks einen Slash vegessen hatte (sic! ):
    also anstatt: /%postname%/
    nur : /%postname%

    eingetragen....

    Falls das Problem damit nicht beseitigt sein sollte - was ich ja mal annehme...dann nehme ich mal Eure Vorschläge ins Visier....

    bis später
    Grüße thomas

  7. Thomas Scholz am 16.05.2010 · 00:46

    @thomas: Das ist ja eine ganz legale Einstellung, damit sollte das Plugin also zurechtkommen. Ich habe es mit /%postname%.html getestet, und damit funktioniert die neue Fassung. Also sollte auch das bloße /%postname% kein Problem mehr sein.

  8. thomas am 16.05.2010 · 15:21

    na ja /%postname%/ schafft mir immerhin den Slash am Ende...und das sollte es schon sein.
    Habe das Plug wieder am laufen - ohne Probleme - allerdings sehe ich nicht ganz den Erfolg:

    Eine Archive Navi mit dem Ende 2010/page/1/ wird immer noch genauso bedient wie nur der Aufruf mit 2010....???

    Ebenso nextpage Aufrufe nach dem Muster: hallo-welt/1/ landen genau dort wo hallo-welt/ auch landen - ebenson wie die Aufrufe die ich mit hallo-welt/99999/ bediene, wohingegen diese Aufrufe vorher ohne Plug - und das ist die einzige Änderung die ich feststellt - unmittelbar zu der Seite zurückführten von der ich gekommen war z.B. hallo-welt/2/

    Da sollte nun doch eigentlich "Seite nicht gefunden" kommen....????

    schöne grüße
    thomas

  9. thomas am 16.05.2010 · 15:35

    ...aber noch als Ergänzung:
    immerhin Archiv Aufrufe nach dem Muster 2010/page/2222222222/ führen nun allerdings doch zur nicht gefundenen Seite.....

    Aber nextpage Aufrufe nach dem Muster hallo-welt/222222222222/ führen zu hallo-welt