PluginProbe
HTTP 410 (Gone) responses / 0.3
HTTP 410 (Gone) responses v0.3
1.2.1 trunk 0.1 0.2 0.3 0.4 0.5 0.6 0.6.1 0.7 0.7.1 0.7.2 0.8.1 0.8.2 1.0.2 1.0.3 1.1.0
wp-410 / wp-410.php

wp-410.php in HTTP 410 (Gone) responses 0.3, at wp-410.php

209 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: 410 for Wordpress
4 Plugin URI: http://rayofsolaris.net/code/410-for-wordpress
5 Description: Sends HTTP 410 (Gone) responses to requests for pages that no longer exist on your blog.
6 Version: 0.3
7 Author: Samir Shah
8 Author URI: http://rayofsolaris.net/
9 License: GPL2
10 Text Domain: wp-410
11 */
12
13 if( !defined('ABSPATH') ) exit;
14
15 class WP_410 {
16 const dom = 'wp-410';
17 const link_opt = 'wp_410_links_list';
18 const version_opt = 'wp_410_options_version';
19 const db_version = 2; // DB version, since 0.2
20 private $permalinks;
21
22 function __construct() {
23 $struct = get_option('permalink_structure');
24 $this->permalinks = !empty( $struct );
25 load_plugin_textdomain( self::dom, false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
26
27 if( get_option( self::version_opt, 0 ) < self::db_version )
28 add_action( 'init', array( &$this, 'upgrade' ) );
29
30 if( is_admin() )
31 add_action( 'admin_menu', array( &$this, 'settings_menu' ) );
32
33 add_action('delete_post', array( &$this, 'note_deleted_post' ) );
34 add_action('wp_insert_post', array( &$this, 'note_inserted_post' ) );
35 add_action('template_redirect', array( &$this, 'check_for_410' ) );
36 }
37
38 function upgrade() {
39 $options_version = get_option( self::version_opt, 0 );
40 $old_links = get_option( self::link_opt, array() );
41 $new_links = array();
42
43 if( 0 == $options_version ) {
44 // upgrade from 0.1 to 0.2, saving links in regex form
45 foreach( $old_links as $link )
46 $new_links[ rawurldecode( $link ) ] = $this->build_regex( rawurldecode( $link ) ); // new links have key = display link and value = regex
47
48 }
49 elseif( 1 == $options_version ) {
50 // regex format changed, add case-insensitive parameter to end and fix urlencoding
51 foreach( $old_links as $key => $regex )
52 $new_links[ rawurldecode( $key ) ] = rawurldecode( $regex ) . 'i';
53 }
54
55 update_option( self::link_opt, $new_links );
56 update_option( self::version_opt, self::db_version );
57 }
58
59 function settings_menu() {
60 add_submenu_page('plugins.php', __('410 for Wordpress', self::dom), __('410 for Wordpress', self::dom), 'manage_options', 'wp_410_settings', array(&$this, 'settings_page') );
61 }
62
63 function settings_page() {
64 $old_links = get_option( self::link_opt, array() );
65
66 if ( isset( $_POST['submit'] ) ) {
67 $failed_to_add = array();
68 if( !empty( $_POST['old_links_to_add'] ) ) {
69 $added_links = preg_split( '/(\r?\n)+/', $_POST['old_links_to_add'], -1, PREG_SPLIT_NO_EMPTY );
70
71 foreach( $added_links as $k => $link ) {
72 $parts = parse_url( $link );
73 if( !$parts || empty( $parts['scheme'] ) || empty( $parts['host'] ) ) // invalid URL
74 $failed_to_add[] = '<code>' . htmlspecialchars( $link ) . '</code>';
75 else
76 $old_links[$link] = $this->build_regex( $link ); // key is display link, value is regex
77 }
78 }
79
80 if( !empty( $_POST['old_links_to_remove'] ) )
81 foreach( $_POST['old_links_to_remove'] as $key )
82 unset( $old_links[$key] );
83
84 ksort( $old_links );
85
86 update_option( self::link_opt, $old_links );
87 echo '<div class="updated fade"><p>'.__('Options updated.', self::dom).'</p></div>';
88
89 if( $failed_to_add )
90 echo '<div class="error"><p>'. __('The following entries could not be recognised as valid URLs, and were not added to the list.', self::dom). '<br />- ' . implode( '<br />- ', $failed_to_add ) .'</p></div>';
91 }
92 ?>
93 <style>
94 .indent {padding-left: 2em}
95 .wp_gone_deleted label {text-decoration: line-through}
96 </style>
97 <div class="wrap">
98 <h2><?php _e('410 for Wordpress', self::dom);?></h2>
99 <p><?php _e('This plugin will issue a HTTP 410 response to articles that no longer exist on your blog. When an article is deleted, it records this and issues a 410 response when pages unique to that article are requested. This HTTP code informs robots visiting your site that the requested page has been permanently removed, and that they should stop trying to access it.', self::dom);?></p>
100 <p><?php _e('Note: this plugin will only return a 410 response if Wordpress has not found something valid to display for the requested URL.', self::dom);?></p>
101 <form action="" method="post" id="wp-gone-captcha-settings">
102 <h3><?php _e('Obsolete URLs', self::dom);?></h3>
103 <?php
104 if( empty( $old_links ) ) {
105 echo '<p>' . __( 'There are currently no obsolete URLs in this list. You can add some manually below.', self::dom ) . '</p>';
106 }
107 else {
108 echo '<p>' . __( 'The following URLs are currently considered obsolete. To remove items from the list, check the corresponding box.', self::dom ) .'</p>';
109 echo '<ul id="wp_gone_old_links" class="indent">';
110 foreach( array_keys( $old_links ) as $k )
111 echo "<li><input type='checkbox' name='old_links_to_remove[]' value='" . htmlspecialchars( $k ) . "' id='old_link_$k' /> <label for='old_link_$k'><code>" . htmlspecialchars( rawurldecode( $k ) ). "</code></label></li>";
112 echo '</ul>';
113 }
114 ?>
115 <p><small><?php _e('If you create or update an article whose URL matches one of those above, that URL will automatically be removed from this list.', self::dom);?></small></p>
116 <h3><?php _e('Manually add URLs', self::dom);?></h3>
117 <p><?php _e('You can manually add items to the list by entering them below. Please enter one <strong>fully qualified</strong> URL per line.', self::dom);?></p>
118 <p><?php printf( __( 'Use %s as a wildcard character. So %s will match all URLs ending in %s.'), '<code>*</code>', '<code>http://www.example.com/*/music/</code>', '<code>/music/</code>' );?></p>
119 <textarea name="old_links_to_add" rows="8" cols="80"></textarea>
120 <p class="submit"><input class="button-primary" type="submit" name="submit" value="<?php _e('Update settings', self::dom);?>" /></p>
121 </form>
122 </div>
123 <script>
124 jQuery(document).ready(function(){
125 jQuery('#wp_gone_old_links input').change( function(){
126 this.parentNode.className = jQuery(this).is(":checked") ? 'wp_gone_deleted' : '';
127 });
128 });
129 </script>
130 <?php
131 }
132
133 function note_deleted_post( $id ) {
134 // NOTE: function wp_delete_post calls the delete_post action twice
135 static $delete_noted = false;
136
137 if( $delete_noted )
138 return;
139 $delete_noted = true;
140
141 $post = get_post( $id );
142
143 if( 'revision' == $post->post_type )
144 return;
145
146 $link = rawurldecode( get_permalink( $id ) );
147 if( $this->permalinks )
148 $link .= '*'; // catch everything like /page/ and /feed/
149
150 $list = get_option( self::link_opt, array() );
151
152 $list[$link] = $this->build_regex( $link );
153
154 update_option( self::link_opt, $list );
155 }
156
157 function note_inserted_post( $id ) {
158 $post = get_post( $id );
159
160 if( 'revision' == $post->post_type || 'draft' == $post->post_status )
161 return;
162
163 // Check our list of URLs against the new/updated post's permalink, and if they match, scratch it from our list
164 $links = array();
165
166 $links[] = rawurldecode( get_permalink( $id ) );
167 $links[] = get_post_comments_feed_link( $id ); // back compat
168
169 if( $this->permalinks )
170 $links[0] .= '*';
171
172 $list = get_option( self::link_opt, array() );
173
174 foreach( $links as $link )
175 unset( $list[$link] );
176
177 update_option( self::link_opt, $list );
178 }
179
180 function check_for_410() {
181 // Don't mess if Wordpress has found something to display
182 if( !is_404() )
183 return;
184
185 $links = get_option( self::link_opt, array() );
186 $req = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
187 $req = rawurldecode( $req );
188
189 foreach( $links as $regex ) {
190 if( @preg_match( $regex, $req ) ) {
191 status_header( 410 );
192 do_action( 'wp_410_response' ); // use this to customise the response message
193 _e( 'Sorry, the page you requested has been permanently removed.', self::dom );
194 exit;
195 }
196 }
197 }
198
199 private function build_regex( $link ) {
200 $parts = preg_split( '/(\*)/', $link, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
201 foreach( $parts as &$part ) if( '*' != $part )
202 $part = preg_quote( $part, '|' );
203 $parts = str_replace( '*', '.*', $parts );
204 return '|^' . implode( '', $parts ) . '$|i';
205 }
206 }
207
208 new WP_410();
209 ?>