Passed
Push — master ( 553534...d77e2c )
by Dominik
06:58 queued 03:32
created

storeResizedUrls()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 19
nc 2
nop 0
dl 0
loc 24
rs 9.6333
c 0
b 0
f 0
1
<?php
2
3
namespace Flynt\TimberDynamicResize;
4
5
use Twig\TwigFilter;
6
use Timber;
7
use Routes;
8
9
const DB_VERSION = '1.1';
10
const TABLE_NAME = 'resized_images';
11
const IMAGE_ROUTE = 'dynamic-images';
12
const IMAGE_PATH_SEPARATOR = 'dynamic';
13
14
function getTableName()
15
{
16
    global $wpdb;
17
    return $wpdb->prefix . TABLE_NAME;
18
}
19
20
call_user_func(function () {
21
    $optionName = TABLE_NAME . '_db_version';
22
23
    $installedVersion = get_option($optionName);
24
25
    if ($installedVersion !== DB_VERSION) {
26
        global $wpdb;
27
        $tableName = getTableName();
28
29
        $charsetCollate = $wpdb->get_charset_collate();
30
31
        $sql = "CREATE TABLE $tableName (
32
            url varchar(511),
33
            arguments text
34
        ) $charsetCollate;";
35
36
        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
37
        dbDelta($sql);
38
39
        update_option($optionName, DB_VERSION);
40
    }
41
});
42
43
function getRelativeUploadDir()
44
{
45
    $uploadDir = wp_upload_dir();
46
    return $uploadDir['relative'];
47
}
48
49
add_action('timber/twig/filters', function ($twig) {
50
    $twig->addFilter(
51
        new TwigFilter('resizeDynamic', function (
52
            $src,
53
            $w,
54
            $h = 0,
55
            $crop = 'default',
56
            $force = false
57
        ) {
58
            $resizeOp = new Timber\Image\Operation\Resize($w, $h, $crop);
59
            $fileinfo = pathinfo($src);
60
            $resizedUrl = $resizeOp->filename(
61
                $fileinfo['dirname'] . '/' . $fileinfo['filename'],
62
                $fileinfo['extension']
63
            );
64
65
            $arguments = [
66
                'src' => $src,
67
                'w' => $w,
68
                'h' => $h,
69
                'crop' => $crop,
70
                'force' => $force
71
            ];
72
73
            global $flyntResizedImages;
74
            if (empty($flyntResizedImages)) {
75
                add_action('shutdown', function () {
76
                    storeResizedUrls();
77
                }, -1);
78
            }
79
            $flyntResizedImages[$resizedUrl] = json_encode($arguments);
80
81
            $uploadDirRelative = getRelativeUploadDir();
82
83
            return str_replace(
84
                $uploadDirRelative,
85
                trailingslashit($uploadDirRelative) . IMAGE_PATH_SEPARATOR,
86
                $resizedUrl
87
            );
88
        })
89
    );
90
91
    return $twig;
92
});
93
94
Routes::map(IMAGE_ROUTE, function () {
95
    $uploadDirRelative = getRelativeUploadDir();
96
    $src = str_replace(
97
        trailingslashit($uploadDirRelative) . IMAGE_PATH_SEPARATOR,
98
        $uploadDirRelative,
99
        home_url($_GET['src'] ?? '')
100
    );
101
102
    global $wpdb;
103
    $tableName = getTableName();
104
    $resizedImage = $wpdb->get_row(
105
        $wpdb->prepare("SELECT * FROM {$tableName} WHERE url = %s", $src)
106
    );
107
108
    if (empty($resizedImage)) {
109
        header("HTTP/1.0 404 Not Found");
110
        exit();
111
    }
112
    $urlParts = wp_parse_url($src);
113
    $homeUrl = home_url();
114
    $localDev = parse_url($homeUrl)['host'] !== $urlParts['host'];
115
    if ($localDev) {
116
        $src = http_build_url($homeUrl, ['path' => $urlParts['path']]);
0 ignored issues
show
Unused Code introduced by
The assignment to $src is dead and can be removed.
Loading history...
117
    }
118
    $moveImageFunction = function ($location) use ($uploadDirRelative) {
119
        return str_replace(
120
            $uploadDirRelative,
121
            trailingslashit($uploadDirRelative) . IMAGE_PATH_SEPARATOR,
122
            $location
123
        );
124
    };
125
    add_filter('timber/image/new_url', $moveImageFunction);
126
    add_filter('timber/image/new_path', $moveImageFunction);
127
    $arguments = json_decode($resizedImage->arguments, true);
128
    $url = Timber\ImageHelper::resize(
129
        $arguments['src'],
130
        (int) $arguments['w'],
131
        (int) $arguments['h'],
132
        $arguments['crop'],
133
        false
134
    );
135
136
    remove_filter('timber/image/new_url', $moveImageFunction);
137
    remove_filter('timber/image/new_path', $moveImageFunction);
138
139
    Timber\ImageHelper::img_to_webp($url);
140
141
    if ($localDev) {
142
        unset($urlParts['path']);
143
        $url = http_build_url($url, $urlParts);
144
    }
145
    header("Location: {$url}", true, 301);
146
    exit();
147
});
148
149
function addRewriteRule($rules)
150
{
151
    $imageRoute = IMAGE_ROUTE;
152
    $uploadDirRelative = trailingslashit(getRelativeUploadDir());
153
    $dynamicImageDir = trailingslashit($uploadDirRelative . IMAGE_PATH_SEPARATOR);
154
    $dynamicImageRule = <<<EOD
155
\n# BEGIN Flynt dynamic images
156
RewriteEngine On
157
RewriteCond %{REQUEST_URI} ^{$dynamicImageDir}
158
RewriteCond %{REQUEST_FILENAME} !-f
159
RewriteCond %{REQUEST_FILENAME} !-d
160
RewriteRule ^(.*)$ /{$imageRoute}?src=$1 [L,R]
161
162
<IfModule mod_setenvif.c>
163
# Vary: Accept for all the requests to jpeg and png
164
SetEnvIf Request_URI "\.(jpe?g|png)$" REQUEST_image
165
</IfModule>
166
167
<IfModule mod_rewrite.c>
168
RewriteEngine On
169
170
# Check if browser supports WebP images
171
RewriteCond %{HTTP_ACCEPT} image/webp
172
173
# Check if WebP replacement image exists
174
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
175
176
# Serve WebP image instead
177
RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp]
178
</IfModule>
179
180
<IfModule mod_headers.c>
181
Header append Vary Accept env=REQUEST_image
182
</IfModule>
183
184
<IfModule mod_mime.c>
185
AddType image/webp .webp
186
</IfModule>
187
# END Flynt dynamic images\n\n
188
EOD;
189
    return $dynamicImageRule . $rules;
190
}
191
192
add_filter('mod_rewrite_rules', 'Flynt\\TimberDynamicResize\\addRewriteRule');
193
194
add_action('after_switch_theme', function () {
195
    add_action('shutdown', 'flush_rewrite_rules');
196
});
197
198
add_action('switch_theme', function () {
199
    remove_filter('mod_rewrite_rules', 'Flynt\\TimberDynamicResize\\addRewriteRule');
200
    flush_rewrite_rules();
201
});
202
203
global $flyntResizedImages;
204
$flyntResizedImages = [];
205
206
function storeResizedUrls()
207
{
208
    global $wpdb, $flyntResizedImages;
209
    $tableName = getTableName();
210
    $urls = array_keys($flyntResizedImages);
211
    $deletePlaceholders = array_fill(0, count($urls), '%s');
212
    $deletePlaceholdersString = '(' . implode(', ', $deletePlaceholders) . ')';
213
    $wpdb->query(
214
        $wpdb->prepare(
215
            "DELETE FROM {$tableName} WHERE url IN {$deletePlaceholdersString}",
216
            $urls
217
        )
218
    );
219
    $insertPlaceholders = array_fill(0, count($urls), '(%s, %s)');
220
    $insertPlaceholdersString = implode(', ', $insertPlaceholders);
221
    $insertValues = [];
222
    foreach ($urls as $url) {
223
        $insertValues[] = $url;
224
        $insertValues[] = $flyntResizedImages[$url];
225
    }
226
    $wpdb->query(
227
        $wpdb->prepare(
228
            "INSERT INTO {$tableName} (url, arguments) VALUES {$insertPlaceholdersString}",
229
            $insertValues
230
        )
231
    );
232
}
233