404page – your smart custom 404 error page - Version 2.4

Version Description

Version 2.4 fixes several issues. See changelog for details.

Download this release

Release Info

Developer petersplugins
Plugin Icon 128x128 404page – your smart custom 404 error page
Version 2.4
Comparing to
See all releases

Code changes from version 2.3 to 2.4

Files changed (3) hide show
  1. 404page.php +116 -46
  2. pluginicon.png +0 -0
  3. readme.txt +26 -10
404page.php CHANGED
@@ -3,15 +3,14 @@
3
  Plugin Name: 404page - your smart custom 404 error page
4
  Plugin URI: http://petersplugins.com/free-wordpress-plugins/404page/
5
  Description: Custom 404 the easy way! Set any page as custom 404 error page. No coding needed. Works with (almost) every Theme.
6
- Version: 2.3
7
- Author: Peter's Plugins, smartware.cc
8
  Author URI: http://petersplugins.com
9
  Text Domain: 404page
10
  License: GPL2+
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.txt
12
  */
13
 
14
-
15
  if ( ! defined( 'WPINC' ) ) {
16
  die;
17
  }
@@ -32,9 +31,9 @@ class Smart404Page {
32
  public function __construct() {
33
  $this->plugin_name = '404page';
34
  $this->plugin_slug = '404page';
35
- $this->version = '2.3';
36
  $this->get_settings();
37
- $this->init();
38
  }
39
 
40
  // get all settings
@@ -46,12 +45,22 @@ class Smart404Page {
46
  // $this->settings['404page_method'] = $this->get_404page_method(); --> moved to set_mode in v 2.2 because this may be too early here
47
  $this->settings['404page_native'] = false;
48
  }
 
 
 
 
 
 
 
 
49
 
50
- // do plugin init
51
- private function init() {
 
52
 
53
  // as of v 2.2 always call set_mode
54
- add_action( 'init', array( $this, 'set_mode' ) );
 
55
 
56
  if ( !is_admin() ) {
57
 
@@ -91,7 +100,8 @@ class Smart404Page {
91
  } elseif ( $this->settings['404page_method'] != 'STD' ) {
92
 
93
  // Compatibility Mode
94
- add_filter( 'posts_results', array( $this, 'show404_compatiblity_mode' ), 999 );
 
95
 
96
  } else {
97
 
@@ -111,7 +121,7 @@ class Smart404Page {
111
  function show404_standard_mode( $template ) {
112
 
113
  global $wp_query;
114
- $pageid = $this->settings['404page_page_id'];
115
  if ( $pageid > 0 ) {
116
  if ( ! $this->settings['404page_native'] ) {
117
  $wp_query = null;
@@ -132,27 +142,39 @@ class Smart404Page {
132
  function show404_compatiblity_mode( $posts ) {
133
 
134
  // remove the filter so we handle only the first query - no custom queries
135
- remove_filter( 'posts_results', array( $this, 'show404_compatiblity_mode' ), 999 );
136
 
137
- $pageid = $this->settings['404page_page_id'];
138
  if ( $pageid > 0 && ! $this->settings['404page_native'] ) {
139
  if ( empty( $posts ) && is_main_query() && !is_robots() && !is_home() && !is_feed() && !is_search() && !is_archive() && ( !defined('DOING_AJAX') || !DOING_AJAX ) ) {
140
- // we need to get the 404 page
141
-
142
- $pageid = $this->get_page_id( $pageid );
143
 
144
  // as of v2.1 we do not alter the posts argument here because this does not work with SiteOrigin's Page Builder Plugin, template_include filter introduced
145
  $this->postid = $pageid;
146
- $this->template = get_page_template_slug( $pageid );
147
- if ( $this->template == '' ) {
148
- $this->template = get_page_template();
149
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  add_action( 'wp', array( $this, 'do_404_header' ) );
151
  add_filter( 'body_class', array( $this, 'add_404_body_class' ) );
152
  add_filter( 'template_include', array( $this, 'change_404_template' ), 999 );
153
 
154
- $posts[] = get_post( $pageid );
155
-
156
  $this->do_404page_action();
157
 
158
  } elseif ( 1 == count( $posts ) && 'page' == $posts[0]->post_type ) {
@@ -192,6 +214,7 @@ class Smart404Page {
192
 
193
  // this function overrides the page template in compatibilty mode
194
  function change_404_template( $template ) {
 
195
  // we have to check if the template file is there because if the theme was changed maybe a wrong template is stored in the database
196
  $new_template = locate_template( array( $this->template ) );
197
  if ( '' != $new_template ) {
@@ -226,7 +249,7 @@ class Smart404Page {
226
  // show title - Customizr Compatibility Mode
227
  function show404title_customizr_mode( $title ) {
228
  if ( ! $this->settings['404page_native'] ) {
229
- return '<h1 class="entry-title">' . get_the_title( $this->settings['404page_page_id'] ) . '</h1>';
230
  } else {
231
  return $title;
232
  }
@@ -235,7 +258,7 @@ class Smart404Page {
235
  // show content - Customizr Compatibility Mode
236
  function show404_customizr_mode( $content ) {
237
  if ( ! $this->settings['404page_native'] ) {
238
- return '<div class="entry-content">' . apply_filters( 'the_content', get_post_field( 'post_content', $this->settings['404page_page_id'] ) ) . '</div>';
239
  } else {
240
  return $content;
241
  }
@@ -245,7 +268,7 @@ class Smart404Page {
245
  // change article selectors - Customizr Compatibility Mode
246
  function show404articleselectors_customizr_mode( $selectors ) {
247
  if ( ! $this->settings['404page_native'] ) {
248
- return 'id="post-' . $this->settings['404page_page_id'] . '" ' . 'class="' . join( ' ', get_post_class( 'row-fluid', $this->settings['404page_page_id'] ) ) . '"';
249
  } else {
250
  return $selectors;
251
  }
@@ -272,7 +295,9 @@ class Smart404Page {
272
  function admin_css() {
273
  echo '<style type="text/css">#select404page {width: 100%; }';
274
  if ( $this->settings['404page_page_id'] > 0 ) {
275
- echo ' #the-list #post-' . $this->settings['404page_page_id'] . ' .column-title {min-height: 32px; background-position: left top; background-repeat: no-repeat; background-image: url(' . plugins_url( 'pluginicon.png', __FILE__ ) . '); padding-left: 40px;}';
 
 
276
  }
277
  echo '</style>';
278
  }
@@ -321,7 +346,7 @@ class Smart404Page {
321
 
322
  echo '<p><span class="dashicons dashicons-info"></span>&nbsp;' . __( 'This setting is not availbe because the 404page Plugin works in WPML Mode.', '404page' ) . ' (<a href="' . $this->dc_url . '/#special_modes">' . __( 'Read more', '404page' ) . '</a>)</p>';
323
 
324
- } elseif ( defined( 'POLYLANG_VERSION' ) ) {
325
 
326
  echo '<p><span class="dashicons dashicons-info"></span>&nbsp;' . __( 'This setting is not availbe because the 404page Plugin works in Polylang Mode.', '404page' ) . ' (<a href="' . $this->dc_url . '/#special_modes">' . __( 'Read more', '404page' ) . '</a>)</p>';
327
 
@@ -341,22 +366,25 @@ class Smart404Page {
341
 
342
  // this function hides the selected page from the list of pages
343
  function exclude_404page( $query ) {
344
- if ( $this->settings['404page_page_id'] > 0 ) {
 
345
  global $pagenow;
346
 
347
  $post_type = $query->get( 'post_type' );
348
 
349
  // as of v 2.3 we check the post_type on front end
350
  if( ( is_admin() && ( 'edit.php' == $pagenow && !current_user_can( 'create_users' ) ) ) || ( ! is_admin() && ( !empty( $post_type) && ( ('page' === $post_type || 'any' === $post_type) || ( is_array( $post_type ) && in_array( 'page', $post_type ) ) ) )) ) {
351
- $pageid = $this->settings['404page_page_id'];
352
 
353
- if ( ! is_admin() ) {
354
- $pageid = $this->get_page_id( $pageid );
 
 
 
355
  }
356
 
357
  // as of v 2.3 we add the ID of the 404 page to post__not_in
358
  // using just $query->set() overrides existing settings but not adds a new setting
359
- $query->set( 'post__not_in', array_merge( (array)$query->get( 'post__not_in', array() ), array( $pageid ) ) );
360
 
361
  }
362
  }
@@ -364,8 +392,8 @@ class Smart404Page {
364
 
365
  // this function removes the 404 page from get_pages result array
366
  function remove_404page_from_array( $pages, $r ) {
367
- if ( $this->settings['404page_page_id'] > 0 ) {
368
- $pageid = $this->get_page_id( $this->settings['404page_page_id'] );
369
  for ( $i = 0; $i < sizeof( $pages ); $i++ ) {
370
  if ( $pages[$i]->ID == $pageid ) {
371
  unset( $pages[$i] );
@@ -438,7 +466,7 @@ class Smart404Page {
438
 
439
  // returns the selected method
440
  private function get_404page_method() {
441
- if ( defined( 'ICL_SITEPRESS_VERSION' ) || defined( 'POLYLANG_VERSION' ) ) {
442
  // WPML or Polylang is active
443
  return 'CMP';
444
  } else {
@@ -456,20 +484,27 @@ class Smart404Page {
456
  return (bool)get_option( '404page_fire_error', true );
457
  }
458
 
459
- // this function gets the id of the translated page if WPML or Polylang is active - otherwise the original pageid is returned
460
- private function get_page_id( $pageid ) {
 
 
461
 
462
- if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
 
 
 
 
463
 
464
- // WPML is active
465
- $pageid = apply_filters( 'wpml_object_id', $pageid, 'page', true );
466
 
467
- } elseif ( defined( 'POLYLANG_VERSION' ) ) {
468
 
469
- // Polylang is active
470
- $translatedpageid = pll_get_post( $pageid );
471
- if ( !empty( $translatedpageid ) && 'publish' == get_post_status( $translatedpageid ) ) {
472
- $pageid = $translatedpageid;
 
473
  }
474
 
475
  }
@@ -478,6 +513,41 @@ class Smart404Page {
478
 
479
  }
480
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  // make plugin expandable
482
  function do_404page_action() {
483
  do_action( '404page_after_404' );
@@ -574,7 +644,7 @@ class Smart404Page {
574
  function pp_404_get_the_title() {
575
  $title = '';
576
  if ( $this->settings['404page_page_id'] > 0 && $this->settings['404page_native'] ) {
577
- $title = get_the_title( $this->settings['404page_page_id'] );
578
  }
579
  return $title;
580
  }
@@ -588,7 +658,7 @@ class Smart404Page {
588
  function pp_404_get_the_content() {
589
  $content = '';
590
  if ( $this->settings['404page_page_id'] > 0 && $this->settings['404page_native'] ) {
591
- $content = apply_filters( 'the_content', get_post_field( 'post_content', $this->settings['404page_page_id'] ) );
592
  }
593
  return $content;
594
  }
3
  Plugin Name: 404page - your smart custom 404 error page
4
  Plugin URI: http://petersplugins.com/free-wordpress-plugins/404page/
5
  Description: Custom 404 the easy way! Set any page as custom 404 error page. No coding needed. Works with (almost) every Theme.
6
+ Version: 2.4
7
+ Author: Peter's Plugins (formerly smartware.cc)
8
  Author URI: http://petersplugins.com
9
  Text Domain: 404page
10
  License: GPL2+
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.txt
12
  */
13
 
 
14
  if ( ! defined( 'WPINC' ) ) {
15
  die;
16
  }
31
  public function __construct() {
32
  $this->plugin_name = '404page';
33
  $this->plugin_slug = '404page';
34
+ $this->version = '2.4';
35
  $this->get_settings();
36
+ $this->load();
37
  }
38
 
39
  // get all settings
45
  // $this->settings['404page_method'] = $this->get_404page_method(); --> moved to set_mode in v 2.2 because this may be too early here
46
  $this->settings['404page_native'] = false;
47
  }
48
+
49
+ // load
50
+ // this function was introduced in v 2.4 and runs the init() function on firing of init action to ensure everything is loaded properly
51
+ private function load() {
52
+
53
+ add_action( 'init', array( $this, 'init' ) );
54
+
55
+ }
56
 
57
+ // do plugin init
58
+ // as of v 2.4 this runs after init action has fired to ensure everything is loaded properly
59
+ function init() {
60
 
61
  // as of v 2.2 always call set_mode
62
+ // as of v 2.4 we do not need to add an init action hook
63
+ $this->set_mode();
64
 
65
  if ( !is_admin() ) {
66
 
100
  } elseif ( $this->settings['404page_method'] != 'STD' ) {
101
 
102
  // Compatibility Mode
103
+ // As of v 2.4 we use the the_posts filter instead of posts_results, because the posts array is internally processed after posts_results fires
104
+ add_filter( 'the_posts', array( $this, 'show404_compatiblity_mode' ), 999 );
105
 
106
  } else {
107
 
121
  function show404_standard_mode( $template ) {
122
 
123
  global $wp_query;
124
+ $pageid = $this->get_page_id();
125
  if ( $pageid > 0 ) {
126
  if ( ! $this->settings['404page_native'] ) {
127
  $wp_query = null;
142
  function show404_compatiblity_mode( $posts ) {
143
 
144
  // remove the filter so we handle only the first query - no custom queries
145
+ remove_filter( 'the_posts', array( $this, 'show404_compatiblity_mode' ), 999 );
146
 
147
+ $pageid = $this->get_page_id();
148
  if ( $pageid > 0 && ! $this->settings['404page_native'] ) {
149
  if ( empty( $posts ) && is_main_query() && !is_robots() && !is_home() && !is_feed() && !is_search() && !is_archive() && ( !defined('DOING_AJAX') || !DOING_AJAX ) ) {
 
 
 
150
 
151
  // as of v2.1 we do not alter the posts argument here because this does not work with SiteOrigin's Page Builder Plugin, template_include filter introduced
152
  $this->postid = $pageid;
153
+
154
+ // as of v 2.4 we use the the_posts filter instead of posts_results
155
+ // therefore we have to reset $wp_query
156
+ // resetting $wp_query also forces us to remove the pre_get_posts action plus the get_pages filter
157
+
158
+ remove_action( 'pre_get_posts', array ( $this, 'exclude_404page' ) );
159
+ remove_filter( 'get_pages', array ( $this, 'remove_404page_from_array' ), 10, 2 );
160
+
161
+ global $wp_query;
162
+ $wp_query = null;
163
+ $wp_query = new WP_Query();
164
+ $wp_query->query( 'page_id=' . $pageid );
165
+ $wp_query->the_post();
166
+
167
+ $this->template = get_page_template();
168
+
169
+ $posts = $wp_query->posts;
170
+
171
+ $wp_query->rewind_posts();
172
+
173
+
174
  add_action( 'wp', array( $this, 'do_404_header' ) );
175
  add_filter( 'body_class', array( $this, 'add_404_body_class' ) );
176
  add_filter( 'template_include', array( $this, 'change_404_template' ), 999 );
177
 
 
 
178
  $this->do_404page_action();
179
 
180
  } elseif ( 1 == count( $posts ) && 'page' == $posts[0]->post_type ) {
214
 
215
  // this function overrides the page template in compatibilty mode
216
  function change_404_template( $template ) {
217
+
218
  // we have to check if the template file is there because if the theme was changed maybe a wrong template is stored in the database
219
  $new_template = locate_template( array( $this->template ) );
220
  if ( '' != $new_template ) {
249
  // show title - Customizr Compatibility Mode
250
  function show404title_customizr_mode( $title ) {
251
  if ( ! $this->settings['404page_native'] ) {
252
+ return '<h1 class="entry-title">' . get_the_title( $this->get_page_id() ) . '</h1>';
253
  } else {
254
  return $title;
255
  }
258
  // show content - Customizr Compatibility Mode
259
  function show404_customizr_mode( $content ) {
260
  if ( ! $this->settings['404page_native'] ) {
261
+ return '<div class="entry-content">' . apply_filters( 'the_content', get_post_field( 'post_content', $this->get_page_id() ) ) . '</div>';
262
  } else {
263
  return $content;
264
  }
268
  // change article selectors - Customizr Compatibility Mode
269
  function show404articleselectors_customizr_mode( $selectors ) {
270
  if ( ! $this->settings['404page_native'] ) {
271
+ return 'id="post-' . $this->get_page_id() . '" ' . 'class="' . join( ' ', get_post_class( 'row-fluid', $this->get_page_id() ) ) . '"';
272
  } else {
273
  return $selectors;
274
  }
295
  function admin_css() {
296
  echo '<style type="text/css">#select404page {width: 100%; }';
297
  if ( $this->settings['404page_page_id'] > 0 ) {
298
+ foreach ( $this->get_all_page_ids() as $pid ) {
299
+ echo ' #the-list #post-' . $pid . ' .column-title .row-title:before { content: "404"; background-color: #333; color: #FFF; display: inline-block; padding: 0 5px; margin-right: 10px; }';
300
+ }
301
  }
302
  echo '</style>';
303
  }
346
 
347
  echo '<p><span class="dashicons dashicons-info"></span>&nbsp;' . __( 'This setting is not availbe because the 404page Plugin works in WPML Mode.', '404page' ) . ' (<a href="' . $this->dc_url . '/#special_modes">' . __( 'Read more', '404page' ) . '</a>)</p>';
348
 
349
+ } elseif ( defined( 'xxxPOLYLANG_VERSION' ) ) {
350
 
351
  echo '<p><span class="dashicons dashicons-info"></span>&nbsp;' . __( 'This setting is not availbe because the 404page Plugin works in Polylang Mode.', '404page' ) . ' (<a href="' . $this->dc_url . '/#special_modes">' . __( 'Read more', '404page' ) . '</a>)</p>';
352
 
366
 
367
  // this function hides the selected page from the list of pages
368
  function exclude_404page( $query ) {
369
+ $pageid = $this->get_page_id();
370
+ if ( $pageid > 0 ) {
371
  global $pagenow;
372
 
373
  $post_type = $query->get( 'post_type' );
374
 
375
  // as of v 2.3 we check the post_type on front end
376
  if( ( is_admin() && ( 'edit.php' == $pagenow && !current_user_can( 'create_users' ) ) ) || ( ! is_admin() && ( !empty( $post_type) && ( ('page' === $post_type || 'any' === $post_type) || ( is_array( $post_type ) && in_array( 'page', $post_type ) ) ) )) ) {
 
377
 
378
+ // as of v 2.4 we hide all translations in admin for WPML
379
+ if ( is_admin() ) {
380
+ $pageids = $this->get_all_page_ids();
381
+ } else {
382
+ $pageids = array( $pageid );
383
  }
384
 
385
  // as of v 2.3 we add the ID of the 404 page to post__not_in
386
  // using just $query->set() overrides existing settings but not adds a new setting
387
+ $query->set( 'post__not_in', array_merge( (array)$query->get( 'post__not_in', array() ), $pageids ) );
388
 
389
  }
390
  }
392
 
393
  // this function removes the 404 page from get_pages result array
394
  function remove_404page_from_array( $pages, $r ) {
395
+ $pageid = $this->get_page_id();
396
+ if ( $pageid > 0 ) {
397
  for ( $i = 0; $i < sizeof( $pages ); $i++ ) {
398
  if ( $pages[$i]->ID == $pageid ) {
399
  unset( $pages[$i] );
466
 
467
  // returns the selected method
468
  private function get_404page_method() {
469
+ if ( defined( 'ICL_SITEPRESS_VERSION' ) || defined( 'xxxPOLYLANG_VERSION' ) ) {
470
  // WPML or Polylang is active
471
  return 'CMP';
472
  } else {
484
  return (bool)get_option( '404page_fire_error', true );
485
  }
486
 
487
+ // as of version 2.4 this function returns the page id of the 404 page in the current language
488
+ // in previous versions this functions required a parameter and only did the translation if WPML or Polylang is active
489
+ // now we have all in one function
490
+ private function get_page_id() {
491
 
492
+ $pageid = $this->settings['404page_page_id'];
493
+
494
+ if ( $pageid > 0 ) {
495
+
496
+ if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
497
 
498
+ // WPML is active
499
+ $pageid = apply_filters( 'wpml_object_id', $pageid, 'page', true );
500
 
501
+ } elseif ( defined( 'POLYLANG_VERSION' ) ) {
502
 
503
+ // Polylang is active
504
+ $translatedpageid = pll_get_post( $pageid );
505
+ if ( !empty( $translatedpageid ) && 'publish' == get_post_status( $translatedpageid ) ) {
506
+ $pageid = $translatedpageid;
507
+ }
508
  }
509
 
510
  }
513
 
514
  }
515
 
516
+ // if WPML is active this function returns an array of all page ids in all available languages
517
+ // otherwise it returns the page id as array
518
+ // introduced in v 2.4
519
+ private function get_all_page_ids() {
520
+
521
+ if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
522
+
523
+ // WPML is active
524
+ // get an array for all translations
525
+
526
+ $pageid = $this->settings['404page_page_id'];
527
+ $pages = array( $pageid );
528
+ if ( $pageid > 0 ) {
529
+ $languages = apply_filters( 'wpml_active_languages', NULL );
530
+ if ( !empty( $languages ) ) {
531
+ foreach( $languages as $l ) {
532
+ $p = apply_filters( 'wpml_object_id', $pageid, 'page', false, $l['language_code'] );
533
+ if ( $p ) {
534
+ $pages[] = $p;
535
+ }
536
+ }
537
+ }
538
+ }
539
+ $pageids = array_unique( $pages, SORT_NUMERIC );
540
+
541
+ } else {
542
+
543
+ $pageids = array( $this->get_page_id() );
544
+
545
+ }
546
+
547
+ return $pageids;
548
+
549
+ }
550
+
551
  // make plugin expandable
552
  function do_404page_action() {
553
  do_action( '404page_after_404' );
644
  function pp_404_get_the_title() {
645
  $title = '';
646
  if ( $this->settings['404page_page_id'] > 0 && $this->settings['404page_native'] ) {
647
+ $title = get_the_title( $this->get_page_id() );
648
  }
649
  return $title;
650
  }
658
  function pp_404_get_the_content() {
659
  $content = '';
660
  if ( $this->settings['404page_page_id'] > 0 && $this->settings['404page_native'] ) {
661
+ $content = apply_filters( 'the_content', get_post_field( 'post_content', $this->get_page_id() ) );
662
  }
663
  return $content;
664
  }
pluginicon.png CHANGED
Binary file
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link:http://petersplugins.com/make-a-donation/
4
  Tags: page, 404, error, error page, 404 page, page not found, page not found error, 404 error page, missing, broken link, template, 404 link, seo, custom 404, custom 404 page, custom 404 error, custom 404 error page, customize 404, customize 404 page, customize 404 error page
5
  Requires at least: 3.0
6
  Tested up to: 4.7
7
- Stable tag: 2.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -12,29 +12,31 @@ Custom 404 the easy way! Set any page as custom 404 error page. No coding needed
12
 
13
  == Description ==
14
 
15
- > Create your custom 404 Error Page using the full Power of WordPress
16
 
17
- **See also [Plugin Homepage](http://petersplugins.com/free-wordpress-plugins/404page/) and [Plugin Doc](http://petersplugins.com/docs/404page/)**
18
 
19
  https://www.youtube.com/watch?v=VTL07Lf0IsY
20
 
21
- Create your custom 404 Page as a normal WordPress Page using the full power of WordPress. You can use a Custom Page Template or Custom Fields, you can set a Featured Image - everything like on every other Page. Then go to 'Appearance' -> '404 Error Page' from your WordPress Dashbord and select the created Page as your 404 error page. That's it!
22
-
23
  = Why you should choose this plugin =
24
 
25
  * Different from other similar plugins the 404page plugin **does not create redirects**. That’s **quite important** because a correct code 404 is delivered which tells search engines that the page does not exist and has to be removed from the index. A redirect would result in a HTTP code 301 or 302 and the URL would remain in the search index.
26
  * Different from other similar plugins the 404page plugin **does not create additional server requests**.
27
 
28
- = Translations =
29
-
30
- The 404page Plugin uses GlotPress - the wordpress.org Translation System - for translations. Translations can be submitted at [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/404page).
31
 
32
- **Translation are highly appreciated**. It would be great if you'd support the 404page Plugin by adding a new translation or keeping an existing one up to date. If you're new to GlotPress take a look at the [Translator Handbook](https://make.wordpress.org/polyglots/handbook/tools/glotpress-translate-wordpress-org/).
33
 
34
  = Do you like the 404page Plugin? =
35
 
36
  Thanks, I appreciate that. You don’t need to make a donation. No money, no beer, no coffee. Please, just [tell the world that you like what I’m doing](http://petersplugins.com/make-a-donation/)! And that’s all.
37
 
 
 
 
 
 
 
38
  = More plugins from Peter =
39
 
40
  * **[hashtagger](https://wordpress.org/plugins/hashtagger/)** - Use hashtags in WordPress
@@ -80,6 +82,13 @@ The 404page plugin adds a CSS class `error404` to the `<body>` tag which can be
80
 
81
  == Changelog ==
82
 
 
 
 
 
 
 
 
83
  = 2.3 (2016-11-21) =
84
  * a few minor bug fixes solve some problems with page templates in certain combinations
85
 
@@ -135,6 +144,12 @@ The 404page plugin adds a CSS class `error404` to the `<body>` tag which can be
135
 
136
  == Upgrade Notice ==
137
 
 
 
 
 
 
 
138
  = 2.2 =
139
  Enhanced compatibility. Automated Operating Method select removed. Several fixes.
140
 
@@ -152,6 +167,7 @@ Editing of the 404 page is now possible directly from settings page. Portuguese
152
  = The 404page plugin was sucessfully tested by the author with the following themes =
153
  * [Athena](https://wordpress.org/themes/athena/)
154
  * [Customizr](https://wordpress.org/themes/customizr/) (Read more about [Customizr Compatibility Mode](http://petersplugins.com/docs/404page/#settings_operating_method))
 
155
  * [evolve](https://wordpress.org/themes/evolve/)
156
  * [GeneratePress](https://wordpress.org/themes/generatepress/)
157
  * [Graphene](https://wordpress.org/themes/graphene/)
@@ -174,7 +190,7 @@ Editing of the 404 page is now possible directly from settings page. Portuguese
174
  * [Zerif Lite](http://themeisle.com/themes/zerif-lite/)
175
 
176
  = The 404page plugin was sucessfully tested by the author with the following starter themes =
177
- * [Bones}(http://themble.com/bones/)
178
  * [JointsWP](http://jointswp.com/)
179
  * [undersores](http://underscores.me/)
180
 
4
  Tags: page, 404, error, error page, 404 page, page not found, page not found error, 404 error page, missing, broken link, template, 404 link, seo, custom 404, custom 404 page, custom 404 error, custom 404 error page, customize 404, customize 404 page, customize 404 error page
5
  Requires at least: 3.0
6
  Tested up to: 4.7
7
+ Stable tag: 2.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
12
 
13
  == Description ==
14
 
15
+ Create your custom 404 Page as a normal WordPress Page using the full power of WordPress. You can use a Custom Page Template or Custom Fields, you can set a Featured Image - everything like on every other Page. Then go to 'Appearance' -> '404 Error Page' from your WordPress Dashbord and select the created Page as your 404 error page. That's it!
16
 
17
+ = Watch the video =
18
 
19
  https://www.youtube.com/watch?v=VTL07Lf0IsY
20
 
 
 
21
  = Why you should choose this plugin =
22
 
23
  * Different from other similar plugins the 404page plugin **does not create redirects**. That’s **quite important** because a correct code 404 is delivered which tells search engines that the page does not exist and has to be removed from the index. A redirect would result in a HTTP code 301 or 302 and the URL would remain in the search index.
24
  * Different from other similar plugins the 404page plugin **does not create additional server requests**.
25
 
26
+ = More information =
 
 
27
 
28
+ See [Plugin Homepage](http://petersplugins.com/free-wordpress-plugins/404page/) and [Plugin Doc](http://petersplugins.com/docs/404page/).
29
 
30
  = Do you like the 404page Plugin? =
31
 
32
  Thanks, I appreciate that. You don’t need to make a donation. No money, no beer, no coffee. Please, just [tell the world that you like what I’m doing](http://petersplugins.com/make-a-donation/)! And that’s all.
33
 
34
+ = Translations =
35
+
36
+ The 404page Plugin uses GlotPress - the wordpress.org Translation System - for translations. Translations can be submitted at [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/404page).
37
+
38
+ **Translation are highly appreciated**. It would be great if you'd support the 404page Plugin by adding a new translation or keeping an existing one up to date. If you're new to GlotPress take a look at the [Translator Handbook](https://make.wordpress.org/polyglots/handbook/tools/glotpress-translate-wordpress-org/).
39
+
40
  = More plugins from Peter =
41
 
42
  * **[hashtagger](https://wordpress.org/plugins/hashtagger/)** - Use hashtags in WordPress
82
 
83
  == Changelog ==
84
 
85
+ = 2.4 (2017-03-08) =
86
+ * ensure that all core files are loaded properly ([See Topic](https://wordpress.org/support/topic/had-to-deactivate-404page-to-make-wordpress-correctly))
87
+ * Polylang plugin does no longer require Compatibility Mode ([See Topic](https://wordpress.org/support/topic/still-displaying-the-themes-404-page-with-polylang/))
88
+ * hide all translations if WPML is installed and "Hide 404 page" is active (thanks to the [WPML](https://wpml.org/) guys for pointing me at this)
89
+ * post status fix ([See topic](https://wordpress.org/support/topic/doesnt-work-with-custom-post-status/))
90
+ * [Enfold theme](https://themeforest.net/item/enfold-responsive-multipurpose-theme/4519990?ref=petersplugins) issue fix (thanks to the guys at [Kriesi.at](http://www.kriesi.at/) for supporting me)
91
+
92
  = 2.3 (2016-11-21) =
93
  * a few minor bug fixes solve some problems with page templates in certain combinations
94
 
144
 
145
  == Upgrade Notice ==
146
 
147
+ = 2.4 =
148
+ Version 2.4 fixes several issues. See [changelog](https://wordpress.org/plugins/404page/changelog/) for details.
149
+
150
+ = 2.3 =
151
+ A few minor bug fixes solve some problems with page templates in certain combinations.
152
+
153
  = 2.2 =
154
  Enhanced compatibility. Automated Operating Method select removed. Several fixes.
155
 
167
  = The 404page plugin was sucessfully tested by the author with the following themes =
168
  * [Athena](https://wordpress.org/themes/athena/)
169
  * [Customizr](https://wordpress.org/themes/customizr/) (Read more about [Customizr Compatibility Mode](http://petersplugins.com/docs/404page/#settings_operating_method))
170
+ * [Enfold](https://themeforest.net/item/enfold-responsive-multipurpose-theme/4519990?ref=petersplugins)
171
  * [evolve](https://wordpress.org/themes/evolve/)
172
  * [GeneratePress](https://wordpress.org/themes/generatepress/)
173
  * [Graphene](https://wordpress.org/themes/graphene/)
190
  * [Zerif Lite](http://themeisle.com/themes/zerif-lite/)
191
 
192
  = The 404page plugin was sucessfully tested by the author with the following starter themes =
193
+ * [Bones](http://themble.com/bones/)
194
  * [JointsWP](http://jointswp.com/)
195
  * [undersores](http://underscores.me/)
196