Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Skip404
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 11
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 handle_actions_on_plugins_loaded
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 is_active
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 get_value
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 on_update_htaccess
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 maybe_add_rules
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 add_rules
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 remove_rules
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 on_activation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 on_deactivation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 add_to_runtime
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace NewfoldLabs\WP\Module\Performance\Skip404;
4
5use NewfoldLabs\WP\ModuleLoader\Container;
6use NewfoldLabs\WP\Module\Performance\OptionListener;
7
8use function WP_Forge\WP_Htaccess_Manager\addContent;
9use function WP_Forge\WP_Htaccess_Manager\removeMarkers;
10
11/**
12 * Handles Skip 404 functionality.
13 */
14class Skip404 {
15
16    /**
17     * Dependency injection container.
18     *
19     * @var Container
20     */
21    protected $container;
22
23    /**
24     * Option name for skip 404 setting.
25     *
26     * @var string
27     */
28    const OPTION_NAME = 'newfold_skip_404_handling';
29
30    /**
31     * The file marker name.
32     */
33    const MARKER = 'Newfold Skip 404 Handling for Static Files';
34
35
36    /**
37     * Constructor.
38     *
39     * @param Container $container The dependency injection container.
40     */
41    public function __construct( Container $container ) {
42        $this->container = $container;
43
44        new OptionListener( self::OPTION_NAME, array( __CLASS__, 'maybe_add_rules' ) );
45
46        add_filter( 'newfold_update_htaccess', array( $this, 'on_update_htaccess' ) );
47
48        add_action( 'newfold_container_set', array( $this, 'handle_actions_newfold_container_set' ) );
49        add_action( 'plugins_loaded', array( $this, 'handle_actions_on_plugins_loaded' ) );
50
51        add_filter( 'newfold-runtime', array( $this, 'add_to_runtime' ), 100 );
52
53        register_activation_hook( $container->plugin()->file, array( $this, 'on_activation' ) );
54        register_deactivation_hook( $container->plugin()->file, array( $this, 'on_deactivation' ) );
55    }
56
57
58    /**
59     * Perform actions on enabling/disabling Performance feature
60     *
61     * @return void
62     */
63    public function handle_actions_on_plugins_loaded() {
64        add_action( 'newfold/features/action/onEnable:performance', array( $this, 'on_activation' ) );
65        add_action( 'newfold/features/action/onDisable:performance', array( $this, 'on_deactivation' ) );
66    }
67
68    /**
69     * Detect if the feature needs to be performed or not
70     *
71     * @param Container $container Dependency injection container.
72     *
73     * @return bool
74     */
75    public static function is_active( Container $container ) {
76        return (bool) $container->has( 'isApache' ) && $container->get( 'isApache' );
77    }
78
79    /**
80     * Get value for SKIP404 option
81     *
82     * @return bool
83     */
84    public static function get_value() {
85        return (bool) get_option( self::OPTION_NAME, true );
86    }
87
88    /**
89     * When updating .htaccess, also update our rules as appropriate.
90     */
91    public function on_update_htaccess() {
92        self::maybe_add_rules( self::get_value() );
93
94        // Remove the old option from EPC, if it exists
95        if ( $this->container->get( 'hasMustUsePlugin' ) && absint( get_option( 'epc_skip_404_handling', 0 ) ) ) {
96            update_option( 'epc_skip_404_handling', 0 );
97            delete_option( 'epc_skip_404_handling' );
98        }
99    }
100
101    /**
102     * Conditionally add or remove .htaccess rules based on option value.
103     *
104     * @param bool|null $shouldSkip404Handling if should skip 404 handling.
105     */
106    public static function maybe_add_rules( $shouldSkip404Handling ) {
107        (bool) $shouldSkip404Handling ? self::add_rules() : self::remove_rules();
108    }
109
110    /**
111     * Add our rules to the .htacces file.
112     */
113    public static function add_rules() {
114        $content = <<<HTACCESS
115            <IfModule mod_rewrite.c>
116                RewriteEngine On
117                RewriteCond %{REQUEST_FILENAME} !-f
118                RewriteCond %{REQUEST_FILENAME} !-d
119                RewriteCond %{REQUEST_URI} !(robots\.txt|ads\.txt|[a-z0-9_\-]*sitemap[a-z0-9_\.\-]*\.(xml|xsl|html)(\.gz)?)
120                RewriteCond %{REQUEST_URI} \.(css|htc|less|js|js2|js3|js4|html|htm|rtf|rtx|txt|xsd|xsl|xml|asf|asx|wax|wmv|wmx|avi|avif|avifs|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|webp|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|webm|mpp|otf|_otf|odb|odc|odf|odg|odp|ods|odt|ogg|ogv|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|_ttf|wav|wma|wri|woff|woff2|xla|xls|xlsx|xlt|xlw|zip)$ [NC]
121                RewriteRule .* - [L]
122            </IfModule>
123            HTACCESS; // phpcs:ignore Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsedHeredocCloser
124
125        addContent( self::MARKER, $content );
126    }
127
128    /**
129     * Remove our rules from the .htaccess file.
130     */
131    public static function remove_rules() {
132        removeMarkers( self::MARKER );
133    }
134
135    /**
136     * Handle activation logic.
137     */
138    public static function on_activation() {
139        self::maybe_add_rules( self::get_value() );
140    }
141
142    /**
143     * Handle deactivation logic.
144     */
145    public static function on_deactivation() {
146        self::remove_rules();
147    }
148
149    /**
150     * Add to Newfold SDK runtime.
151     *
152     * @param array $sdk SDK data.
153     * @return array SDK data.
154     */
155    public function add_to_runtime( $sdk ) {
156        $values = array(
157            'is_active' => $this->get_value(),
158        );
159
160        return array_merge( $sdk, array( 'skip404' => $values ) );
161    }
162}