PK y[ZX] admin/404page-admin-page.phpnu [ PK y[?5U U ppf/assets/img/advanced.svgnu [ PK y[ ppf/assets/img/general.svgnu [ PK y[#y1 1 ppf/assets/img/info.svgnu [ PK y[_Fu+ + ppf/assets/img/videos.svgnu [ PK y[PM]1 1 ppf/assets/js/jquery.cookie.jsnu [ /*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2013 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// Write
if (value !== undefined && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setTime(+t + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// Read
var result = key ? undefined : {};
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
var cookies = document.cookie ? document.cookie.split('; ') : [];
for (var i = 0, l = cookies.length; i < l; i++) {
var parts = cookies[i].split('=');
var name = decode(parts.shift());
var cookie = parts.join('=');
if (key && key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
if ($.cookie(key) === undefined) {
return false;
}
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));
PK y[jW W ppf/assets/js/pp-admin-page.jsnu [ jQuery( document ).ready(function( $ ) {
var cookie_name = pp_admin_cookie_prefix + '_current_tab';
$( '.tab-navigation .tabset' ).click( function() {
if ( $( this ).not( '.current' ) ) {
$( '.tab-panel .panel.current' ).removeClass( 'current ');
$( '#' + $(this).data('tab-content') ).addClass( 'current' );
$( '.tab-navigation .tabset.current' ).removeClass( 'current ');
$( this ).addClass( 'current' );
$.cookie( cookie_name, $( '.tab-navigation .tabset.current' ).attr('id') );
}
});
var current_tab = jQuery.cookie( cookie_name );
if ( current_tab === undefined ) {
current_tab = $( '.tab-navigation .tabset:first' ).attr('id');
$.removeCookie( cookie_name );
}
$( '#' + current_tab ).trigger( 'click' );
});PK y[sp ppf/loader.phpnu [ add_setting_section( $section );
}
// since PPF04
$this->maybe_register_setting();
}
/**
* add a single setting section
*
* @since PPF04
* @param array $sections setting section to add
* @access public
* @see add_settings()
*/
public function add_setting_section( $section ) {
// as of PPF04 add sections to _sections array one by one
$this->_sections[] = $section;
if ( array_key_exists( 'fields', $section ) ) {
$this->add_settings( $section );
}
$this->maybe_register_setting();
}
/**
* register the setting
*
* @since PPF04
* @access private
*
* was part of add_setting_sections() before PPF04
*/
public function maybe_register_setting() {
if ( ! $this->_settings_registered ) {
// Register the options
// since PPF03 only if there is a settings class
// so we can use the same function also if we don't need any settings
if ( false !== $this->settings() ) {
register_setting( $this->core()->get_plugin_slug(), $this->settings()->get_option_name(), array( 'sanitize_callback' => array( $this, 'sanitize_callback' ) ) );
}
$this->_settings_registered = true;
}
}
/**
* helper function to add a complete setting section
*
* @since PPF01
* @param array $settings array of settings to add
* string $section => ID of the section
* int $order => sort order
* this was added in PPF04, so we check if it exists for backwards compatibility
* string $title => title for section (used by print_setting_sections())
* string $icon => icon for tab
* since PPF05
* string $html => HTML code to add to this section
* array $fields => multidimensional array of fields to add
* string $key => key of the option array
* string $callback => function to call
* as of PPF04 this can be an array to enable external callbacks
* array $callbackargs => array of arguments to pass to callback function
* introduced in PPF08
* bool $nosubmit => this section should not show the submit button
* @access private
*/
private function add_settings( $settings ) {
$section_id = $this->core()->get_plugin_slug() . '-' . $settings['section'];
add_settings_section( $section_id, '', null, $this->core()->get_plugin_slug() );
foreach ( $settings['fields'] as $field ) {
$field_id = $this->core()->get_plugin_slug() . '-' . $field['key'];
// since PPF04
if ( is_array( $field['callback'] ) ) {
$callback = $field['callback'];
} else {
$callback = array( $this, $field['callback'] );
}
$callbackargs = false;
if ( isset( $field['callbackargs'] ) && is_array( $field['callbackargs'] ) ) {
$callbackargs = $field['callbackargs'];
}
add_settings_field( $field_id, '' , $callback, $this->core()->get_plugin_slug(), $section_id, $callbackargs );
}
return;
}
/**
* helper function to print out a slider styled checkbox
*
* @since PPF01
* @param string $key option key name
* @param string $title title
* @param string $help anchor to link to in manual
* @param string $video YouTube video ID
* @param string $note second line
* @param bool $disabled true/false (optional)
* @access public
*/
public function print_slider_check( $key, $title, $help, $video, $note, $disabled = false ) {
$dis = '';
if ( $disabled ) {
$dis = ' disabled="disabled"';
}
$hlp = '';
if ( ! empty( $help ) ) {
$hlp = $this->add_manual_link( $help );
}
$vid = '';
if ( ! empty( $video ) ) {
$vid = $this->add_video_link( $video );
}
$add = '';
if ( ! empty( $note ) ) {
$add = ' ' . $note;
}
echo '
';
}
/**
* helper function to add a plugin manual link
*
* @since PPF01
* @param string $anchor name of the anchor to link to
* @return string
* @access private
*/
private function add_manual_link( $anchor = '' ) {
return ' ';
}
/**
* helper function to add a video link
*
* @since PPF01
* @param string $youtubeid ID of the YouTube video
* @return string
* @access private
*/
private function add_video_link( $youtubeid = '' ) {
return ' ';
}
/**
* print out setting sections
* it is not possible to use do_settings_sections() because we are not able to create a tabbed interface
*
* @since PPF01
* @access public
* @see add_settings()
*/
public function print_setting_sections() {
$currentclass = ' current';
foreach( $this->_sections as $section ) {
$section_id = $this->core()->get_plugin_slug() . '-' . $section['section'];
$extraclass = '';
if ( array_key_exists( 'nosubmit', $section ) && true === $section['nosubmit'] ) {
$extraclass = ' nosubmit';
}
echo '
';
}
/**
* sanitize the posted values
*
* @since PPF01
* @param array $settings array of settings to save
* @access public
*/
public function sanitize_callback( $settings ) {
// since PPF06
// if wen don't get anything we need to create an empty array
if ( empty( $settings ) ) {
$settings = array();
}
foreach ( $this->settings()->get_defaults() as $key => $value ) {
if ( true === is_bool( $value ) ) {
if ( ! array_key_exists( $key, $settings ) ) {
// we have to add the missing keys
// HTML forms only send data if a checkbox is checked
// missing keys would be overwritten with their default on next load
// this concerns only boolean values
// if key does not exist the checkbox was not checked
// so we have to handle it as false
$settings[$key] = false;
} else {
// also we check if a given value is boolean
// otherwise we reset it to false
// this is for security
// so it is not possible to pass non boolean values
// if a checkbox was checked we get 1
// so we only have to check for 1
if ( 1 != $settings[$key] ) {
$settings[$key] = false;
}
}
}
}
// it is not possible to do other sanitation because we do not know what to do
// more sanitation has to be done by the plugin itself
return $this->sanitize_settings( $settings );
}
/**
* sanitize the settings
* called by sanitize_callback()
* this can be used to sanitize the settings after missing keys have been added
*
* @since PPF01
* @param array $settings array of settings to save
* @access public
*/
public function sanitize_settings( $settings ) {
return $settings;
}
/**
* add toolbar icons
*
* @since PPF01
* @param array $icons array of icons to show in toolbar
* string $link => URL to link to
* string $title => title to show
* string $icon => icon to use from dashicons
* @access public
*/
public function add_toolbar_icons( $icons ) {
$this->_toolbar = '';
}
/**
* show the admin page
*
* @since PPF01
* @param string $capability minimum required capability to show page (optional)
* @access public
*/
public function show( $capability = 'read' ) {
if ( !current_user_can( $capability ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.' ) );
}
// sort the sections
// see add_settings()
$sort = false;
foreach( $this->_sections as $section ) {
if ( array_key_exists( 'order', $section ) ) {
$sort = true;
break;
}
}
if ( $sort ) {
usort( $this->_sections, function( $a, $b ) {
return $a['order'] - $b['order'];
} );
}
// end of sort
if ( get_current_screen()->parent_base != 'options-general' ) {
// On Option Screens settings_errors() is called automatically
settings_errors();
}
echo '
';
echo '
';
echo $this->_toolbar;
echo '
' . $this->core()->get_plugin_shortname() . '
';
echo '
';
$this->print_setting_sections_nav();
echo '
';
echo '';
echo '
';
echo '';
wp_enqueue_style( $this->core()->get_plugin_slug() . '-ppf03', $this->get_foundation_asset_url( 'css', 'pp-admin-page.css' ) );
wp_enqueue_script( $this->core()->get_plugin_slug() . '-ppf03-cookie', $this->get_foundation_asset_url( 'js', 'jquery.cookie.js' ), array( 'jquery' ), false, true );
wp_enqueue_script( $this->core()->get_plugin_slug() . '-ppf03', $this->get_foundation_asset_url( 'js', 'pp-admin-page.js' ), array( 'jquery', $this->core()->get_plugin_slug() . '-ppf03-cookie' ), false, true );
}
/**
* set screen id
*
* @since PPF01
* @param string $id id of screen
* @access public
*/
public function set_screen_id( $id ) {
$this->_my_screen_id = $id;
}
/**
* get screen id
*
* @since PPF01
* @return string
* @access public
*/
public function get_screen_id() {
return $this->_my_screen_id;
}
/**
* show admin notice to ask for rating
* this function does not show the notice immediately
* this function just needs to be called and it takes care of everything
*
* @since PPF01
* @param array $content array of texts to show
* string $title => e.g. 'Are you happy with the example plugin?'
* string $subtitle => e.g. 'You've been using this plugin for a while now. Would be great to get some feedback!'
* string $button_yes => e.g. 'Yes, I'm happy with it'
* string $button_no => e.g. 'Not really'
* string $button_later => e.g. 'Ask me later'
* string $button_close => e.g. 'Never show again'
* string $like => e.g. 'I'm really glad you like it. I do not ask for a donation. All I'm asking you for is to give it a good rating. Thank you very much.
* string $button_rate => e.g. 'Yes, I'd like to rate it'
* string $dislike => e.g. 'I'm really sorry you don't like it. Would you please do me a favor and drop me line, why you are not happy with it? Maybe I can do better...'
* string $button_contact => e.g. 'Yes sure'
* @param array $links array of links
* string $rate => e.g. https://wordpress.org/support/plugin/example/reviews/
* string $contact => e.g. https://petersplugins.com/contact/
* @access public
*/
public function init_rating_notice( $content, $links ) {
// quit immediately if message has already been closed
if ( 'YES' == $this->core()->data_get( 'ask_rating_closed' ) ) {
return;
}
$show_notice_start = $this->core()->data_get( 'ask_rating_start' );
// if start date is not set, set it and quit immediately
if ( false === $show_notice_start ) {
$this->core()->data_set( 'ask_rating_start', time() + 30 * DAY_IN_SECONDS );
$this->core()->data_save();
return;
}
// quit immediately if start date is not reached yet
if ( time() < $show_notice_start ) {
return;
}
// quit immediately if current user is not an admin
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$prefix = 'pp-' . $this->core()->get_plugin_slug();
$nonce = wp_create_nonce( $prefix );
// prepare to show notice
add_action( 'admin_notices', function() use( $content, $links, $prefix, $nonce ) {
// show notice only on certain pages
// it's not possible to check this earlier, because we need the id of the current screen for that
if ( ! in_array( get_current_screen()->id, array( 'dashboard', 'themes', 'plugins', 'options-general' , $this->get_screen_id() ) ) ) {
return;
}
?>
id, array( 'dashboard', 'themes', 'plugins', 'options-general' , $this->get_screen_id() ) ) ) {
return;
}
echo '
';
} );
// prepare for ajax
add_action( 'wp_ajax_' . $prefix . '-review-action', function() use( $prefix ) {
check_ajax_referer( $prefix, 'securekey' ); // dies if check fails
if ( isset( $_POST['command'] ) ) {
if ( $prefix . '-review-later' == $_POST['command'] ) {
// move start date 14 days into future
$this->core()->data_set( 'ask_rating_start', time() + 14 * DAY_IN_SECONDS );
$this->core()->data_save();
}
if ( $prefix . '-review-close' == $_POST['command'] ) {
// do not show notice again
$this->core()->data_set( 'ask_rating_closed', 'YES' );
$this->core()->data_save();
}
}
wp_die();
} );
}
}
}PK y[eJqMR R ppf/ppf-class.phpnu [ _dir = __DIR__;
}
/**
* get foundation directory
*
* @since PPF01
* @access protected
* @return string
*/
protected function get_foundation_dir() {
// since PPF02 we have to get the Directory of the Called Class to allow multiple classes based on the same Plugin Foundation
$rc = new ReflectionClass( get_called_class() );
return dirname( $rc->getFileName() ) . '/ppf';
}
/**
* get url for foundation asset file
*
* @since PPF01
* @access protected
* @param string $dir sub-directory of assets dir (js, css)
* @param string $file filename
* @return string
*/
protected function get_foundation_asset_url( $dir, $file ) {
return plugins_url() . str_replace( WP_PLUGIN_DIR, '', $this->get_foundation_dir() ) . '/assets/' . $dir . '/' . $file;
}
/**
* get path for foundation asset file
*
* @since PPF01
* @access protected
* @param string $dir sub-directory of assets dir (js, css)
* @param string $file filename
* @return string
*/
protected function get_foundation_asset_path( $dir, $file ) {
return plugin_dir_path( $this->get_foundation_dir() ) . 'assets/' . $dir . '/' . $file;
}
/**
* add action
*
* @since PPF01
* @access public
* @param string $wpaction name of the action to add
* @param int $priority priority - optional - default 10
* @param int $accepted_args number of arguments the function accepts - optional - default 1
*/
public function add_action( $wpaction, $priority = 10, $accepted_args = 1 ) {
add_action( $wpaction, array( $this, 'action_' . $wpaction ), $priority, $accepted_args );
}
/**
* add multiple actions
* this function does not allow to specify priority and accepted_args
*
* @since PPF01
* @access public
* @param array $actions array of actions to add
* @see add_action()
*/
public function add_actions( $actions ) {
foreach ( $actions as $action ) {
$this->add_action( $action );
}
}
/**
* add filter
*
* @since PPF01
* @access public
* @param string $wpfilter name of the filter to add
* @param int $priority priority - optional - default 10
* @param int $accepted_args number of arguments the function accepts - optional - default 1
*/
public function add_filter( $wpfilter, $priority = 10, $accepted_args = 1 ) {
add_filter( $wpfilter, array( $this, 'filter_' . $wpfilter ), $priority, $accepted_args );
}
}
}PK y[9*. ppf/ppf-plugin-addon.phpnu [ plugin_file = $settings['file'];
$this->plugin_slug = $settings['slug'];
$this->plugin_name = $settings['name'];
$this->plugin_shortname = $settings['shortname'];
$this->plugin_version = $settings['version'];
$this->base_plugin_name = $settings['base_plugin_name'];
$this->base_plugin_function = $settings['base_plugin_function'];
$this->base_plugin_min_version = $settings['base_plugin_min_version'];
$this->_data_key = str_replace( '-', '_', $settings['slug'] ) . '_data';
$this->data_load();
$this->addon_check();
}
/**
* get Base Plugin Name
*
* @since PPF04
* @access public
* @return string
*/
public function get_base_plugin_name() {
return $this->base_plugin_name;
}
/**
* get Base Plugin Function
*
* @since PPF04
* @access public
* @return string
*/
public function get_base_plugin_function() {
return $this->base_plugin_function;
}
/**
* get Base Plugin minimum required version^
*
* @since PPF04
* @access public
* @return string
*/
public function get_base_plugin_min_version() {
return $this->base_plugin_min_version;
}
/**
* check if base plugin exists and has required minimum version
*
* @since PPF04
* @access private
*/
private function addon_check() {
// we need to place all the stuff in plugins_loaded to ensure the base plugin is loaded
add_action( 'plugins_loaded', function() {
$this->plugin_install_update();
$this->plugin_init();
if ( ! $this->base_exists() ) {
add_action('admin_notices', array( $this, 'admin_notice_base_plugin_not_found' ) );
} elseif ( version_compare( $this->get_base_plugin_min_version(), $this->call_base()->get_plugin_version(), '>' ) ) {
add_action('admin_notices', array( $this, 'admin_notice_base_plugin_version_insufficient' ) );
} else {
$this->addon_init();
}
} );
}
/**
* call base plugin
*
* @since PPF04
*/
public function call_base() {
$base = $this->get_base_plugin_function();
if ( function_exists( $base ) ) {
return $base();
}
return false;
}
/**
* check if base function exists
*
* @since PPF04
*/
public function base_exists() {
$base = $this->get_base_plugin_function();
if ( function_exists( $base ) ) {
return true;
}
return false;
}
/**
* addon init
*
* force to be defined
*
* @since PPF04
*/
abstract public function addon_init();
/**
* add admin notice if base plugin not found
*
* force to be defined
*
* @since PPF04
*/
abstract public function admin_notice_base_plugin_not_found();
/**
* add admin notice if base plugin version insufficient
*
* force to be defined
*
* @since PPF04
*/
abstract public function admin_notice_base_plugin_version_insufficient();
}
}PK y[ hɹ- - ppf/ppf-plugin.phpnu [ plugin_file = $settings['file'];
$this->plugin_slug = $settings['slug'];
$this->plugin_name = $settings['name'];
$this->plugin_shortname = $settings['shortname'];
$this->plugin_version = $settings['version'];
$this->plugin_dir = dirname( $settings['file'] );
$this->_data_key = str_replace( '-', '_', $settings['slug'] ) . '_data';
$this->data_load();
$this->plugin_install_update();
$this->plugin_init();
}
/**
* plugin init
*
* force to be defined
*
* @since PPF01
*/
abstract public function plugin_init();
/**
* Prevent Cloning
*
* @since PPF01
*/
final protected function __clone() {}
/**
* Get the Instance
*
* @since PPF01
* @param array $settings {
* @type string $file Plugin Main File Path and Name
* @type string $slug Plugin Slug
* @type string $name Plugin Name
* @type string $version Plugin Verion
* }
* @return singleton
*/
final public static function getInstance( $settings ) {
$calledClass = get_called_class();
if ( !isset( self::$_instances[$calledClass] ) )
{
self::$_instances[$calledClass] = new $calledClass( $settings );
}
return self::$_instances[$calledClass];
}
/**
* get plugin file
*
* @since PPF01
* @access public
* @return string
*/
public function get_plugin_file() {
return $this->plugin_file;
}
/**
* get plugin slug
*
* @since PPF01
* @access public
* @return string
*/
public function get_plugin_slug() {
return $this->plugin_slug;
}
/**
* get plugin name
*
* @since PPF01
* @access public
* @return string
*/
public function get_plugin_name() {
return $this->plugin_name;
}
/**
* get plugin shortname
*
* @since PPF01
* @access public
* @return string
*/
public function get_plugin_shortname() {
return $this->plugin_shortname;
}
/**
* get plugin version
*
* @since PPF01
* @access public
* @return string
*/
public function get_plugin_version() {
return $this->plugin_version;
}
/**
* get url for asset file
*
* @since PPF01
* @access public
* @param string $dir sub-directory of assets dir (js, css)
* @param string $file filename
* @return string
*/
public function get_asset_url( $dir, $file ) {
return plugins_url( 'assets/' . $dir . '/' . $file, $this->get_plugin_file() );
}
/**
* get path for asset file
*
* @since PPF01
* @access public
* @param string $dir sub-directory of assets dir (js, css)
* @param string $file filename
* @return string
*/
public function get_asset_path( $dir, $file ) {
return plugin_dir_path( $this->get_plugin_file() ) . 'assets/' . $dir . '/' . $file;
}
/**
* add a sub class
*
* @since PPF01
* @access private
* @param string $class name of the class
* @param string $file class file without extension php (must bei located in inc dir)
* @param object $_core the core class
* @param object $_settings the settings class (optional)
* @return class
*/
private function add_sub_class( $class, $file, $_core, $_settings = false ) {
require_once plugin_dir_path( $this->get_plugin_file() ) . 'inc/' . $file . '.php';
return new $class( $_core, $_settings);
}
/**
* add a sub class as well in frontend as in backend
*
* @since PPF01
* @access public
* @uses add_sub_class()
* @return class
*/
public function add_sub_class_always( $class, $file, $_core, $_settings = false ) {
return $this->add_sub_class( $class, $file, $_core, $_settings );
}
/**
* add a sub class only in frontend
*
* @since PPF01
* @access public
* @uses add_sub_class()
* @return class or false
*/
public function add_sub_class_frontend( $class, $file, $_core, $_settings = false ) {
if ( ! is_admin() ) {
return $this->add_sub_class( $class, $file, $_core, $_settings );
}
return false;
}
/**
* add a sub class only in backend
*
* @since PPF01
* @access public
* @uses add_sub_class()
* @return class or false
*/
public function add_sub_class_backend( $class, $file, $_core, $_settings = false ) {
if ( is_admin() ) {
return $this->add_sub_class( $class, $file, $_core, $_settings );
}
return false;
}
/**
* add the settings class ( if the plugin uses settings )
*
* @since PPF01
* @access public
* @param string $class name of the class
* @param string $file class file without extension php (must bei located in inc dir)
* @param object $_core the core class
* @param object $defaults the settings defaults
*/
public function add_settings_class( $class, $file, $_core, $defaults ) {
require_once plugin_dir_path( $this->get_plugin_file() ) . 'inc/' . $file . '.php';
$this->settings = new $class( $_core, $defaults );
}
/**
* get settings class
*
* @since PPF01
* @access public
* @return object
*/
public function settings() {
return $this->settings;
}
/**
* do plugin install or update
*
* @since PPF01
* @access protected (since PPF04, was private before)
*/
protected function plugin_install_update() {
$version = $this->data_get( 'current_version' );
if ( false === $version || version_compare( $version, $this->get_plugin_version(), '<' ) ) {
if ( false === $version ) {
// the plugin was not installed before (or the plugin foundation was not used before...)
$this->do_plugin_install();
} else {
// do updates if needed
$this->do_plugin_update( $version, $this->get_plugin_version() );
}
$this->data_set( 'current_version', $this->get_plugin_version() );
$this->data_save();
}
}
/**
* plugin install
*
* to be overwritten
*
* @since PPF01
* @access public
*/
public function do_plugin_install() {}
/**
* plugin update
*
* to be overwritten
*
* @since PPF01
* @access public
*/
public function do_plugin_update( $stored_version, $actual_version ) {}
/**
* load plugin data from database
*
* @since PPF01
* @access public
*/
public function data_load() {
$this->_data = get_option( $this->_data_key, array() );
}
/**
* get a data value
*
* @since PPF01
* @param string $key data key
* @access public
*/
public function data_get( $key ) {
if ( is_array( $this->_data ) && array_key_exists( $key, $this->_data ) ) {
return $this->_data[$key];
} else {
return false;
}
}
/**
* set a data value
*
* @since PPF01
* @param string $key data key
* @param string $value new value
* @access public
*/
public function data_set( $key, $value ) {
return $this->_data[$key] = $value;
}
/**
* save data to database
*
* @since PPF01
* @access public
*/
public function data_save() {
update_option( $this->_data_key, $this->_data );
}
/**
* remove all data from database
*
* @since PPF01
* @access public
*/
public function data_remove() {
delete_option( $this->_data_key );
}
}
}PK y[6Ss s ppf/ppf-settings.phpnu [ _key = $this->get_option_name();
$this->_defaults = $defaults;
$this->load();
}
/**
* Sub-Class init
* do nothing
*
* @since PPF01
* @access public
*/
public function init() {
}
/**
* get option name for settings
*
* @since PPF01
* @access public
* @return string option name
*/
public function get_option_name() {
return str_replace( '-', '_', $this->core()->get_plugin_slug() ) . '_settings';
}
/**
* load settings from database
* settings are automatically loaded, but reload can be forced from outside
*
* @since PPF01
* @access public
*/
public function load() {
$this->_settings = get_option( $this->_key, array() );
$this->_settings = wp_parse_args( $this->_settings, $this->_defaults );
$this->sanitize_settings();
}
/**
* sanitize settings
* this function can be used to sanitize settings after they are loaded
*
* @since PPF01
* @access public
*/
public function sanitize_settings() {
// Just to be defined here
}
/**
* get a settings value
*
* @since PPF01
* @param string $key settings key
* @access public
*/
public function get( $key ) {
// as of PPF04 we check if the key exists
if ( array_key_exists( $key, $this->_settings ) ) {
return $this->_settings[$key];
} else {
return null;
}
}
/**
* set a settings value
*
* @since PPF01
* @param string $key settings key
* @param string $value new value
* @access public
*/
public function set( $key, $value ) {
return $this->_settings[$key] = $value;
}
/**
* save settings to database
*
* @since PPF01
* @access public
*/
public function save() {
update_option( $this->_key, $this->_settings );
}
/**
* get option key name for HTML form fields
*
* @since PPF01
* @param string $key settings key
* @access public
* @return string option key name
*/
public function get_option_key_name( $key ) {
return $this->get_option_name() . '[' . $key . ']';
}
/**
* get the defaults
*
* @since PPF01
* @access public
* @return array defaults
*/
public function get_defaults() {
return $this->_defaults;
}
/**
* remove
*
* @since PPF01
* @access public
*/
public function remove() {
delete_option( $this->_key );
}
}
}PK y[DI ppf/ppf-subclass.phpnu [ _core = $_core;
$this->_settings = $_settings;
$this->init();
}
/**
* Sub-Class init
*
* force to be defined
*
* @since PPF01
*/
abstract public function init();
/**
* get core class
*
* @since PPF01
* @access public
* @return object
*/
public function core() {
return $this->_core;
}
/**
* get settings class
*
* @since PPF01
* @access public
* @return object
*/
public function settings() {
return $this->_settings;
}
}
}PK y[Rb> b> class-404page-admin.phpnu [ add_actions( array(
'admin_init',
'admin_menu',
'admin_head'
) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_js' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_css' ) );
}
/**
* init admin
* moved to PP_404Page_Admin in v 10
*/
function action_admin_init() {
$this->settings()->set_method();
// @since 11.0.0
$this->add_setting_sections(
array(
array(
'section' => 'general',
'order' => 10,
'title' => esc_html__( 'General', '404page' ),
'icon' => 'general',
'fields' => array(
array(
'key' => 'page_id',
'callback' => 'admin_404page'
)
)
),
array(
'section' => 'advanced',
'order' => 20,
'title' => esc_html__( 'Advanced', '404page' ),
'icon' => 'advanced',
'fields' => array(
array(
'key' => 'hide',
'callback' => 'admin_hide'
),
array(
'key' => 'fire_error',
'callback' => 'admin_fire404'
),
array(
'key' => 'force_error',
'callback' => 'admin_force404'
),
array(
'key' => 'no_url_guessing',
'callback' => 'admin_noguess'
),
array(
'key' => 'http410_if_trashed',
'callback' => 'admin_http410'
),
array(
'key' => 'http410_always',
'callback' => 'admin_http410_always'
),
array(
'key' => 'method',
'callback' => 'admin_method'
)
)
)
)
);
do_action( '404page_addtional_setting_sections' );
}
/**
* sanitize settings
* was handle_method() in previous versions
* as of version 11.0.0 the method is part of the settings array
*
* @since 11.0.0
* @param array $settings array of settings to save
* @access public
*/
public function sanitize_settings( $settings ) {
if ( ! array_key_exists( 'method', $settings ) || ( $settings['method'] != 'STD' && $settings['method'] != 'CMP' ) ) {
$settings['method'] = 'STD';
}
return $settings;
}
/**
* handle the settings field page id
* moved to PP_404Page_Admin in v 10
*/
function admin_404page() {
echo esc_html__( 'Page to be displayed as 404 page', '404page' );
if ( $this->settings()->get( 'page_id' ) < 0 ) {
echo '
' . esc_html__( 'The page you have selected as 404 page does not exist anymore. Please choose another page.', '404page' ) . '
';
if ( defined( 'WPSEO_VERSION' ) && method_exists( 'WPSEO_Options', 'get' ) && WPSEO_Options::get( 'enable_xml_sitemap' ) ) {
// as of version 11.1.1 we not only check inf Yoast SEO is active but also if Yoast SEO sitemap feature is activated
echo '
';
if ( $this->settings()->get( 'fire_error' ) ) {
echo esc_html__( 'Yoast SEO sitemap detected. Your 404 page is automatically excluded from the XML sitemap created by Yoast.', '404page' );
} else {
echo esc_html__( 'Yoast SEO sitemap detected. Your 404 page is NOT automatically excluded from the XML sitemap created by Yoast, because you disabled the option "Send an 404 error if the page is accessed directly by its URL" on the "Advanced" tab.', '404page' );
}
echo '
';
}
if ( defined( 'JETPACK__VERSION' ) && method_exists( 'Jetpack', 'is_module_active' ) && Jetpack::is_module_active( 'sitemaps' ) ) {
// Jetpack since version 11.1.2
echo '
';
if ( $this->settings()->get( 'fire_error' ) ) {
echo esc_html__( 'Jetpack sitemap detected. Your 404 page is automatically excluded from the XML sitemap created by Jetpack.', '404page' );
} else {
echo esc_html__( 'Jetpack sitemap detected. Your 404 page is NOT automatically excluded from the XML sitemap created by Jetpack, because you disabled the option "Send an 404 error if the page is accessed directly by its URL" on the "Advanced" tab.', '404page' );
}
echo '
';
}
// WP Super Cache
// since 11.2.0
if ( defined('WPCACHEHOME') ) {
global $cache_enabled;
// is caching active?
if ( $cache_enabled ) {
echo '
';
echo esc_html__( 'WP Super Cache detected. All 404 errors are automatically excluded from caching.', '404page' );
echo '
';
}
}
// W3 Total Cache
// since 11.2.1
if ( defined( 'W3TC' ) ) {
if ( class_exists( 'W3TC\Dispatcher' ) ) {
// is caching active?
if ( W3TC\Dispatcher::config()->get_boolean( 'pgcache.enabled' ) ) {
echo '
';
echo esc_html__( 'W3 Total Cache detected. All 404 errors are automatically excluded from caching.', '404page' );
echo '
';
}
}
}
}
/**
* handle the settings field hide
* moved to PP_404Page_Admin in v 10
*/
function admin_hide() {
$this->print_slider_check(
'hide',
esc_html__( 'Hide the selected page from the Pages list', '404page' ),
false,
false,
' ' . esc_html__( 'For Administrators the page is always visible.', '404page' )
);
}
/**
* handle the settings field fire 404 error
* moved to PP_404Page_Admin in v 10
*/
function admin_fire404() {
$this->print_slider_check(
'fire_error',
esc_html__( 'Send an 404 error if the page is accessed directly by its URL', '404page' ),
false,
false,
' ' . esc_html__( 'Uncheck this if you want the selected page to be accessible.', '404page' )
);
}
/**
* handle the settings field to force an 404 error
* moved to PP_404Page_Admin in v 10
*/
function admin_force404() {
$this->print_slider_check(
'force_error',
esc_html__( 'Force 404 error after loading page', '404page' ),
false,
'09OOCbFLfnI',
' ' . esc_html__( 'Generally this is not needed. It is not recommended to activate this option, unless it is necessary. Please note that this may cause problems with your theme.', '404page' )
);
}
/**
* handle the settings field to stop URL guessing
* moved to PP_404Page_Admin in v 10
*/
function admin_noguess() {
$this->print_slider_check(
'no_url_guessing',
esc_html__( 'Disable URL autocorrection guessing', '404page' ),
false,
'H0EdtFcAGl4',
' ' . esc_html__( 'This stops WordPress from URL autocorrection guessing. Only activate, if you are sure about the consequences.', '404page' )
);
}
/**
* handle the settings field to send an http 410 error in case the object is trashed
* @since 3.2
* moved to PP_404Page_Admin in v 10
*/
function admin_http410() {
$this->print_slider_check(
'http410_if_trashed',
esc_html__( 'Send an HTTP 410 error instead of HTTP 404 in case the requested object is in trash', '404page' ),
false,
'O5xPM0BMZxM',
' ' . esc_html__( 'Check this if you want to inform search engines that the resource requested is no longer available and will not be available again so it can be removed from the search index immediately.', '404page' ),
$this->settings()->get( 'http410_always' )
);
}
/**
* handle the settings field to always send an http 410 error
* @since 11.3.0
*/
function admin_http410_always() {
$this->print_slider_check(
'http410_always',
esc_html__( 'Always send an HTTP 410 error instead of HTTP 404', '404page' ),
false,
false,
' ' . esc_html__( 'Check this if you always want to send an HTTP 410 error instead of an HTTP 404 error.', '404page' )
);
}
/**
* handle the settings field method
* moved to PP_404Page_Admin in v 10
*/
function admin_method() {
// unfortunately we can't use print_slider_check() here
if ( $this->core()->is_native() || defined( 'CUSTOMIZR_VER' ) || defined( 'ICL_SITEPRESS_VERSION' ) ) {
$dis = ' disabled="disabled"';
} else {
$dis = '';
}
echo '
settings()->get( 'method' ), false ) . $dis . '/>';
echo '' . esc_html__( 'Activate Compatibility Mode', '404page' ) . ' ';
echo ' ';
if ( $this->core()->is_native() ) {
esc_html_e( 'This setting is not available because the Theme you are using natively supports the 404page plugin.', '404page' );
} elseif ( defined( 'CUSTOMIZR_VER' ) ) {
esc_html_e( 'This setting is not availbe because the 404page Plugin works in Customizr Compatibility Mode.', '404page' );
} elseif ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
esc_html_e( 'This setting is not availbe because the 404page Plugin works in WPML Mode.', '404page' );
} else {
esc_html_e( 'If you are using a theme or plugin that modifies the WordPress Template System, the 404page plugin may not work properly. Compatibility Mode maybe can fix the problem. Activate Compatibility Mode only if you have any problems.', '404page' );
}
echo '
';
}
/**
* create the menu entry
* moved to PP_404Page_Admin in v 10
*/
function action_admin_menu() {
$screen_id = add_theme_page ( esc_html__( '404 Error Page', "404page" ), esc_html__( '404 Error Page', '404page' ), 'manage_options', '404pagesettings', array( $this, 'show_admin' ) );
$this->set_screen_id( $screen_id );
}
/**
* add admin css to header
* moved to PP_404Page_Admin in v 10
*/
function action_admin_head() {
if ( $this->settings()->get( 'page_id' ) > 0 ) {
echo '';
}
}
/**
* add admin css file
* moved to PP_404Page_Admin in v 10
*/
function admin_css() {
if ( get_current_screen()->id == $this->get_screen_id() ) {
wp_enqueue_style( '404pagelity', $this->core()->get_asset_url( 'css', 'lity.min.css' ) );
wp_enqueue_style( '404pagecss', $this->core()->get_asset_url( 'css', '404page-ui.css' ) );
do_action( '404page_enqueue_css' );
}
}
/**
* add admin js files
* moved to PP_404Page_Admin in v 10
*/
function admin_js() {
if ( get_current_screen()->id == $this->get_screen_id() ) {
wp_enqueue_script( '404page-ui', $this->core()->get_asset_url( 'js', '404page-ui.js' ), 'jquery', $this->core()->get_plugin_version(), true );
wp_enqueue_script( '404page-lity', $this->core()->get_asset_url( 'js', 'lity.min.js' ), 'jquery', $this->core()->get_plugin_version(), true );
do_action( '404page_enqueue_js' );
}
}
/**
* show admin page
* moved to PP_404Page_Admin in v 10
*/
function show_admin() {
$this->show( 'manage_options' );
}
/**
* create nonce
*
* @since 10.4
* @access private
* @return string Nonce
*/
private function get_nonce() {
return wp_create_nonce( 'pp_404page_dismiss_admin_notice' );
}
/**
* check nonce
*
* @since 10.4
* @access private
* @return boolean
*/
private function check_nonce() {
return check_ajax_referer( 'pp_404page_dismiss_admin_notice', 'securekey', false );
}
}
}PK y[ou\
class-404page-block-editor.phpnu [ is_gutenberg_editing() ) {
?>
id == 'page' && $this->settings()->get( 'page_id' ) > 0 ) {
// Is the block editor active for pages and is the classic editor not loaded?
if ( function_exists( 'use_block_editor_for_post_type' ) && use_block_editor_for_post_type( 'page' ) && ! isset( $_GET['classic-editor'] ) ) {
global $post;
$all404pages = $this->core()->get_all_page_ids();
// Is the currently edited page a custom 404 error page?
if ( in_array( $post->ID, $all404pages ) ) {
return true;
}
}
}
return false;
}
}
}PK y[ class-404page-classic-editor.phpnu [ id == 'page' && $this->settings()->get( 'page_id' ) > 0 ) {
global $post;
$all404pages = $this->core()->get_all_page_ids();
if ( in_array( $post->ID, $all404pages ) ) {
?>
core()->get_plugin_slug() ) . '_settings';
if ( false === get_option( $newkey ) ) {
if ( false !== get_option( '404page_page_id' ) ) {
$oldkeys = array(
'404page_page_id',
'404page_hide',
'404page_fire_error',
'404page_force_error',
'404page_no_url_guessing',
'404page_http410_if_trashed',
'404page_method'
);
$newvals = array();
foreach ( $oldkeys as $key ) {
$newvals[ str_replace( '404page_', '', $key ) ] = get_option( $key );
delete_option( $key );
}
update_option( $newkey, $newvals );
// delete user meta for old admin notices for all users
foreach ( array( 'pp-404page-admin-notice-1', 'pp-404page-admin-notice-2', 'pp-404page-update-notice-v8', 'pp-404page-update-notice-v9' ) as $key ) {
delete_metadata( 'user', false, $key, false, true );
}
}
}
}
}
}PK y[=j} } class-404page.phpnu [ 0,
'hide' => false,
'fire_error' => true,
'force_error' => false,
'no_url_guessing' => false,
'http410_if_trashed' => false,
'http410_always' => false,
'method' => 'STD'
);
// since 11.0.0 we use add_settings_class() to load the settings
$this->add_settings_class( 'PP_404Page_Settings', 'class-404page-settings', $this, $defaults );
// @since 11.0.0
$this->add_action( 'init' );
}
/**
* do plugin init
* this runs after init action has fired to ensure everything is loaded properly
* was init() before 11.0.0
*/
function action_init() {
// moved from add_text_domain() in v 11.0.0
load_plugin_textdomain( '404page' );
// change old stuff to new stuff for backward compatibility
// since v 11.0.0
$this->deprecated = $this->add_sub_class_always( 'PP_404Page_Deprecated', 'class-404page-deprecated', $this );
// load the following subclasses only on backend
// using add_sub_class_backend() sinde v 11
$this->admin = $this->add_sub_class_backend( 'PP_404Page_Admin', 'class-404page-admin', $this, $this->settings() );
$this->blockeditor = $this->add_sub_class_backend( 'PP_404Page_BlockEditor', 'class-404page-block-editor', $this, $this->settings() );
$this->classiceditor = $this->add_sub_class_backend( 'PP_404Page_ClassicEditor', 'class-404page-classic-editor', $this, $this->settings() );
// as of v 2.2 always call set_mode
// as of v 2.4 we do not need to add an init action hook
if ( !is_admin() && $this->settings()->get( 'page_id' ) > 0 ) {
// as of v 3.0 we once check if there's a 404 page set and not in all functions separately
$this->set_mode();
add_action( 'pre_get_posts', array ( $this, 'exclude_404page' ) );
add_filter( 'get_pages', array ( $this, 'remove_404page_from_array' ), 10, 2 );
// Stop URL guessing if activated
if ( $this->settings()->get( 'no_url_guessing' ) ) {
add_filter( 'redirect_canonical' ,array ( $this, 'no_url_guessing' ) );
}
// Remove 404 error page from XML sitemaps
// only if "Send an 404 error if the page is accessed directly by its URL" is active
if ( $this->settings()->get( 'fire_error' ) ) {
// YOAST sitemap
// @since 6
// we do not need to check if Yoast Sitemap feature is activated because the filter only fires if it is active
add_filter( 'wpseo_exclude_from_sitemap_by_post_ids', function ( $alreadyExcluded ) {
// as of 11.0.5 we add the page ID to the array of already excluded pages
// plus we exclude the 404 page in all languages
return array_merge( $alreadyExcluded, $this->get_all_page_ids() );
}, 999 );
// Jetpack sitemap
// @since 11.1.2
// we do not need to check if Jetpack Sitemap feature is activated because the filter only fires if it is active
add_filter( 'jetpack_sitemap_skip_post', function ( $skip, $post ) {
if ( in_array( intval( $post->ID ), $this->get_all_page_ids() ) ) {
$skip = true;
}
return $skip;
}, 999, 2 );
}
}
if ( class_exists( 'PP_404Page_Admin' ) ) {
// load classes only if in admin
// @since 10
// using class_exists( 'PP_404Page_Admin' ) instead of is_admin() as of v 10.3 for compatibilty with iThemes Sync
//$this->admin = new PP_404Page_Admin( $this, $this->settings );
//$this->blockeditor = new PP_404Page_BlockEditor( $this );
//$this->classiceditor = new PP_404Page_ClassicEditor( $this );
// Remove 404 page from post list if activated
// not moved to PP_404Page_Admin because we also need exclude_404page() in frontend
if ( $this->settings()->get( 'hide' ) and $this->settings()->get( 'page_id' ) > 0 ) {
add_action( 'pre_get_posts' ,array ( $this, 'exclude_404page' ) );
}
}
}
/**
* init filters
*/
function set_mode() {
$this->settings()->set_method();
if ( defined( 'CUSTOMIZR_VER' ) ) {
// Customizr Compatibility Mode
// @since 3.1
add_filter( 'body_class', array( $this, 'add_404_body_class_customizr_mode' ) );
add_filter( 'tc_404_header_content', array( $this, 'show404title_customizr_mode' ), 999 );
add_filter( 'tc_404_content', array( $this, 'show404_customizr_mode' ), 999 );
add_filter( 'tc_404_selectors', array( $this, 'show404articleselectors_customizr_mode' ), 999 );
// send http 410 instead of http 404 if requested resource is in trash
// @since 3.2
// or always send http 410
// @since 11.3.0
if ( $this->settings()->get( 'http410_if_trashed' ) || $this->settings()->get( 'http410_always' ) ) {
add_action( 'template_redirect', array( $this, 'maybe_send_410' ) );
}
} elseif ( $this->settings()->get( 'method' ) != 'STD' ) {
// Compatibility Mode
// 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
// as of v 11.4.3 we also pass the query
add_filter( 'the_posts', array( $this, 'show404_compatiblity_mode' ), 999, 2 );
// as of v 2.5 we remove the filter if the DW Question & Answer plugin by DesignWall (https://www.designwall.com/wordpress/plugins/dw-question-answer/) is active and we're in the answers list
add_filter( 'dwqa_prepare_answers', array( $this, 'remove_show404_compatiblity_mode' ), 999 );
} else {
// Standard Mode
add_filter( '404_template', array( $this, 'show404_standard_mode' ), 999 );
if ( $this->settings()->get( 'fire_error' ) ) {
add_action( 'template_redirect', array( $this, 'do_404_header_standard_mode' ) );
}
// send http 410 instead of http 404 if requested resource is in trash
// @since 3.2
// or always send http 410
// @since 11.3.0
if ( $this->settings()->get( 'http410_if_trashed' ) || $this->settings()->get( 'http410_always' ) ) {
add_action( 'template_redirect', array( $this, 'maybe_send_410' ) );
}
}
}
/**
* show 404 page
* Standard Mode
*/
function show404_standard_mode( $template ) {
global $wp_query;
// @since 4
// fix for an ugly bbPress problem
// see https://wordpress.org/support/topic/not-fully-bbpress-compatible/
// see https://bbpress.trac.wordpress.org/ticket/3161
// if a bbPress member page is shown and the member has no topics created yet the 404_template filter hook fires
// this is a bbPress problem but it has not been fixed since 6 months
// so let's bypass the problem
if ( function_exists( 'bbp_is_single_user' ) ) {
if ( bbp_is_single_user() ) {
return $template;
}
}
// that's it
// save URL that caused the 404 - since 11.4.0
$this->set_404_url();
if ( ! $this->is_native() ) {
$this->disable_caching();
$wp_query = null;
$wp_query = new WP_Query();
$wp_query->query( 'page_id=' . $this->get_page_id() );
$wp_query->the_post();
$template = get_page_template();
rewind_posts();
add_filter( 'body_class', array( $this, 'add_404_body_class' ) );
}
$this->maybe_force_404();
$this->do_404page_action();
return $template;
}
/**
* show 404 page
* Compatibility Mode
*/
function show404_compatiblity_mode( $posts, $query ) {
global $wp_query;
// remove the filter so we handle only the first query - no custom queries
// moved in 11.4.3 due to problems with WP 6.1
// remove_filter( 'the_posts', array( $this, 'show404_compatiblity_mode' ), 999 );
// @since 4
// fix for an ugly bbPress problem
// see show404_standard_mode()
if ( function_exists( 'bbp_is_single_user' ) ) {
if ( bbp_is_single_user() ) {
return $posts;
}
}
// that's it
$pageid = $this->get_page_id();
if ( ! $this->is_native() ) {
// as of v 10 we also check if $wp_query->query[error] == 404
// this is necessary to bypass a WordPress bug
// if permalink setting is something like e.g. /blog/%postname%/ the $posts is not empty
// bug reported https://core.trac.wordpress.org/ticket/46000
// as of v 11.0.3 we also check for REST_REQUEST to not create a 404 page in case of REST API call
// as of v 11.2.4 we also check for DOING_CRON
// is_main_query() is true in multiple cases
// as of v 11.4.3 we check the query against the main query
if ( ( empty( $posts ) || ( isset( $wp_query->query['error'] ) && $wp_query->query['error'] == 404 ) ) && $wp_query == $query && is_main_query() && !is_robots() && !is_home() && !is_feed() && !is_search() && !is_archive() && ( !defined('DOING_AJAX') || !DOING_AJAX ) && ( !defined('DOING_CRON') || !DOING_CRON ) && ( !defined('REST_REQUEST') || !REST_REQUEST ) ) {
// save URL that caused the 404 - since 11.4.0
$this->set_404_url();
// 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
$this->postid = $pageid;
// as of v 2.4 we use the the_posts filter instead of posts_results
// therefore we have to reset $wp_query
// resetting $wp_query also forces us to remove the pre_get_posts action plus the get_pages filter
remove_action( 'pre_get_posts', array ( $this, 'exclude_404page' ) );
remove_filter( 'get_pages', array ( $this, 'remove_404page_from_array' ), 10, 2 );
// moved here in 11.4.3
remove_filter( 'the_posts', array( $this, 'show404_compatiblity_mode' ), 999 );
$this->disable_caching();
$wp_query = null;
$wp_query = new WP_Query();
// @since 8
// added suppress_filters for compatibilty with current WPML version
$wp_query->query( array( 'page_id' => $pageid, 'suppress_filters' => true ) );
$wp_query->the_post();
$this->template = get_page_template();
$posts = $wp_query->posts;
$wp_query->rewind_posts();
add_action( 'wp', array( $this, 'do_404_header' ) );
add_filter( 'body_class', array( $this, 'add_404_body_class' ) );
add_filter( 'template_include', array( $this, 'change_404_template' ), 999 );
$this->maybe_force_404();
$this->do_404page_action();
} elseif ( 1 == count( $posts ) && 'page' == $posts[0]->post_type ) {
// Do a 404 if the 404 page is opened directly
if ( $this->settings()->get( 'fire_error' ) ) {
// save URL that caused the 404 - since 11.4.0
$this->set_404_url();
$curpageid = $posts[0]->ID;
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
// WPML is active - get the post ID of the default language
global $sitepress;
$curpageid = apply_filters( 'wpml_object_id', $curpageid, 'page', $sitepress->get_default_language() );
$pageid = apply_filters( 'wpml_object_id', $pageid, 'page', $sitepress->get_default_language() );
} elseif ( function_exists( 'pll_get_post' ) ) {
// was defined( 'POLYLANG_VERSION' ) before version 11.2.3
// Polylang is active - get the post ID of the default language
$curpageid = pll_get_post( $curpageid, pll_default_language() );
$pageid = pll_get_post( $pageid, pll_default_language() );
}
if ( $pageid == $curpageid ) {
add_action( 'wp', array( $this, 'do_404_header' ) );
add_filter( 'body_class', array( $this, 'add_404_body_class' ) );
$this->maybe_force_404();
$this->do_404page_action();
}
}
}
} else {
$this->maybe_force_404();
$this->do_404page_action();
}
return $posts;
}
/**
* disable caching for known caching plugins
*
* @since 11.2.0
*/
function disable_caching() {
// WP Super Cache
if ( defined( 'WPCACHEHOME' ) ) {
global $cache_enabled;
// is caching active?
if ( $cache_enabled ) {
define( 'DONOTCACHEPAGE', true );
}
}
// W3 Total Cache
if ( defined( 'W3TC' ) ) {
if ( class_exists( 'W3TC\Dispatcher' ) ) {
// is caching active?
if ( W3TC\Dispatcher::config()->get_boolean( 'pgcache.enabled' ) ) {
define( 'DONOTCACHEPAGE', true );
}
}
}
}
/**
* for DW Question & Answer plugin
* this function is called by the dwqa_prepare_answers filter
*/
function remove_show404_compatiblity_mode( $args ) {
remove_filter( 'the_posts', array( $this, 'show404_compatiblity_mode' ), 999 );
return $args;
}
/**
* this function overrides the page template in compatibilty mode
*/
function change_404_template( $template ) {
// 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
$new_template = locate_template( array( $this->template ) );
if ( '' != $new_template ) {
return $new_template ;
}
return $template;
}
/**
* send 404 HTTP header
* Standard Mode
*/
function do_404_header_standard_mode() {
if ( is_page() && get_the_ID() == $this->settings()->get( 'page_id' ) && !is_404() ) {
// save URL that caused the 404 - since 11.4.0
$this->set_404_url();
status_header( 404 );
nocache_headers();
$this->maybe_force_404();
// Add 404 body class - since 11.4.2
add_filter( 'body_class', array( $this, 'add_404_body_class' ) );
$this->do_404page_action();
}
}
/**
* send 404 HTTP header
* Compatibility Mode
*/
function do_404_header() {
// remove the action so we handle only the first query - no custom queries
remove_action( 'wp', array( $this, 'do_404_header' ) );
// send http 410 instead of http 404 if requested resource is in trash
// @since 3.2
if ( $this->settings()->get( 'http410_if_trashed' ) && $this->is_url_in_trash( $this->get_404_url() ) ) {
status_header( 410 );
} else {
status_header( 404 );
}
nocache_headers();
}
/**
* add body classes
*/
function add_404_body_class( $classes ) {
// as of v 3.1 we first check if the class error404 already exists
if ( ! in_array( 'error404', $classes ) ) {
$classes[] = 'error404';
}
// debug class
// @since 3.1
$debug_class = 'pp404-';
if ( $this->is_native() ) {
$debug_class .= 'native';
} elseif ( defined( 'CUSTOMIZR_VER' ) ) {
$debug_class .= 'customizr';
} elseif ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
$debug_class .= 'wpml';
} elseif ( $this->settings()->get( 'method' ) != 'STD' ) {
$debug_class .= 'cmp';
} else {
$debug_class .= 'std';
}
$classes[] = $debug_class;
return $classes;
}
/**
* add body classes customizr mode
* @since 3.1
*/
function add_404_body_class_customizr_mode( $classes ) {
if ( is_404() ) {
// save URL that caused the 404 - since 11.4.0
$this->set_404_url();
$classes = $this->add_404_body_class( $classes );
}
return $classes;
}
/**
* show title
* Customizr Compatibility Mode
*/
function show404title_customizr_mode( $title ) {
if ( ! $this->is_native() ) {
return '
' . get_the_title( $this->get_page_id() ) . '
';
} else {
return $title;
}
}
/**
* show content
* Customizr Compatibility Mode
*/
function show404_customizr_mode( $content ) {
if ( ! $this->is_native() ) {
return '
';
} else {
return $content;
}
$this->do_404page_action();
}
/**
* change article selectors
* Customizr Compatibility Mode
*/
function show404articleselectors_customizr_mode( $selectors ) {
if ( ! $this->is_native() ) {
return 'id="post-' . $this->get_page_id() . '" class="' . join( ' ', get_post_class( 'row-fluid', $this->get_page_id() ) ) . '"';
} else {
return $selectors;
}
}
/**
* do we have to force a 404 in wp_head?
*/
function maybe_force_404() {
if ( $this->settings()->get( 'force_error' ) ) {
add_action( 'wp_head', array( $this, 'force_404_start' ), 9.9 );
add_action( 'wp_head', array( $this, 'force_404_end' ), 99 );
}
}
/**
* Force 404 in wp_head start
* potentially dangerous!
*/
function force_404_start() {
global $wp_query;
$wp_query->is_404 = true;
}
/**
* Force 404 in wp_head end
* potentially dangerous!
*/
function force_404_end() {
global $wp_query;
$wp_query->is_404 = false;
}
/**
* disable URL autocorrect guessing
*/
function no_url_guessing( $redirect_url ) {
if ( is_404() && !isset($_GET['p']) ) {
$redirect_url = false;
}
return $redirect_url;
}
/**
* send http 410 instead of http 404 in case the requested URL can be found in trash
* @since 3.2
* or always send http 410
* @since 11.3.0
*/
function maybe_send_410() {
// we don't do anything if there is no 404
if ( is_404() ) {
if ( $this->settings()->get( 'http410_always' ) || ( $this->settings()->get( 'http410_if_trashed' ) && $this->is_url_in_trash( $this->get_404_url() ) ) ) {
status_header( 410 );
}
}
}
/**
* hide the 404 page from the list of pages
*/
function exclude_404page( $query ) {
$pageid = $this->get_page_id();
if ( $pageid > 0 ) {
global $pagenow;
$post_type = $query->get( 'post_type' );
// as of v 2.3 we check the post_type on front end
// as of v 2.5 we also hide the page from search results on front end
if( ( is_admin() && ( 'edit.php' == $pagenow && !current_user_can( 'create_users' ) ) ) || ( ! is_admin() && ( is_search() || ( !empty( $post_type) && ( ('page' === $post_type || 'any' === $post_type) || ( is_array( $post_type ) && in_array( 'page', $post_type ) ) ) ) ) ) ) {
// as of v 2.4 we hide all translations in admin for WPML
// as of v 2.5 we hide all translations from search results on front end for WPML
if ( is_admin() || ( ! is_admin() && is_search() ) ) {
$pageids = $this->get_all_page_ids();
} else {
$pageids = array( $pageid );
}
// as of v 2.3 we add the ID of the 404 page to post__not_in
// using just $query->set() overrides existing settings but not adds a new setting
$query->set( 'post__not_in', array_merge( (array)$query->get( 'post__not_in', array() ), $pageids ) );
}
}
}
/**
* remove the 404 page from get_pages result array
*/
function remove_404page_from_array( $pages, $r ) {
$pageid = $this->get_page_id();
if ( $pageid > 0 ) {
for ( $i = 0; $i < sizeof( $pages ); $i++ ) {
if ( $pages[$i]->ID == $pageid ) {
unset( $pages[$i] );
break;
}
}
}
return array_values( $pages );
}
/**
* check if the requested url is found in trash
* @since 3.2
* based on WP core function url_to_postid()
*/
function is_url_in_trash( $url ) {
global $wp_rewrite;
global $wp;
// First, check to see if there is a 'p=N' or 'page_id=N' to match against
if ( preg_match( '#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values ) ) {
$id = absint( $values[2] );
if ( $id ) {
if ( 'trash' == get_post_status( $id ) ) {
return true;
} else {
return false;
}
}
}
// Check to see if we are using rewrite rules
$rewrite = $wp_rewrite->wp_rewrite_rules();
// Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
if ( empty( $rewrite ) ) {
return false;
}
// Get rid of the #anchor
$url_split = explode('#', $url);
$url = $url_split[0];
// Get rid of URL ?query=string
$url_split = explode('?', $url);
$url = $url_split[0];
// Add 'www.' if it is absent and should be there
if ( false !== strpos( home_url(), '://www.' ) && false === strpos( $url, '://www.' ) ) {
$url = str_replace('://', '://www.', $url);
}
// Strip 'www.' if it is present and shouldn't be
if ( false === strpos( home_url(), '://www.' ) ) {
$url = str_replace('://www.', '://', $url);
}
// Strip 'index.php/' if we're not using path info permalinks
if ( !$wp_rewrite->using_index_permalinks() ) {
$url = str_replace( $wp_rewrite->index . '/', '', $url );
}
if ( false !== strpos( trailingslashit( $url ), home_url( '/' ) ) ) {
// Chop off http://domain.com/[path]
$url = str_replace(home_url(), '', $url);
} else {
// Chop off /path/to/blog
$home_path = parse_url( home_url( '/' ) );
$home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
$url = preg_replace( sprintf( '#^%s#', preg_quote( $home_path ) ), '', trailingslashit( $url ) );
}
// Trim leading and lagging slashes
$url = trim($url, '/');
$request = $url;
$post_type_query_vars = array();
foreach ( get_post_types( array() , 'objects' ) as $post_type => $t ) {
if ( ! empty( $t->query_var ) ) {
$post_type_query_vars[ $t->query_var ] = $post_type;
}
}
// Look for matches.
$request_match = $request;
foreach ( (array)$rewrite as $match => $query) {
// If the requesting file is the anchor of the match, prepend it
// to the path info.
if ( !empty( $url ) && ( $url != $request ) && ( strpos( $match, $url ) === 0 ) ) {
$request_match = $url . '/' . $request;
}
if ( preg_match( "#^$match#", $request_match, $matches ) ) {
if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
// This is a verbose page match, let's check to be sure about it.
if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) ) {
continue;
}
}
// Got a match.
// Trim the query of everything up to the '?'.
$query = preg_replace( "!^.+\?!", '', $query );
// Substitute the substring matches into the query.
$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
// Filter out non-public query vars
parse_str( $query, $query_vars );
$query = array();
foreach ( (array) $query_vars as $key => $value ) {
if ( in_array( $key, $wp->public_query_vars ) ) {
$query[$key] = $value;
if ( isset( $post_type_query_vars[$key] ) ) {
$query['post_type'] = $post_type_query_vars[$key];
$query['name'] = $value;
}
}
}
// Magic
if ( isset( $query['pagename'] ) ) {
$query['pagename'] .= '__trashed' ;
}
if ( isset( $query['name'] ) ) {
$query['name'] .= '__trashed' ;
}
$query['post_status'] = array( 'trash' );
// Resolve conflicts between posts with numeric slugs and date archive queries.
$query = wp_resolve_numeric_slug_conflicts( $query );
// Do the query
$query = new WP_Query( $query );
if ( $query->found_posts == 1 ) {
return true;
} else {
return false;
}
}
}
return false;
}
/**
* get the id of the 404 page in the current language if WPML or Polylang is active
* public since v 11.1.0 to use it in pp_404_get_page_id()
*/
public function get_page_id() {
$pageid = $this->settings()->get( 'page_id' );
if ( $pageid > 0 ) {
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
// WPML is active
$pageid = apply_filters( 'wpml_object_id', $pageid, 'page', true );
} elseif ( function_exists( 'pll_get_post' ) ) {
// was defined( 'POLYLANG_VERSION' ) before version 11.2.3
// Polylang is active
$translatedpageid = pll_get_post( $pageid );
if ( !empty( $translatedpageid ) && 'publish' == get_post_status( $translatedpageid ) ) {
$pageid = $translatedpageid;
}
}
}
return $pageid;
}
/**
* get 404 pages in all available languages
* if WPML is active this function returns an array of all page ids in all available languages
* otherwise it returns the page id as array
* introduced in v 2.4
* public since v9 to access it from other classes
*/
public function get_all_page_ids() {
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
// WPML is active
// get an array for all translations
$pageid = $this->settings()->get( 'page_id' );
$pages = array( $pageid );
if ( $pageid > 0 ) {
$languages = apply_filters( 'wpml_active_languages', NULL );
if ( !empty( $languages ) ) {
foreach( $languages as $l ) {
$p = apply_filters( 'wpml_object_id', $pageid, 'page', false, $l['language_code'] );
if ( $p ) {
$pages[] = $p;
}
}
}
}
$pageids = array_unique( $pages, SORT_NUMERIC );
} else {
$pageids = array( $this->settings()->get( 'page_id' ) );
}
return $pageids;
}
/**
* fire 404page_after_404 hook to make plugin expandable
*/
function do_404page_action() {
do_action( '404page_after_404' );
}
/**
* uninstall plugin
*/
function uninstall() {
if( is_multisite() ) {
$this->uninstall_network();
} else {
$this->uninstall_single();
}
}
/**
* uninstall network wide
*/
function uninstall_network() {
global $wpdb;
$activeblog = $wpdb->blogid;
$blogids = $wpdb->get_col( esc_sql( 'SELECT blog_id FROM ' . $wpdb->blogs ) );
foreach ( $blogids as $blogid ) {
switch_to_blog( $blogid );
$this->uninstall_single();
}
switch_to_blog( $activeblog );
}
/**
* uninstall for a single blog
*/
function uninstall_single() {
$this->data_remove();
$this->settings()->remove();
}
/**
* functions for theme usage
*/
// check if there's a custom 404 page set
function pp_404_is_active() {
return ( $this->settings()->get( 'page_id' ) > 0 );
}
// activate the native theme support
function pp_404_set_native_support() {
$this->set_native();
}
// get the title - native theme support
function pp_404_get_the_title() {
$title = '';
if ( $this->settings()->get( 'page_id' ) > 0 && $this->is_native() ) {
$title = get_the_title( $this->get_page_id() );
}
return $title;
}
// print title - native theme support
function pp_404_the_title() {
echo esc_html( $this->pp_404_get_the_title() );
}
// get the content - native theme support
function pp_404_get_the_content() {
$content = '';
if ( $this->settings()->get( 'page_id' ) > 0 && $this->is_native() ) {
$content = apply_filters( 'the_content', get_post_field( 'post_content', $this->get_page_id() ) );
}
return $content;
}
// print content - native theme support
function pp_404_the_content() {
echo esc_html( $this->pp_404_get_the_content() );
}
/**
* set native mode
*
* @since 11.0.0 - was part of previous settings class
* @access public
*/
public function set_native() {
$this->native = true;
}
/**
* is native mode ative
*
* @since 11.0.0 - was part of previous settings class
* @access public
*/
public function is_native() {
return ( true === $this->native );
}
/**
* get settings class
*
* @since 11.3.0
* @access public
* @return object
*/
public function admin() {
return $this->admin;
}
/**
* save URL that caused the 404 error
*
* @since 11.4.0
* @access private
*/
private function set_404_url() {
$url = rawurldecode( ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
$this->error_url = parse_url( $url );
$this->error_url['full'] = $url;
return true;
}
/**
* get URL that caused the 404 error
*
* @since 11.4.0
* @access public
* @param string $what - array index to get
* @return string
*/
public function get_404_url( $what = 'full' ) {
if ( $this->error_url && is_array( $this->error_url ) && isset( $this->error_url[$what] ) && ! empty( $this->error_url[$what] ) ) {
return $this->error_url[$what];
}
}
}
}PK y[ˈE E class-404page-settings.phpnu [ get( 'page_id' ) != 0 ) {
$page = get_post( $this->get( 'page_id' ) );
if ( !$page || $page->post_status != 'publish' ) {
$this->set( 'page_id', -1 );
}
}
}
/**
* set the method
*
* @since 7
* @access public
*/
public function set_method() {
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
// WPML is active
$this->set('method', 'CMP' );
} else {
// we dont' need to set this here, because this is set in load()
}
}
}
}PK y[* index.phpnu [