@media (min-width:20em) { /* iPhones, Androids portrait 480x320 phones */ }
@media (min-width:30em) { /* e-readers (Nook/Kindle), mini tablets 600x600 */ }
@media (min-width:40em) { /* medium tablets, iPads, and e-readers, landscape 800x480 */ }
@media (min-width:60em) { /* standard tablets, landscape iPads, lo-resolution laptops ands desktops */ }
@media (min-width:64em) { /* larger tablets, standard laptops, and 24" monitors */ }
@media (min-width:80em) { /* High resolution laptops and desktops */ }
Category: Web Development
How To Upgrade NextCloud 22.1.1 to 22.2.0 When Deployed with Kubernetes & Helm
Step 1:
Navigate to nextcloud > html > edit version.php
<?php
$OC_Version = array(22,1,1,2);
$OC_VersionString = '22.1.1';
$OC_Edition = '';
$OC_Channel = 'stable';
$OC_VersionCanBeUpgradedFrom = array (
'nextcloud' =>
array (
'21.0' => true,
'22.0' => true,
'22.1' => true,
'22.2' => true, # Add this line
),
'owncloud' =>
array (
'10.5' => true,
),
);
$OC_Build = '2021-08-26T13:27:46+00:00 1eea64f2c3eb0e110391c24830cea5f8d9c3e6a1';
$vendor = 'nextcloud';
Step 2: Run the ‘helm upgrade…’ command with the desired NextCloud version
# Example:
helm upgrade nextcloud nextcloud/nextcloud \
--set image.tag=22.2.0-fpm \
--set nginx.enabled=true \
--set nextcloud.host=dragoncoin.com \
--set nextcloud.username=dragon,nextcloud.password=SOMEVERYCOMPLEXANDVERYVERYLONGPASSWORD \
--set internalDatabase.enabled=false \
--set externalDatabase.existingSecret.enabled=true \
--set externalDatabase.type=postgresql \
--set externalDatabase.host='nextcloud-db-postgresql.default.svc.cluster.local' \
--set persistence.enabled=true \
--set persistence.existingClaim=nextcloud-claim \
--set persistence.size=100Ti \
--set livenessProbe.enabled=false \
--set readinessProbe.enabled=false \
--set nextcloud.phpConfigs.upload_max_size=40G \
--set nextcloud.phpConfigs.upload_max_filesize=40G \
--set nextcloud.phpConfigs.post_max_size=40G \
--set nextcloud.phpConfigs.memory_limit=80G
Step 3: Check the logs and wait for the upgrading process to complete
Previous pods terminated to make way for new pods
admin@controller:~$ k get pod
NAME READY STATUS RESTARTS AGE
nextcloud-67855fc94c-lc2xr 0/2 Terminating 0 74m
nextcloud-db-postgresql-0 1/1 Running 0 91m
admin@controller:~$ k get pod
NAME READY STATUS RESTARTS AGE
nextcloud-79b5b775fd-2s4bj 2/2 Running 0 56s
nextcloud-db-postgresql-0 1/1 Running 0 92m
Expected 502 errors during pod upgrades
admin@controller:~$ k logs nextcloud-79b5b775fd-2s4bj nextcloud-nginx
2021/11/01 05:36:49 [error] 32#32: *24 connect() failed (111: Connection refused) while connecting to upstream, client: 10.10.0.95, server: , request: "GET /status.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "dragoncoin.com"
10.10.0.95 - dragon [01/Nov/2021:05:36:49 +0000] "GET /status.php HTTP/1.1" 502 157 "-" "Mozilla/5.0 (Linux) mirall/3.2.2git (build 5903) (Nextcloud, linuxmint-5.4.0-89-generic ClientArchitecture: x86_64 OsArchitecture: x86_64)" "192.168.0.164"
Logs showing that the upgrading process has progressed… and eventually completed
admin@controller:~$ kubectl logs nextcloud-79b5b775fd-2s4bj nextcloud
Initializing nextcloud 22.2.0.2 ...
Upgrading nextcloud from 22.1.1.2 ...
Initializing finished
Nextcloud or one of the apps require upgrade - only a limited number of commands are available
You may use your browser or the occ upgrade command to do the upgrade
Setting log level to debug
Turned on maintenance mode
Updating database schema
Updated database
Updating <lookup_server_connector> ...
Updated <lookup_server_connector> to 1.10.0
Updating <oauth2> ...
Updated <oauth2> to 1.10.0
Updating <files> ...
Updated <files> to 1.17.0
Updating <cloud_federation_api> ...
Updated <cloud_federation_api> to 1.5.0
Updating <dav> ...
Fix broken values of calendar objects
Starting ...
Updated <dav> to 1.19.0
Updating <files_sharing> ...
Updated <files_sharing> to 1.14.0
Updating <files_trashbin> ...
Updated <files_trashbin> to 1.12.0
Updating <files_versions> ...
Updated <files_versions> to 1.15.0
Updating <sharebymail> ...
Updated <sharebymail> to 1.12.0
Updating <workflowengine> ...
Updated <workflowengine> to 2.4.0
Updating <systemtags> ...
Updated <systemtags> to 1.12.0
Updating <theming> ...
Updated <theming> to 1.13.0
Updating <accessibility> ...
Migrate old user config
0/0 [>---------------------------] 0% Starting ...
0/0 [->--------------------------] 0%
Starting ...
Updated <accessibility> to 1.8.0
Updating <contactsinteraction> ...
Updated <contactsinteraction> to 1.3.0
Updating <federatedfilesharing> ...
Updated <federatedfilesharing> to 1.12.0
Updating <provisioning_api> ...
Updated <provisioning_api> to 1.12.0
Updating <settings> ...
Updated <settings> to 1.4.0
Updating <twofactor_backupcodes> ...
Updated <twofactor_backupcodes> to 1.11.0
Updating <updatenotification> ...
Updated <updatenotification> to 1.12.0
Updating <user_status> ...
Updated <user_status> to 1.2.0
Updating <weather_status> ...
Updated <weather_status> to 1.2.0
Checking for update of app accessibility in appstore
Checked for update of app "accessibility" in App Store
Checking for update of app activity in appstore
Checked for update of app "activity" in App Store
Checking for update of app audioplayer in appstore
Checked for update of app "audioplayer" in App Store
Checking for update of app breezedark in appstore
Checked for update of app "breezedark" in App Store
Checking for update of app bruteforcesettings in appstore
Checked for update of app "bruteforcesettings" in App Store
Checking for update of app camerarawpreviews in appstore
Checked for update of app "camerarawpreviews" in App Store
Checking for update of app cloud_federation_api in appstore
Checked for update of app "cloud_federation_api" in App Store
Checking for update of app cms_pico in appstore
Checked for update of app "cms_pico" in App Store
Checking for update of app contactsinteraction in appstore
Checked for update of app "contactsinteraction" in App Store
Checking for update of app dav in appstore
Checked for update of app "dav" in App Store
Checking for update of app documentserver_community in appstore
Checked for update of app "documentserver_community" in App Store
Checking for update of app drawio in appstore
Checked for update of app "drawio" in App Store
Checking for update of app external in appstore
Checked for update of app "external" in App Store
Checking for update of app federatedfilesharing in appstore
Checked for update of app "federatedfilesharing" in App Store
Checking for update of app files in appstore
Checked for update of app "files" in App Store
Checking for update of app files_antivirus in appstore
Checked for update of app "files_antivirus" in App Store
Checking for update of app files_markdown in appstore
Checked for update of app "files_markdown" in App Store
Checking for update of app files_mindmap in appstore
Checked for update of app "files_mindmap" in App Store
Checking for update of app files_pdfviewer in appstore
Checked for update of app "files_pdfviewer" in App Store
Checking for update of app files_rightclick in appstore
Checked for update of app "files_rightclick" in App Store
Checking for update of app files_sharing in appstore
Checked for update of app "files_sharing" in App Store
Checking for update of app files_trashbin in appstore
Checked for update of app "files_trashbin" in App Store
Checking for update of app files_versions in appstore
Checked for update of app "files_versions" in App Store
Checking for update of app files_videoplayer in appstore
Checked for update of app "files_videoplayer" in App Store
Checking for update of app forms in appstore
Checked for update of app "forms" in App Store
Checking for update of app logreader in appstore
Checked for update of app "logreader" in App Store
Checking for update of app lookup_server_connector in appstore
Checked for update of app "lookup_server_connector" in App Store
Checking for update of app maps in appstore
Checked for update of app "maps" in App Store
Checking for update of app music in appstore
Checked for update of app "music" in App Store
Checking for update of app news in appstore
Checked for update of app "news" in App Store
Checking for update of app notifications in appstore
Checked for update of app "notifications" in App Store
Checking for update of app oauth2 in appstore
Checked for update of app "oauth2" in App Store
Checking for update of app password_policy in appstore
Checked for update of app "password_policy" in App Store
Checking for update of app photos in appstore
Checked for update of app "photos" in App Store
Checking for update of app privacy in appstore
Checked for update of app "privacy" in App Store
Checking for update of app provisioning_api in appstore
Checked for update of app "provisioning_api" in App Store
Checking for update of app quicknotes in appstore
Checked for update of app "quicknotes" in App Store
Checking for update of app recommendations in appstore
Checked for update of app "recommendations" in App Store
Checking for update of app registration in appstore
Checked for update of app "registration" in App Store
Checking for update of app richdocuments in appstore
Checked for update of app "richdocuments" in App Store
Checking for update of app serverinfo in appstore
Checked for update of app "serverinfo" in App Store
Checking for update of app settings in appstore
Checked for update of app "settings" in App Store
Checking for update of app sharebymail in appstore
Checked for update of app "sharebymail" in App Store
Checking for update of app spreed in appstore
Checked for update of app "spreed" in App Store
Checking for update of app support in appstore
Checked for update of app "support" in App Store
Checking for update of app survey_client in appstore
Checked for update of app "survey_client" in App Store
Checking for update of app systemtags in appstore
Checked for update of app "systemtags" in App Store
Checking for update of app tasks in appstore
Checked for update of app "tasks" in App Store
Checking for update of app text in appstore
Checked for update of app "text" in App Store
Checking for update of app theming in appstore
Checked for update of app "theming" in App Store
Checking for update of app twofactor_backupcodes in appstore
Checked for update of app "twofactor_backupcodes" in App Store
Checking for update of app updatenotification in appstore
Checked for update of app "updatenotification" in App Store
Checking for update of app user_status in appstore
Checked for update of app "user_status" in App Store
Checking for update of app video_converter in appstore
Checked for update of app "video_converter" in App Store
Checking for update of app viewer in appstore
Checked for update of app "viewer" in App Store
Checking for update of app weather_status in appstore
Checked for update of app "weather_status" in App Store
Checking for update of app workflowengine in appstore
Checked for update of app "workflowengine" in App Store
Starting code integrity check...
After about 5 minutes (depending on the system hardware), NextCloud should be rendered back online. At this point, the upgrade has completed.
WordPress: How To Add Custom XML Sitemap to Yoast SEO
Step 1: Install Yoast SEO
Step 2: Install Code Snippets
Step 3: Add this Snippet
/* Add External Sitemap to Yoast Sitemap Index
* Credit: Paul https:// wordpress.org/support/users/paulmighty/
* Last Tested: Aug 25 2017 using Yoast SEO 5.3.2 on WordPress 4.8.1
* Please note that changes will be applied upon next sitemap update.
* To manually refresh the sitemap, please disable and enable the sitemaps.
* Code obtained from https:// gist.github.com/amboutwe/8cfb7a3d8f05e580867341d4ff84141d
*/
add_filter( 'wpseo_sitemap_index', 'add_sitemap_custom_items' );
function add_sitemap_custom_items() {
$sitemap_custom_items = '
<sitemap>
<loc>https://sexcenter.com/wp-content/gallery-pages.xml</loc>
<lastmod>2021-10-30T23:12:27+00:00</lastmod>
</sitemap>';
/* DO NOT REMOVE ANYTHING BELOW THIS LINE
* Send the information to Yoast SEO
*/
return $sitemap_custom_items;
}
Step 4: Create an XML Sitemap and Place It Under wp-content
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brunette-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/asian-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/blonde-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/redhead-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/brown-hair-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/latinas/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/lesbians/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/sex-toys/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/gay-guys/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/group-sex/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/mature-women/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/black-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/2</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/3</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/4</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/5</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/6</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/7</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/8</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/9</loc>
<lastmod>2021-10-30</lastmod>
</url>
<url>
<loc>https://sexcenter.com/porn-galleries/white-girls/porn-gallery/page/10</loc>
<lastmod>2021-10-30</lastmod>
</url>
</urlset>
Linux: How To Use Dig
Checking Name Server(s)
kim@kim-linux:~$ dig @8.8.8.8 microsoft.com
; <<>> DiG 9.16.1-Ubuntu <<>> @8.8.8.8 microsoft.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47352
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;microsoft.com. IN A
;; ANSWER SECTION:
microsoft.com. 816 IN A 104.215.148.63
microsoft.com. 816 IN A 40.76.4.15
microsoft.com. 816 IN A 40.112.72.205
microsoft.com. 816 IN A 40.113.200.201
microsoft.com. 816 IN A 13.77.161.179
;; Query time: 4 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Oct 29 09:41:15 PDT 2021
;; MSG SIZE rcvd: 122
Looking Up TXT Records (Including SPF)
kim@kim-linux:~$ dig @8.8.8.8 microsoft.com txt
; <<>> DiG 9.16.1-Ubuntu <<>> @8.8.8.8 microsoft.com txt
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42064
;; flags: qr rd ra; QUERY: 1, ANSWER: 16, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;microsoft.com. IN TXT
;; ANSWER SECTION:
microsoft.com. 2127 IN TXT "docusign=d5a3737c-c23c-4bd0-9095-d2ff621f2840"
microsoft.com. 2127 IN TXT "v=spf1 include:_spf-a.microsoft.com include:_spf-b.microsoft.com include:_spf-c.microsoft.com include:_spf-ssg-a.microsoft.com include:spf-a.hotmail.com include:_spf1-meo.microsoft.com -all"
microsoft.com. 2127 IN TXT "google-site-verification=Zv1IvEEZg4N9wbEXpBSSyAiIjDyyB3S-fzfFClb7D1E"
microsoft.com. 2127 IN TXT "adobe-sign-verification=c1fea9b4cdd4df0d5778517f29e0934"
microsoft.com. 2127 IN TXT "docusign=52998482-393d-46f7-95d4-15ac6509bfdd"
microsoft.com. 2127 IN TXT "google-site-verification=8-zFCaUXhhPcvN29EVw2RvtASDCaDPQ02L1HJ8Om8I0"
microsoft.com. 2127 IN TXT "adobe-idp-site-verification=8aa35c528af5d72beb19b1bd3ed9b86d87ea7f24b2ba3c99ffcd00c27e9d809c"
microsoft.com. 2127 IN TXT "d365mktkey=4d8bnycx40fy3581petta4gsf"
microsoft.com. 2127 IN TXT "8RPDXjBzBS9tu7Pbysu7qCACrwXPoDV8ZtLfthTnC4y9VJFLd84it5sQlEITgSLJ4KOIA8pBZxmyvPujuUvhOg=="
microsoft.com. 2127 IN TXT "google-site-verification=1TeK8q0OziFl4T1tF-QR65JkzHZ1rcdgNccDFp78iTk"
microsoft.com. 2127 IN TXT "d365mktkey=3uc1cf82cpv750lzk70v9bvf2"
microsoft.com. 2127 IN TXT "facebook-domain-verification=fwzwhbbzwmg5fzgotc2go51olc3566"
microsoft.com. 2127 IN TXT "apple-domain-verification=0gMeaYyYy6GLViGo"
microsoft.com. 2127 IN TXT "google-site-verification=pjPOauSPcrfXOZS9jnPPa5axowcHGCDAl1_86dCqFpk"
microsoft.com. 2127 IN TXT "fg2t0gov9424p2tdcuo94goe9j"
microsoft.com. 2127 IN TXT "t7sebee51jrj7vm932k531hipa"
;; Query time: 4 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Oct 29 09:39:39 PDT 2021
;; MSG SIZE rcvd: 1261
Domain Name Records Overview: A-record, MX, DKIM, SPF, SRV
A RECORD (A-host):
– What: address record (A-record) specifies the IP address(es) of a given domain. In the case of IPv6, this is called an AAAA record.
– Why: name to address translation is necessary for users to type in a name to get to an IP address of the web server
– Who: domain admin sets these up, and these affect all users of the domain
– How:kimconnect.com record type: value: TTL
@ A x.x.x.x 14400
MX (Mail Exchange):
– What: mail exchange (MX) records direct emails toward designated mail servers. These are like CNAME records for name servers with the difference in their marking as designated for mailings
– Why: these entries control how email messages should be routed in accordance with the Simple Mail Transfer Protocol (SMTP)
– Who: domain admins can edit these records
– How: below is an example of setting mail records of a domain toward 2 mail servers with different prioritieskimconnect.com record type: priority: value: TTL
@ MX 10 mail1.kimconnect.com 45000
@ MX 20 mail2.kimconnect.com 45000
SPF (Sender Policy Framework):
– What: Sender Policy Framework (spf) is a type of TXT record in your DNS zone
– Why: SPF records help identify which mail servers are permitted to send email on behalf of your domain. These records prevent spammers from sending emails with a forged ‘From’ addresses of your domain
– Who: domain admins can make these changes. Users benefit from not receiving forged emails, and would correctly receive emails being sent from company servers.
– How (examples):
a. Simple:- v=spf1 include:_spf.google.com ~all (Google)
- v=spf1 include:spf.protection.outlook.com ~all (Microsoft)
b. Complex:- v=spf1 ip4:IP.ADDRESS.HERE/NETMASK include:_spf.google.com ~all (Google)
- v=spf1 ip4:IP.ADDRESS.HERE/NETMASK include:spf.protection.outlook.com ~all (Microsoft)
- v=spf1 ip4:IP.ADDRESS.HERE/NETMASK include:spf.protection.outlook.com include:_spf.google.com include:aem.autotask.net include:customers.clickdimensions.com ~all (Google, Microsoft, ClickDimensions, Autotask)
Explanations
v=spf1
: marks spf protocol version (version 1 is the most commonly used protocol by email servers as of this writing)ip4
orip6
: specifies the IP address versioning. A single IP or a summarized subnet/supernet are acceptablemx
: allows the MX servers to send mailinclude
: allows a third-party to send emails on your domain’s behalfa
: allows the current IP to send mail+all
: allows any IP to send emails on this domain’s behalf-all
: allows no other IP’s to send emails on the domain’s behalf~all
: allows all IP’s to send emails on your domain’s behalf, while messages would be marked
DKIM (DomainKeys Identified Mail):
– What: it’s an email record associated with certain domains. These are composed of a selector and a public key. There is a private key that is installed on the email server, and is its alternate hashes are attached to email headers. Only the public key is added as the domain’s DNS record. The receiving email server performs keys matching to determine if the email is legitimate (not spam)
– Why: to prevent email spoofing
– Who: domain admins make these changes
– How: (source: Google)
- Generate the domain key for your domain (For Google: https:// support.google.com/a/answer/174126?hl=en&ref_topic=2752442)
- Add the public key to your domain’s DNS records
- Example:
kimconnect.com. 300 IN TXT "v=DKIM1; k=rsa; p=SOMEHASH" "MOREHASH"
- Example:
- Add DKIM onto email server(s) to start adding a DKIM signature to all outgoing messages
- Example:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=kimconnect.com; s=google;
h=sender:mime-version:from:to:date:subject:message-id
:x-original-sender:x-original-authentication-results:precedence
:mailing-list:list-id:list-post:list-help:list-archive
:list-unsubscribe;
bh=SOMELONGHASH
- Example:
SRV (Service Records):
– What: service (SRV) records specify hosts and ports for services such as VoIP, instant messaging, domain proof of ownership, etc.
– Why: these records include IP address and port information that other type of DNS records do not have the option. Some Internet protocols require the use of SRV records in order to function.
– Who: domain admins manage these at DNS zone control panels
– How: SRV records must point to an A record (in IPv4) or an AAAA record (in IPv6), not CNAME. Below are some examples_sip._tls.@ 100 1 443 sipdir.online.lync.com. (Microsoft Lync)
_sipfederationtls._tcp.@ 100 1 5061 sipfed.online.lync.com. (Microsoft Lync)
_xmpp._tcp.kimconnect.com. 86400 IN SRV 10 5 5223 xmpp.kimconnect.com. (xmpp server)
How To Improve WordPress Website Rendering Speed
These are the recommended plug-ins to enable caching, database cleaning, image compressing, and minify codes to enhance a website’s response time.
Wp-Optimize: primary function is to optimize the WordPress Database and remove unnecessary data from tables (post revisions, auto-drafts, trashed). This may speed up SQL query response time. Other functions include page caching, minify JS/CSS/HTML (less matured than Autoptimize).
WP Super Cache: primary function is caching. It is different from other plugins in way that it converts all the php to html, thus reducing the server execution time everytime a request is made.
WP total cache: primary function is to provide caching. This is a contender to WP Optimize.
Autoptimize: primary function is minify JS/CSS/HTML, which optimizes delivery of of CSS and JQuery files on your website. This has been known to improve website speed.
– Optimize javascript code, Aggregate JS files, Also inline JS
– Optimize CSS Code, Aggregate CSS files, Also aggregate inline CSS
– Optimize HTML code
– Images: lazy load images, optimize images (glossy)
– Extra: Remove emojis, Remove query strings
Ewww image optimizer: primary function is to compress images for faster delivery.
a3 lazy load: primary function is to enable a ‘lazy load’ function to only trigger downloading of images when site scroller is in view. This does save bandwidth; thus, faster initial rendering is expected.
The 5 Rules of Thumb of Business Presentation (To Attract Investors)
I’m noting this here so that I can revisit these bullet points in the future…
1. Define the problem or need of the users in the market
2. Present your team or yourself as the expert who can solve this problem
3. Present the solution from the users’ perspective
4. Show a growth chart: users, revenue, traffic
5. Vision: must be realistic and credible
Credit: Justin Kan (one of the heros on my list)
WordPress PHP Fatal error: Maximum execution time of 30 seconds exceeded
Error:
[Tue Oct 12 05:57:03.088314 2021] [php7:error] [pid 167] [client 172.16.90.64:39776] PHP Fatal error: Maximum execution time of 30 seconds exceeded in /bitnami/wordpress/wp-content/plugins/nextgen-gallery/vendor/imagely/pope-framework/lib/class.extensibleobject.php on line 0, referer: https://dragoncoin.com/wp-admin/admin.php?page=ngg_addgallery
Resolution:
Option A: Edit php.ini
// Case: Kubernetes Pod / Docker Container
containerName=sexcenter-wordpress-6f59c9fbff-5b99h
kubectl exec --stdin --tty $containerName -- /bin/bash
// Check execution time
grep max_execution_time /opt/bitnami/php/etc/php.ini
// Change execution time duration to 1 hour
sed -i '/max_execution_time/c\max_execution_time = 3600' /opt/bitnami/php/etc/php.ini
// Check memory limit
grep memory_limit /opt/bitnami/php/etc/php.ini
// Set memory limit to 20GB
sed -i '/memory_limit/c\memory_limit = 20G' /opt/bitnami/php/etc/php.ini
// Change execution time duration and memory to unlimited (for testing purposes)
sed -i '/max_execution_time/c\max_execution_time = 999999' /opt/bitnami/php/etc/php.ini
sed -i '/memory_limit/c\memory_limit = -1' /opt/bitnami/php/etc/php.ini
// Restart apache
apachectl restart
Option B: Edit wp-config.php
// Set execution time to 24 hours
ini_set('max_execution_time', '5184000');
set_time_limit(5184000);
Option C: Edit .htaccess
php_value max_execution_time 120
How To Increase WordPress Memory Limit
It’s are lesser known fact that WordPress overrides PHP’s memory_limit settings. Thus, it is possible to edit the wp-config.php file to increase WordPress’ memory allocation.
Depending on the deployment configs, wp-config.php usually is located in the /public/html directory. In the case of docker, it’s one level above wp-content directory.
A. Increasing the Administrative Memory
For admin pages, WordPress ignores PHP’s memory limit and configures its own. To change it to something other than 256 megabytes, you must set WP_MAX_MEMORY_LIMIT in wp-config.php.
To increase the memory to the administrative side of your site, add the following line in your wp-config.php:
// This sets the admin panel memory limit to 4GB
define('WP_MAX_MEMORY_LIMIT', '4G');
B. Increasing Public Memory
To increase the memory limit for your public-facing pages, open your app’s wp‑config.php and add the following line:
// This configures the public users' view memory limit to 8GB
define('WP_MEMORY_LIMIT', '8G');
Kubernetes: Use Helm to Deploy WordPress
Deploying WordPress in a Kubernetes cluster isn’t as straight-forward is one might expect. As the whole infrastructure is controlled by K8s, the deployed containers must be configured with the correct permissions to avoid strange issues. For example, there are certain plugins such as NextGen Gallery that would seem to work fine (initially) in a WordPress instance; however, it would suddenly ‘break’ as CSS and JS (JavaScripts) are showing 404’s. Specially, lightbox and other gallery views functions would become orphanated to leave a Gallery view without slideshow, multi-column views, and other animations. Hence, there are many lesion-learned prior issuing this blog post…
Step 1: Prepare an SSL Cert using LetsEncrypt
# Create SSL Cert, assuming the certmanager has been deployed in the Kubernetes cluster
appName=kimconnect
domainName=kimconnect.com
cat <<EOF > $appName-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: $appName-cert
namespace: $appName
annotations:
kubernetes.io/ingress.class: "nginx"
acme.cert-manager.io/http01-edit-in-place: "true"
kubernetes.io/tls-acme: "true"
spec:
dnsNames:
- $domainName
secretName: $appName-cert
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
EOF
kubectl apply -f $appName-cert.yaml
Step 2: Deploy WordPress
# Create name space and enter it
appName=kimconnect
kubectl create namespace $appName
kubectl config set-context --current --namespace=$appName
# Install WordPress with Dynamic NFS Provisioning
# Documentation: https://hub.kubeapps.com/charts/bitnami/wordpress
# Set variables
appName=kimconnect
domainName=kimconnect.com
wordpressusername=kimconnect
wordpressPassword=SOMEVERYCOMPLEXPASSWORD
rootPassword=SOMEVERYCOMPLEXPASSWORD
storageClass=nfs-client
helm install $appName bitnami/wordpress \
--set readinessProbe.enabled=false \
--set image.tag=latest \
--set persistence.accessMode=ReadWriteMany \
--set persistence.storageClass=$storageClass \
--set persistence.size=10Ti \
--set mariadb.primary.persistence.storageClass=$storageClass \
--set mariadb.primary.persistence.size=300Gi \
--set wordpressUsername=$wordpressusername \
--set wordpressPassword=$wordpressPassword \
--set mariadb.auth.rootPassword=$rootPassword \
--set mariadb.auth.password=$rootPassword \
--set ingress.enabled=true,ingress.hostname=$domainName \
--set volumePermissions.enabled=true \
--set allowEmptyPassword=false \
--set service.externalTrafficPolicy=Local # this setting is to make sure the source IP address is preserved.
Step 3: Patch Ingress
# Patch the deployed ingress with an existing SSL cert
appName=kimconnect
domainName=kimconnect.com
certName=$appName-cert
serviceName=$appName-wordpress
cat <<EOF> $appName-patch.yaml
metadata:
Annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
location ~ /wp-admin$ {
return 301 /wp-admin/;
}
spec:
tls:
- hosts:
- $domainName
secretName: $certName
rules:
- host: $domainName
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: $serviceName
port:
number: 80
EOF
kubectl patch ingress/$appName-wordpress -p "$(cat $appName-patch.yaml)"
Step 4: Patch WordPress to Add Libraries and Frameworks
# Still researching this item
# Add iocube loader while inside the container
sed -i '/\[PHP\]/a zend_extension=/bitnami/wordpress/extensions/ioncube_loader_lin_7.4.so' /opt/bitnami/php/etc/php.ini && httpd -k restart
How To Hide Featured Image in Blog Posts in Single View
In WordPress, single posts can have a featured image to help with displaying in List views as well as search engine excerpts (previews). However, such featured images could overwhelm a blog post when they would dominate the upper section of an article. Therefore, it’s often necessary to hide featured images while retaining their prevalence in list views. Here are the steps:
Lightbox Javascript Contents
These JavaScript codes are open source and part of many applications, such as NextGen Gallery. Their contents are pasted here for ease of reading and referencing.
// lightbox_context.min.js
"use strict";function nextgen_lightbox_filter_selector(e,t){if(nextgen_lightbox_settings&&nextgen_lightbox_settings.context){var n=nextgen_lightbox_settings.context;"all_images"==n?t=t.add(e("a > img").parent()):"all_images_direct"==n?t=t.add(e("a[href] > img").parent().filter(function(){var t=e(this).attr("href").toLowerCase(),n=t.substring(t.length-3),g=t.substring(t.length-4);return"jpg"==n||"gif"==n||"png"==n||"tiff"==g||"jpeg"==g||"webp"==g})):"nextgen_and_wp_images"==n&&(t=t.add(e('a > img[class*="wp-image-"]').parent())),t=t.not(".gallery_link"),t=t.not(".use_imagebrowser_effect")}return t}
// common.js
(function($) {
window.NggPaginatedGallery = function(displayed_gallery_id, container) {
this.displayed_gallery_id = displayed_gallery_id;
this.container = $(container);
this.container_name = container;
this.get_displayed_gallery_obj = function() {
var index = 'gallery_' + this.displayed_gallery_id;
if (typeof(window.galleries[index]) == 'undefined') {
return false;
} else {
return window.galleries[index];
}
};
this.enable_ajax_pagination = function() {
var self = this;
// Attach a click event handler for each pagination link to adjust the request to be sent via XHR
$('body').on('click', 'a.ngg-browser-prev, a.ngg-browser-next', function (event) {
var skip = true;
$(this).parents(container).each(function() {
if ($(this).data('nextgen-gallery-id') != self.displayed_gallery_id) {
return true;
}
skip = false;
});
if (!skip) {
event.preventDefault();
} else {
return;
}
// Adjust the user notification
window['ngg_ajax_operaton_count']++;
$('body, a').css('cursor', 'wait');
// Send the AJAX request
$.get($(this).attr('href'), function (response) {
window['ngg_ajax_operaton_count']--;
if (window['ngg_ajax_operaton_count'] <= 0) {
window['ngg_ajax_operaton_count'] = 0;
$('body, a').css('cursor', 'auto');
}
if (response) {
var html = $(response);
var replacement = false;
html.find(self.container_name).each(function() {
if (replacement) {
return true;
}
if ($(this).data('nextgen-gallery-id') != self.displayed_gallery_id) {
return true;
}
replacement = $(this);
});
if (replacement) {
self.container.each(function () {
var $this = $(this);
if ($this.data('nextgen-gallery-id') != self.displayed_gallery_id) {
return true;
}
// If the image gallery makes up the bulk of the post/page content the .html() call
// below will empty the contents causing the browser's scroll position to be reset to
// zero as the browser believes it has been pushed back to the top of the page. Here
// we give the parent container a min-height equal to the gallery's height to prevent
// this flicker and resetting of the scroll position.
var $new_element = $(replacement.html());
var promises = $new_element.find('img').toArray().map(function(img){
return new Promise(function(resolve, reject){
var i = new Image();
i.src = img.src;
$(i).on('load', resolve);
});
});
Promise.all(promises).then(function(){
$this.html($new_element);
// Let the user know that we've refreshed the content
$(document).trigger('refreshed');
});
return true;
});
}
}
});
});
};
// Initialize
var displayed_gallery = this.get_displayed_gallery_obj();
if (displayed_gallery) {
if (typeof(displayed_gallery.display_settings['ajax_pagination']) != 'undefined') {
if (parseInt(displayed_gallery.display_settings['ajax_pagination'])) {
this.enable_ajax_pagination();
}
}
}
// We maintain a count of all the current AJAX actions initiated
if (typeof(window['ngg_ajax_operation_count']) == 'undefined') {
window['ngg_ajax_operaton_count'] = 0;
}
};
// Polyfill for older browsers
Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
obj.__proto__ = proto;
return obj;
};
if (typeof window.galleries !== 'undefined') {
Object.setPrototypeOf(
window.galleries,
{
get_api_version: function() {
return '0.1';
},
get_from_id: function (gallery_id) {
var self = this;
var retval = null;
var keys = Object.keys(this);
for (var i = 1; i <= keys.length; i++) {
var gallery = self[keys[i - 1]];
if (gallery.ID === gallery_id || gallery.ID === 'gallery_' + gallery_id || gallery.ID === parseInt(gallery_id)) {
retval = gallery;
break;
}
}
return retval;
},
get_from_slug: function (slug) {
var self = this;
var retval = null;
var keys = Object.keys(this);
for (var i = 1; i <= keys.length; i++) {
var gallery = self[keys[i - 1]];
if (gallery.slug === slug) {
retval = gallery;
break;
}
}
return retval;
},
get_setting: function(gallery_id, name, def) {
var tmp = '';
var gallery = this.get_from_id(gallery_id);
if (gallery && typeof gallery[name] !== 'undefined') {
tmp = gallery[name];
} else {
tmp = def;
}
if (tmp === 1) tmp = true;
if (tmp === 0) tmp = false;
if (tmp === '1') tmp = true;
if (tmp === '0') tmp = false;
if (tmp === 'false') tmp = false;
if (tmp === 'true') tmp = true;
return tmp;
},
get_display_setting: function(gallery_id, name, def) {
var tmp = '';
var gallery = this.get_from_id(gallery_id);
if (gallery && typeof gallery.display_settings[name] !== 'undefined') {
tmp = gallery.display_settings[name];
} else {
tmp = def;
}
if (tmp === 1) tmp = true;
if (tmp === 0) tmp = false;
if (tmp === '1') tmp = true;
if (tmp === '0') tmp = false;
if (tmp === 'false') tmp = false;
if (tmp === 'true') tmp = true;
return tmp;
},
is_widget: function(gallery_id) {
var retval = false;
var gallery = this.get_from_id(gallery_id);
var slug = gallery.slug;
if (slug) {
return slug.indexOf('widget-ngg-images') !== -1;
}
return retval;
}
}
); }
})(jQuery);
// lightbox_context.js
function nextgen_lightbox_filter_selector($, selector)
{
if (nextgen_lightbox_settings && nextgen_lightbox_settings.context) {
var context = nextgen_lightbox_settings.context;
if (context == 'all_images') {
selector = selector.add($('a > img').parent());
}
else if (context == 'all_images_direct') {
selector = selector.add($('a[href] > img').parent()
.filter(function() {
var href = $(this).attr('href').toLowerCase();
var ext = href.substring(href.length - 3);
var ext2 = href.substring(href.length - 4);
return (ext == 'jpg' || ext == 'gif' || ext == 'png' || ext2 == 'tiff' || ext2 == 'jpeg' || ext2 == 'webp');
}));
}
else if (context == 'nextgen_and_wp_images') {
selector = selector.add($('a > img[class*="wp-image-"]').parent());
}
selector = selector.not('.gallery_link');
selector = selector.not('.use_imagebrowser_effect');
}
return selector;
}
// simple_lightbox.js
/*!
By André Rinas, www.andrerinas.de
Documentation, www.simplelightbox.de
Available for use under the MIT License
Version 2.1.5
*/
"use strict";
function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var SimpleLightbox = /*#__PURE__*/function () {
function SimpleLightbox(elements, options) {
var _this = this;
_classCallCheck(this, SimpleLightbox);
_defineProperty(this, "defaultOptions", {
sourceAttr: 'href',
overlay: true,
spinner: true,
nav: true,
navText: ['‹', '›'],
captions: true,
captionDelay: 0,
captionSelector: 'img',
captionType: 'attr',
captionsData: 'title',
captionPosition: 'bottom',
captionClass: '',
close: true,
closeText: '×',
swipeClose: true,
showCounter: true,
fileExt: 'png|jpg|jpeg|gif|webp',
animationSlide: true,
animationSpeed: 250,
preloading: true,
enableKeyboard: true,
loop: true,
rel: false,
docClose: true,
swipeTolerance: 50,
className: 'simple-lightbox',
widthRatio: 0.8,
heightRatio: 0.9,
scaleImageToRatio: false,
disableRightClick: false,
disableScroll: true,
alertError: true,
alertErrorMessage: 'Image not found, next image will be loaded',
additionalHtml: false,
history: true,
throttleInterval: 0,
doubleTapZoom: 2,
maxZoom: 10,
htmlClass: 'has-lightbox',
rtl: false
});
_defineProperty(this, "transitionPrefix", void 0);
_defineProperty(this, "transitionCapable", false);
_defineProperty(this, "isTouchDevice", 'ontouchstart' in window);
_defineProperty(this, "initialLocationHash", void 0);
_defineProperty(this, "pushStateSupport", 'pushState' in history);
_defineProperty(this, "isOpen", false);
_defineProperty(this, "isAnimating", false);
_defineProperty(this, "isClosing", false);
_defineProperty(this, "urlChangedOnce", false);
_defineProperty(this, "hashReseted", false);
_defineProperty(this, "historyHasChanges", false);
_defineProperty(this, "historyUpdateTimeout", null);
_defineProperty(this, "currentImage", void 0);
_defineProperty(this, "eventNamespace", 'simplelightbox');
_defineProperty(this, "domNodes", {});
_defineProperty(this, "loadedImages", []);
_defineProperty(this, "initialImageIndex", 0);
_defineProperty(this, "currentImageIndex", 0);
_defineProperty(this, "initialSelector", null);
_defineProperty(this, "globalScrollbarWidth", 0);
_defineProperty(this, "controlCoordinates", {
swipeDiff: 0,
swipeYDiff: 0,
swipeStart: 0,
swipeEnd: 0,
swipeYStart: 0,
swipeYEnd: 0,
mousedown: false,
imageLeft: 0,
zoomed: false,
containerHeight: 0,
containerWidth: 0,
containerOffsetX: 0,
containerOffsetY: 0,
imgHeight: 0,
imgWidth: 0,
capture: false,
initialOffsetX: 0,
initialOffsetY: 0,
initialPointerOffsetX: 0,
initialPointerOffsetY: 0,
initialPointerOffsetX2: 0,
initialPointerOffsetY2: 0,
initialScale: 1,
initialPinchDistance: 0,
pointerOffsetX: 0,
pointerOffsetY: 0,
pointerOffsetX2: 0,
pointerOffsetY2: 0,
targetOffsetX: 0,
targetOffsetY: 0,
targetScale: 0,
pinchOffsetX: 0,
pinchOffsetY: 0,
limitOffsetX: 0,
limitOffsetY: 0,
scaleDifference: 0,
targetPinchDistance: 0,
touchCount: 0,
doubleTapped: false,
touchmoveCount: 0
});
this.options = Object.assign(this.defaultOptions, options);
if (typeof elements === 'string') {
this.initialSelector = elements;
this.elements = Array.from(document.querySelectorAll(elements));
} else {
this.elements = typeof elements.length !== 'undefined' && elements.length > 0 ? Array.from(elements) : [elements];
}
this.relatedElements = [];
this.transitionPrefix = this.calculateTransitionPrefix();
this.transitionCapable = this.transitionPrefix !== false;
this.initialLocationHash = this.hash; // this should be handled by attribute selector IMHO! => 'a[rel=bla]'...
if (this.options.rel) {
this.elements = this.getRelated(this.options.rel);
}
this.createDomNodes();
if (this.options.close) {
this.domNodes.wrapper.appendChild(this.domNodes.closeButton);
}
if (this.options.nav) {
this.domNodes.wrapper.appendChild(this.domNodes.navigation);
}
if (this.options.spinner) {
this.domNodes.wrapper.appendChild(this.domNodes.spinner);
}
this.addEventListener(this.elements, 'click.' + this.eventNamespace, function (event) {
if (_this.isValidLink(event.currentTarget)) {
event.preventDefault();
if (_this.isAnimating) {
return false;
}
_this.initialImageIndex = _this.elements.indexOf(event.currentTarget);
_this.openImage(event.currentTarget);
}
}); // close addEventListener click addEventListener doc
if (this.options.docClose) {
this.addEventListener(this.domNodes.overlay, ['click.' + this.eventNamespace, 'touchstart.' + this.eventNamespace], function (event) {
if (_this.isOpen) {
_this.close();
}
});
} // disable rightclick
if (this.options.disableRightClick) {
this.addEventListener(document.body, 'contextmenu.' + this.eventNamespace, function (event) {
if (event.target.classList.contains('sl-overlay')) {
event.preventDefault();
}
});
} // keyboard-control
if (this.options.enableKeyboard) {
this.addEventListener(document.body, 'keyup.' + this.eventNamespace, this.throttle(function (event) {
_this.controlCoordinates.swipeDiff = 0; // keyboard control only if lightbox is open
if (_this.isAnimating && event.key === 'Escape') {
_this.currentImage.setAttribute('src', '');
_this.isAnimating = false;
return _this.close();
}
if (_this.isOpen) {
event.preventDefault();
if (event.key === 'Escape') {
_this.close();
}
if (!_this.isAnimating && ['ArrowLeft', 'ArrowRight'].indexOf(event.key) > -1) {
_this.loadImage(event.key === 'ArrowRight' ? 1 : -1);
}
}
}, this.options.throttleInterval));
}
this.addEvents();
}
_createClass(SimpleLightbox, [{
key: "createDomNodes",
value: function createDomNodes() {
this.domNodes.overlay = document.createElement('div');
this.domNodes.overlay.classList.add('sl-overlay');
this.domNodes.overlay.dataset.opacityTarget = ".7";
this.domNodes.closeButton = document.createElement('button');
this.domNodes.closeButton.classList.add('sl-close');
this.domNodes.closeButton.innerHTML = this.options.closeText;
this.domNodes.spinner = document.createElement('div');
this.domNodes.spinner.classList.add('sl-spinner');
this.domNodes.spinner.innerHTML = '<div></div>';
this.domNodes.navigation = document.createElement('div');
this.domNodes.navigation.classList.add('sl-navigation');
this.domNodes.navigation.innerHTML = "<button class=\"sl-prev\">".concat(this.options.navText[0], "</button><button class=\"sl-next\">").concat(this.options.navText[1], "</button>");
this.domNodes.counter = document.createElement('div');
this.domNodes.counter.classList.add('sl-counter');
this.domNodes.counter.innerHTML = '<span class="sl-current"></span>/<span class="sl-total"></span>';
this.domNodes.caption = document.createElement('div');
this.domNodes.caption.classList.add('sl-caption', 'pos-' + this.options.captionPosition);
if (this.options.captionClass) {
this.domNodes.caption.classList.add(this.options.captionClass);
}
this.domNodes.image = document.createElement('div');
this.domNodes.image.classList.add('sl-image');
this.domNodes.wrapper = document.createElement('div');
this.domNodes.wrapper.classList.add('sl-wrapper');
if (this.options.className) {
this.domNodes.wrapper.classList.add(this.options.className);
}
if (this.options.rtl) {
this.domNodes.wrapper.classList.add('sl-dir-rtl');
}
}
}, {
key: "throttle",
value: function throttle(func, limit) {
var inThrottle;
return function () {
if (!inThrottle) {
func.apply(this, arguments);
inThrottle = true;
setTimeout(function () {
return inThrottle = false;
}, limit);
}
};
}
}, {
key: "isValidLink",
value: function isValidLink(element) {
return !this.options.fileExt || 'pathname' in element && new RegExp('(' + this.options.fileExt + ')$', 'i').test(element.pathname);
}
}, {
key: "calculateTransitionPrefix",
value: function calculateTransitionPrefix() {
var s = (document.body || document.documentElement).style;
return 'transition' in s ? '' : 'WebkitTransition' in s ? '-webkit-' : 'MozTransition' in s ? '-moz-' : 'OTransition' in s ? '-o' : false;
}
}, {
key: "toggleScrollbar",
value: function toggleScrollbar(type) {
var scrollbarWidth = 0;
if (type === 'hide') {
var fullWindowWidth = window.innerWidth;
if (!fullWindowWidth) {
var documentElementRect = document.documentElement.getBoundingClientRect();
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
}
if (document.body.clientWidth < fullWindowWidth) {
var scrollDiv = document.createElement('div'),
paddingRight = parseInt(document.body.style.paddingRight || 0, 10);
scrollDiv.classList.add('sl-scrollbar-measure');
document.body.appendChild(scrollDiv);
scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
document.body.dataset.originalPaddingRight = paddingRight;
if (scrollbarWidth > 0) {
document.body.classList.add('hidden-scroll');
document.body.style.paddingRight = paddingRight + scrollbarWidth + 'px';
}
}
} else {
document.body.classList.remove('hidden-scroll');
document.body.style.paddingRight = document.body.dataset.originalPaddingRight;
}
return scrollbarWidth;
}
}, {
key: "close",
value: function close() {
var _this2 = this;
if (!this.isOpen || this.isAnimating || this.isClosing) {
return false;
}
this.isClosing = true;
var element = this.relatedElements[this.currentImageIndex];
element.dispatchEvent(new Event('close.simplelightbox'));
if (this.options.history) {
this.historyHasChanges = false;
if (!this.hashReseted) {
this.resetHash();
}
}
this.fadeOut(document.querySelectorAll('.sl-image img, .sl-overlay, .sl-close, .sl-navigation, .sl-image .sl-caption, .sl-counter'), 300, function () {
if (_this2.options.disableScroll) {
_this2.toggleScrollbar('show');
}
if (_this2.options.htmlClass && _this2.options.htmlClass !== '') {
document.querySelector('html').classList.remove(_this2.options.htmlClass);
}
document.body.removeChild(_this2.domNodes.wrapper);
document.body.removeChild(_this2.domNodes.overlay);
_this2.domNodes.additionalHtml = null;
element.dispatchEvent(new Event('closed.simplelightbox'));
_this2.isClosing = false;
});
this.currentImage = null;
this.isOpen = false;
this.isAnimating = false; // reset touchcontrol coordinates
for (var key in this.controlCoordinates) {
this.controlCoordinates[key] = 0;
}
this.controlCoordinates.mousedown = false;
this.controlCoordinates.zoomed = false;
this.controlCoordinates.capture = false;
this.controlCoordinates.initialScale = this.minMax(1, 1, this.options.maxZoom);
this.controlCoordinates.doubleTapped = false;
}
}, {
key: "preload",
value: function preload() {
var _this3 = this;
var index = this.currentImageIndex,
length = this.relatedElements.length,
next = index + 1 < 0 ? length - 1 : index + 1 >= length - 1 ? 0 : index + 1,
prev = index - 1 < 0 ? length - 1 : index - 1 >= length - 1 ? 0 : index - 1,
nextImage = new Image(),
prevImage = new Image();
nextImage.addEventListener('load', function (event) {
var src = event.target.getAttribute('src');
if (_this3.loadedImages.indexOf(src) === -1) {
//is this condition even required... setting multiple times will not change usage...
_this3.loadedImages.push(src);
}
_this3.relatedElements[index].dispatchEvent(new Event('nextImageLoaded.' + _this3.eventNamespace));
});
nextImage.setAttribute('src', this.relatedElements[next].getAttribute(this.options.sourceAttr));
prevImage.addEventListener('load', function (event) {
var src = event.target.getAttribute('src');
if (_this3.loadedImages.indexOf(src) === -1) {
_this3.loadedImages.push(src);
}
_this3.relatedElements[index].dispatchEvent(new Event('prevImageLoaded.' + _this3.eventNamespace));
});
prevImage.setAttribute('src', this.relatedElements[prev].getAttribute(this.options.sourceAttr));
}
}, {
key: "loadImage",
value: function loadImage(direction) {
var _this4 = this;
var slideDirection = direction;
if (this.options.rtl) {
direction = -direction;
}
this.relatedElements[this.currentImageIndex].dispatchEvent(new Event('change.' + this.eventNamespace));
this.relatedElements[this.currentImageIndex].dispatchEvent(new Event((direction === 1 ? 'next' : 'prev') + '.' + this.eventNamespace));
var newIndex = this.currentImageIndex + direction;
if (this.isAnimating || (newIndex < 0 || newIndex >= this.relatedElements.length) && this.options.loop === false) {
return false;
}
this.currentImageIndex = newIndex < 0 ? this.relatedElements.length - 1 : newIndex > this.relatedElements.length - 1 ? 0 : newIndex;
this.domNodes.counter.querySelector('.sl-current').innerHTML = this.currentImageIndex + 1;
if (this.options.animationSlide) {
this.slide(this.options.animationSpeed / 1000, -100 * slideDirection - this.controlCoordinates.swipeDiff + 'px');
}
this.fadeOut(this.domNodes.image, 300, function () {
_this4.isAnimating = true;
setTimeout(function () {
var element = _this4.relatedElements[_this4.currentImageIndex];
_this4.currentImage.setAttribute('src', element.getAttribute(_this4.options.sourceAttr));
if (_this4.loadedImages.indexOf(element.getAttribute(_this4.options.sourceAttr)) === -1) {
_this4.show(_this4.domNodes.spinner);
}
if (_this4.domNodes.image.contains(_this4.domNodes.caption)) {
_this4.domNodes.image.removeChild(_this4.domNodes.caption);
}
_this4.adjustImage(slideDirection);
if (_this4.options.preloading) _this4.preload();
}, 100);
});
}
}, {
key: "adjustImage",
value: function adjustImage(direction) {
var _this5 = this;
if (!this.currentImage) {
return false;
}
var tmpImage = new Image(),
windowWidth = window.innerWidth * this.options.widthRatio,
windowHeight = window.innerHeight * this.options.heightRatio;
tmpImage.setAttribute('src', this.currentImage.getAttribute('src'));
this.currentImage.dataset.scale = 1;
this.currentImage.dataset.translateX = 0;
this.currentImage.dataset.translateY = 0;
this.zoomPanElement(0, 0, 1);
tmpImage.addEventListener('error', function (event) {
_this5.relatedElements[_this5.currentImageIndex].dispatchEvent(new Event('error.' + _this5.eventNamespace));
_this5.isAnimating = false;
_this5.isOpen = false;
_this5.domNodes.spinner.style.display = 'none';
var dirIsDefined = direction === 1 || direction === -1;
if (_this5.initialImageIndex === _this5.currentImageIndex && dirIsDefined) {
return _this5.close();
}
if (_this5.options.alertError) {
alert(_this5.options.alertErrorMessage);
}
_this5.loadImage(dirIsDefined ? direction : 1);
});
tmpImage.addEventListener('load', function (event) {
if (typeof direction !== 'undefined') {
_this5.relatedElements[_this5.currentImageIndex].dispatchEvent(new Event('changed.' + _this5.eventNamespace));
_this5.relatedElements[_this5.currentImageIndex].dispatchEvent(new Event((direction === 1 ? 'nextDone' : 'prevDone') + '.' + _this5.eventNamespace));
} // history
if (_this5.options.history) {
_this5.updateURL();
}
if (_this5.loadedImages.indexOf(_this5.currentImage.getAttribute('src')) === -1) {
_this5.loadedImages.push(_this5.currentImage.getAttribute('src'));
}
var imageWidth = event.target.width,
imageHeight = event.target.height;
if (_this5.options.scaleImageToRatio || imageWidth > windowWidth || imageHeight > windowHeight) {
var ratio = imageWidth / imageHeight > windowWidth / windowHeight ? imageWidth / windowWidth : imageHeight / windowHeight;
imageWidth /= ratio;
imageHeight /= ratio;
}
_this5.domNodes.image.style.top = (window.innerHeight - imageHeight) / 2 + 'px';
_this5.domNodes.image.style.left = (window.innerWidth - imageWidth - _this5.globalScrollbarWidth) / 2 + 'px';
_this5.domNodes.image.style.width = imageWidth + 'px';
_this5.domNodes.image.style.height = imageHeight + 'px';
_this5.domNodes.spinner.style.display = 'none';
_this5.fadeIn(_this5.currentImage, 300);
_this5.isOpen = true;
var captionContainer = _this5.options.captionSelector === 'self' ? _this5.relatedElements[_this5.currentImageIndex] : _this5.relatedElements[_this5.currentImageIndex].querySelector(_this5.options.captionSelector),
captionText;
if (_this5.options.captions && captionContainer) {
if (_this5.options.captionType === 'data') {
captionText = captionContainer.dataset[_this5.options.captionsData];
} else if (_this5.options.captionType === 'text') {
captionText = captionContainer.innerHTML;
} else {
captionText = captionContainer.getAttribute(_this5.options.captionsData);
}
}
if (!_this5.options.loop) {
if (_this5.currentImageIndex === 0) {
_this5.hide(_this5.domNodes.navigation.querySelector('.sl-prev'));
}
if (_this5.currentImageIndex >= _this5.relatedElements.length - 1) {
_this5.hide(_this5.domNodes.navigation.querySelector('.sl-next'));
}
if (_this5.currentImageIndex > 0) {
_this5.show(_this5.domNodes.navigation.querySelector('.sl-prev'));
}
if (_this5.currentImageIndex < _this5.relatedElements.length - 1) {
_this5.show(_this5.domNodes.navigation.querySelector('.sl-next'));
}
}
if (_this5.relatedElements.length === 1) {
_this5.hide(_this5.domNodes.navigation.querySelectorAll('.sl-prev, .sl-next'));
} else {
_this5.show(_this5.domNodes.navigation.querySelectorAll('.sl-prev, .sl-next'));
}
if (direction === 1 || direction === -1) {
if (_this5.options.animationSlide) {
_this5.slide(0, 100 * direction + 'px');
setTimeout(function () {
_this5.slide(_this5.options.animationSpeed / 1000, 0 + 'px');
}, 50);
}
_this5.fadeIn(_this5.domNodes.image, 300, function () {
_this5.isAnimating = false;
_this5.setCaption(captionText, imageWidth);
});
} else {
_this5.isAnimating = false;
_this5.setCaption(captionText, imageWidth);
}
if (_this5.options.additionalHtml && !_this5.domNodes.additionalHtml) {
_this5.domNodes.additionalHtml = document.createElement('div');
_this5.domNodes.additionalHtml.classList.add('sl-additional-html');
_this5.domNodes.additionalHtml.innerHTML = _this5.options.additionalHtml;
_this5.domNodes.image.appendChild(_this5.domNodes.additionalHtml);
}
});
}
}, {
key: "zoomPanElement",
value: function zoomPanElement(targetOffsetX, targetOffsetY, targetScale) {
this.currentImage.style[this.transitionPrefix + 'transform'] = 'translate(' + targetOffsetX + ',' + targetOffsetY + ') scale(' + targetScale + ')';
}
}, {
key: "minMax",
value: function minMax(value, min, max) {
return value < min ? min : value > max ? max : value;
}
}, {
key: "setZoomData",
value: function setZoomData(initialScale, targetOffsetX, targetOffsetY) {
this.currentImage.dataset.scale = initialScale;
this.currentImage.dataset.translateX = targetOffsetX;
this.currentImage.dataset.translateY = targetOffsetY;
}
}, {
key: "hashchangeHandler",
value: function hashchangeHandler() {
if (this.isOpen && this.hash === this.initialLocationHash) {
this.hashReseted = true;
this.close();
}
}
}, {
key: "addEvents",
value: function addEvents() {
var _this6 = this;
// resize/responsive
this.addEventListener(window, 'resize.' + this.eventNamespace, function (event) {
//this.adjustImage.bind(this)
if (_this6.isOpen) {
_this6.adjustImage();
}
});
this.addEventListener(this.domNodes.closeButton, ['click.' + this.eventNamespace, 'touchstart.' + this.eventNamespace], this.close.bind(this));
if (this.options.history) {
setTimeout(function () {
_this6.addEventListener(window, 'hashchange.' + _this6.eventNamespace, function (event) {
if (_this6.isOpen) {
_this6.hashchangeHandler();
}
});
}, 40);
}
this.addEventListener(this.domNodes.navigation.getElementsByTagName('button'), 'click.' + this.eventNamespace, function (event) {
if (!event.currentTarget.tagName.match(/button/i)) {
return true;
}
event.preventDefault();
_this6.controlCoordinates.swipeDiff = 0;
_this6.loadImage(event.currentTarget.classList.contains('sl-next') ? 1 : -1);
});
this.addEventListener(this.domNodes.image, ['touchstart.' + this.eventNamespace, 'mousedown.' + this.eventNamespace], function (event) {
if (event.target.tagName === 'A' && event.type === 'touchstart') {
return true;
}
if (event.type === 'mousedown') {
_this6.controlCoordinates.initialPointerOffsetX = event.clientX;
_this6.controlCoordinates.initialPointerOffsetY = event.clientY;
_this6.controlCoordinates.containerHeight = _this6.getDimensions(_this6.domNodes.image).height;
_this6.controlCoordinates.containerWidth = _this6.getDimensions(_this6.domNodes.image).width;
_this6.controlCoordinates.imgHeight = _this6.getDimensions(_this6.currentImage).height;
_this6.controlCoordinates.imgWidth = _this6.getDimensions(_this6.currentImage).width;
_this6.controlCoordinates.containerOffsetX = _this6.domNodes.image.offsetLeft;
_this6.controlCoordinates.containerOffsetY = _this6.domNodes.image.offsetTop;
_this6.controlCoordinates.initialOffsetX = parseFloat(_this6.currentImage.dataset.translateX);
_this6.controlCoordinates.initialOffsetY = parseFloat(_this6.currentImage.dataset.translateY);
_this6.controlCoordinates.capture = true;
} else {
_this6.controlCoordinates.touchCount = event.touches.length;
_this6.controlCoordinates.initialPointerOffsetX = event.touches[0].clientX;
_this6.controlCoordinates.initialPointerOffsetY = event.touches[0].clientY;
_this6.controlCoordinates.containerHeight = _this6.getDimensions(_this6.domNodes.image).height;
_this6.controlCoordinates.containerWidth = _this6.getDimensions(_this6.domNodes.image).width;
_this6.controlCoordinates.imgHeight = _this6.getDimensions(_this6.currentImage).height;
_this6.controlCoordinates.imgWidth = _this6.getDimensions(_this6.currentImage).width;
_this6.controlCoordinates.containerOffsetX = _this6.domNodes.image.offsetLeft;
_this6.controlCoordinates.containerOffsetY = _this6.domNodes.image.offsetTop;
if (_this6.controlCoordinates.touchCount === 1)
/* Single touch */
{
if (!_this6.controlCoordinates.doubleTapped) {
_this6.controlCoordinates.doubleTapped = true;
setTimeout(function () {
_this6.controlCoordinates.doubleTapped = false;
}, 300);
} else {
_this6.currentImage.classList.add('sl-transition');
if (!_this6.controlCoordinates.zoomed) {
_this6.controlCoordinates.initialScale = _this6.options.doubleTapZoom;
_this6.setZoomData(_this6.controlCoordinates.initialScale, 0, 0);
_this6.zoomPanElement(0 + "px", 0 + "px", _this6.controlCoordinates.initialScale);
if (!_this6.domNodes.caption.style.opacity && _this6.domNodes.caption.style.display !== 'none') {
_this6.fadeOut(_this6.domNodes.caption, 200);
}
_this6.controlCoordinates.zoomed = true;
} else {
_this6.controlCoordinates.initialScale = 1;
_this6.setZoomData(_this6.controlCoordinates.initialScale, 0, 0);
_this6.zoomPanElement(0 + "px", 0 + "px", _this6.controlCoordinates.initialScale);
_this6.controlCoordinates.zoomed = false;
}
setTimeout(function () {
if (_this6.currentImage) {
_this6.currentImage.classList.remove('sl-transition');
}
}, 200);
return false;
}
_this6.controlCoordinates.initialOffsetX = parseFloat(_this6.currentImage.dataset.translateX);
_this6.controlCoordinates.initialOffsetY = parseFloat(_this6.currentImage.dataset.translateY);
} else if (_this6.controlCoordinates.touchCount === 2)
/* Pinch */
{
_this6.controlCoordinates.initialPointerOffsetX2 = event.touches[1].clientX;
_this6.controlCoordinates.initialPointerOffsetY2 = event.touches[1].clientY;
_this6.controlCoordinates.initialOffsetX = parseFloat(_this6.currentImage.dataset.translateX);
_this6.controlCoordinates.initialOffsetY = parseFloat(_this6.currentImage.dataset.translateY);
_this6.controlCoordinates.pinchOffsetX = (_this6.controlCoordinates.initialPointerOffsetX + _this6.controlCoordinates.initialPointerOffsetX2) / 2;
_this6.controlCoordinates.pinchOffsetY = (_this6.controlCoordinates.initialPointerOffsetY + _this6.controlCoordinates.initialPointerOffsetY2) / 2;
_this6.controlCoordinates.initialPinchDistance = Math.sqrt((_this6.controlCoordinates.initialPointerOffsetX - _this6.controlCoordinates.initialPointerOffsetX2) * (_this6.controlCoordinates.initialPointerOffsetX - _this6.controlCoordinates.initialPointerOffsetX2) + (_this6.controlCoordinates.initialPointerOffsetY - _this6.controlCoordinates.initialPointerOffsetY2) * (_this6.controlCoordinates.initialPointerOffsetY - _this6.controlCoordinates.initialPointerOffsetY2));
}
_this6.controlCoordinates.capture = true;
}
if (_this6.controlCoordinates.mousedown) return true;
if (_this6.transitionCapable) {
_this6.controlCoordinates.imageLeft = parseInt(_this6.domNodes.image.style.left, 10);
}
_this6.controlCoordinates.mousedown = true;
_this6.controlCoordinates.swipeDiff = 0;
_this6.controlCoordinates.swipeYDiff = 0;
_this6.controlCoordinates.swipeStart = event.pageX || event.touches[0].pageX;
_this6.controlCoordinates.swipeYStart = event.pageY || event.touches[0].pageY;
return false;
});
this.addEventListener(this.domNodes.image, ['touchmove.' + this.eventNamespace, 'mousemove.' + this.eventNamespace, 'MSPointerMove'], function (event) {
if (!_this6.controlCoordinates.mousedown) {
return true;
}
event.preventDefault();
if (event.type === 'touchmove') {
if (_this6.controlCoordinates.capture === false) {
return false;
}
_this6.controlCoordinates.pointerOffsetX = event.touches[0].clientX;
_this6.controlCoordinates.pointerOffsetY = event.touches[0].clientY;
_this6.controlCoordinates.touchCount = event.touches.length;
_this6.controlCoordinates.touchmoveCount++;
if (_this6.controlCoordinates.touchCount > 1)
/* Pinch */
{
_this6.controlCoordinates.pointerOffsetX2 = event.touches[1].clientX;
_this6.controlCoordinates.pointerOffsetY2 = event.touches[1].clientY;
_this6.controlCoordinates.targetPinchDistance = Math.sqrt((_this6.controlCoordinates.pointerOffsetX - _this6.controlCoordinates.pointerOffsetX2) * (_this6.controlCoordinates.pointerOffsetX - _this6.controlCoordinates.pointerOffsetX2) + (_this6.controlCoordinates.pointerOffsetY - _this6.controlCoordinates.pointerOffsetY2) * (_this6.controlCoordinates.pointerOffsetY - _this6.controlCoordinates.pointerOffsetY2));
if (_this6.controlCoordinates.initialPinchDistance === null) {
_this6.controlCoordinates.initialPinchDistance = _this6.controlCoordinates.targetPinchDistance;
}
if (Math.abs(_this6.controlCoordinates.initialPinchDistance - _this6.controlCoordinates.targetPinchDistance) >= 1) {
/* Initialize helpers */
_this6.controlCoordinates.targetScale = _this6.minMax(_this6.controlCoordinates.targetPinchDistance / _this6.controlCoordinates.initialPinchDistance * _this6.controlCoordinates.initialScale, 1, _this6.options.maxZoom);
_this6.controlCoordinates.limitOffsetX = (_this6.controlCoordinates.imgWidth * _this6.controlCoordinates.targetScale - _this6.controlCoordinates.containerWidth) / 2;
_this6.controlCoordinates.limitOffsetY = (_this6.controlCoordinates.imgHeight * _this6.controlCoordinates.targetScale - _this6.controlCoordinates.containerHeight) / 2;
_this6.controlCoordinates.scaleDifference = _this6.controlCoordinates.targetScale - _this6.controlCoordinates.initialScale;
_this6.controlCoordinates.targetOffsetX = _this6.controlCoordinates.imgWidth * _this6.controlCoordinates.targetScale <= _this6.controlCoordinates.containerWidth ? 0 : _this6.minMax(_this6.controlCoordinates.initialOffsetX - (_this6.controlCoordinates.pinchOffsetX - _this6.controlCoordinates.containerOffsetX - _this6.controlCoordinates.containerWidth / 2 - _this6.controlCoordinates.initialOffsetX) / (_this6.controlCoordinates.targetScale - _this6.controlCoordinates.scaleDifference) * _this6.controlCoordinates.scaleDifference, _this6.controlCoordinates.limitOffsetX * -1, _this6.controlCoordinates.limitOffsetX);
_this6.controlCoordinates.targetOffsetY = _this6.controlCoordinates.imgHeight * _this6.controlCoordinates.targetScale <= _this6.controlCoordinates.containerHeight ? 0 : _this6.minMax(_this6.controlCoordinates.initialOffsetY - (_this6.controlCoordinates.pinchOffsetY - _this6.controlCoordinates.containerOffsetY - _this6.controlCoordinates.containerHeight / 2 - _this6.controlCoordinates.initialOffsetY) / (_this6.controlCoordinates.targetScale - _this6.controlCoordinates.scaleDifference) * _this6.controlCoordinates.scaleDifference, _this6.controlCoordinates.limitOffsetY * -1, _this6.controlCoordinates.limitOffsetY);
_this6.zoomPanElement(_this6.controlCoordinates.targetOffsetX + "px", _this6.controlCoordinates.targetOffsetY + "px", _this6.controlCoordinates.targetScale);
if (_this6.controlCoordinates.targetScale > 1) {
_this6.controlCoordinates.zoomed = true;
if (!_this6.domNodes.caption.style.opacity && _this6.domNodes.caption.style.display !== 'none') {
_this6.fadeOut(_this6.domNodes.caption, 200);
}
}
_this6.controlCoordinates.initialPinchDistance = _this6.controlCoordinates.targetPinchDistance;
_this6.controlCoordinates.initialScale = _this6.controlCoordinates.targetScale;
_this6.controlCoordinates.initialOffsetX = _this6.controlCoordinates.targetOffsetX;
_this6.controlCoordinates.initialOffsetY = _this6.controlCoordinates.targetOffsetY;
}
} else {
_this6.controlCoordinates.targetScale = _this6.controlCoordinates.initialScale;
_this6.controlCoordinates.limitOffsetX = (_this6.controlCoordinates.imgWidth * _this6.controlCoordinates.targetScale - _this6.controlCoordinates.containerWidth) / 2;
_this6.controlCoordinates.limitOffsetY = (_this6.controlCoordinates.imgHeight * _this6.controlCoordinates.targetScale - _this6.controlCoordinates.containerHeight) / 2;
_this6.controlCoordinates.targetOffsetX = _this6.controlCoordinates.imgWidth * _this6.controlCoordinates.targetScale <= _this6.controlCoordinates.containerWidth ? 0 : _this6.minMax(_this6.controlCoordinates.pointerOffsetX - (_this6.controlCoordinates.initialPointerOffsetX - _this6.controlCoordinates.initialOffsetX), _this6.controlCoordinates.limitOffsetX * -1, _this6.controlCoordinates.limitOffsetX);
_this6.controlCoordinates.targetOffsetY = _this6.controlCoordinates.imgHeight * _this6.controlCoordinates.targetScale <= _this6.controlCoordinates.containerHeight ? 0 : _this6.minMax(_this6.controlCoordinates.pointerOffsetY - (_this6.controlCoordinates.initialPointerOffsetY - _this6.controlCoordinates.initialOffsetY), _this6.controlCoordinates.limitOffsetY * -1, _this6.controlCoordinates.limitOffsetY);
if (Math.abs(_this6.controlCoordinates.targetOffsetX) === Math.abs(_this6.controlCoordinates.limitOffsetX)) {
_this6.controlCoordinates.initialOffsetX = _this6.controlCoordinates.targetOffsetX;
_this6.controlCoordinates.initialPointerOffsetX = _this6.controlCoordinates.pointerOffsetX;
}
if (Math.abs(_this6.controlCoordinates.targetOffsetY) === Math.abs(_this6.controlCoordinates.limitOffsetY)) {
_this6.controlCoordinates.initialOffsetY = _this6.controlCoordinates.targetOffsetY;
_this6.controlCoordinates.initialPointerOffsetY = _this6.controlCoordinates.pointerOffsetY;
}
_this6.setZoomData(_this6.controlCoordinates.initialScale, _this6.controlCoordinates.targetOffsetX, _this6.controlCoordinates.targetOffsetY);
_this6.zoomPanElement(_this6.controlCoordinates.targetOffsetX + "px", _this6.controlCoordinates.targetOffsetY + "px", _this6.controlCoordinates.targetScale);
}
}
/* Mouse Move implementation */
if (event.type === 'mousemove' && _this6.controlCoordinates.mousedown) {
if (event.type == 'touchmove') return true;
if (_this6.controlCoordinates.capture === false) return false;
_this6.controlCoordinates.pointerOffsetX = event.clientX;
_this6.controlCoordinates.pointerOffsetY = event.clientY;
_this6.controlCoordinates.targetScale = _this6.controlCoordinates.initialScale;
_this6.controlCoordinates.limitOffsetX = (_this6.controlCoordinates.imgWidth * _this6.controlCoordinates.targetScale - _this6.controlCoordinates.containerWidth) / 2;
_this6.controlCoordinates.limitOffsetY = (_this6.controlCoordinates.imgHeight * _this6.controlCoordinates.targetScale - _this6.controlCoordinates.containerHeight) / 2;
_this6.controlCoordinates.targetOffsetX = _this6.controlCoordinates.imgWidth * _this6.controlCoordinates.targetScale <= _this6.controlCoordinates.containerWidth ? 0 : _this6.minMax(_this6.controlCoordinates.pointerOffsetX - (_this6.controlCoordinates.initialPointerOffsetX - _this6.controlCoordinates.initialOffsetX), _this6.controlCoordinates.limitOffsetX * -1, _this6.controlCoordinates.limitOffsetX);
_this6.controlCoordinates.targetOffsetY = _this6.controlCoordinates.imgHeight * _this6.controlCoordinates.targetScale <= _this6.controlCoordinates.containerHeight ? 0 : _this6.minMax(_this6.controlCoordinates.pointerOffsetY - (_this6.controlCoordinates.initialPointerOffsetY - _this6.controlCoordinates.initialOffsetY), _this6.controlCoordinates.limitOffsetY * -1, _this6.controlCoordinates.limitOffsetY);
if (Math.abs(_this6.controlCoordinates.targetOffsetX) === Math.abs(_this6.controlCoordinates.limitOffsetX)) {
_this6.controlCoordinates.initialOffsetX = _this6.controlCoordinates.targetOffsetX;
_this6.controlCoordinates.initialPointerOffsetX = _this6.controlCoordinates.pointerOffsetX;
}
if (Math.abs(_this6.controlCoordinates.targetOffsetY) === Math.abs(_this6.controlCoordinates.limitOffsetY)) {
_this6.controlCoordinates.initialOffsetY = _this6.controlCoordinates.targetOffsetY;
_this6.controlCoordinates.initialPointerOffsetY = _this6.controlCoordinates.pointerOffsetY;
}
_this6.setZoomData(_this6.controlCoordinates.initialScale, _this6.controlCoordinates.targetOffsetX, _this6.controlCoordinates.targetOffsetY);
_this6.zoomPanElement(_this6.controlCoordinates.targetOffsetX + "px", _this6.controlCoordinates.targetOffsetY + "px", _this6.controlCoordinates.targetScale);
}
if (!_this6.controlCoordinates.zoomed) {
_this6.controlCoordinates.swipeEnd = event.pageX || event.touches[0].pageX;
_this6.controlCoordinates.swipeYEnd = event.pageY || event.touches[0].pageY;
_this6.controlCoordinates.swipeDiff = _this6.controlCoordinates.swipeStart - _this6.controlCoordinates.swipeEnd;
_this6.controlCoordinates.swipeYDiff = _this6.controlCoordinates.swipeYStart - _this6.controlCoordinates.swipeYEnd;
if (_this6.options.animationSlide) {
_this6.slide(0, -_this6.controlCoordinates.swipeDiff + 'px');
}
}
});
this.addEventListener(this.domNodes.image, ['touchend.' + this.eventNamespace, 'mouseup.' + this.eventNamespace, 'touchcancel.' + this.eventNamespace, 'mouseleave.' + this.eventNamespace, 'pointerup', 'pointercancel', 'MSPointerUp', 'MSPointerCancel'], function (event) {
if (_this6.isTouchDevice && event.type === 'touchend') {
_this6.controlCoordinates.touchCount = event.touches.length;
if (_this6.controlCoordinates.touchCount === 0)
/* No touch */
{
/* Set attributes */
_this6.setZoomData(_this6.controlCoordinates.initialScale, _this6.controlCoordinates.targetOffsetX, _this6.controlCoordinates.targetOffsetY);
if (_this6.controlCoordinates.initialScale === 1) {
_this6.controlCoordinates.zoomed = false;
if (_this6.domNodes.caption.style.display === 'none') {
_this6.fadeIn(_this6.domNodes.caption, 200);
}
}
_this6.controlCoordinates.initialPinchDistance = null;
_this6.controlCoordinates.capture = false;
} else if (_this6.controlCoordinates.touchCount === 1)
/* Single touch */
{
_this6.controlCoordinates.initialPointerOffsetX = event.touches[0].clientX;
_this6.controlCoordinates.initialPointerOffsetY = event.touches[0].clientY;
} else if (_this6.controlCoordinates.touchCount > 1)
/* Pinch */
{
_this6.controlCoordinates.initialPinchDistance = null;
}
}
if (_this6.controlCoordinates.mousedown) {
_this6.controlCoordinates.mousedown = false;
var possibleDir = true;
if (!_this6.options.loop) {
if (_this6.currentImageIndex === 0 && _this6.controlCoordinates.swipeDiff < 0) {
possibleDir = false;
}
if (_this6.currentImageIndex >= _this6.relatedElements.length - 1 && _this6.controlCoordinates.swipeDiff > 0) {
possibleDir = false;
}
}
if (Math.abs(_this6.controlCoordinates.swipeDiff) > _this6.options.swipeTolerance && possibleDir) {
_this6.loadImage(_this6.controlCoordinates.swipeDiff > 0 ? 1 : -1);
} else if (_this6.options.animationSlide) {
_this6.slide(_this6.options.animationSpeed / 1000, 0 + 'px');
}
if (_this6.options.swipeClose && Math.abs(_this6.controlCoordinates.swipeYDiff) > 50 && Math.abs(_this6.controlCoordinates.swipeDiff) < _this6.options.swipeTolerance) {
_this6.close();
}
}
});
this.addEventListener(this.domNodes.image, ['dblclick'], function (event) {
if (_this6.isTouchDevice) return;
_this6.controlCoordinates.initialPointerOffsetX = event.clientX;
_this6.controlCoordinates.initialPointerOffsetY = event.clientY;
_this6.controlCoordinates.containerHeight = _this6.getDimensions(_this6.domNodes.image).height;
_this6.controlCoordinates.containerWidth = _this6.getDimensions(_this6.domNodes.image).width;
_this6.controlCoordinates.imgHeight = _this6.getDimensions(_this6.currentImage).height;
_this6.controlCoordinates.imgWidth = _this6.getDimensions(_this6.currentImage).width;
_this6.controlCoordinates.containerOffsetX = _this6.domNodes.image.offsetLeft;
_this6.controlCoordinates.containerOffsetY = _this6.domNodes.image.offsetTop;
_this6.currentImage.classList.add('sl-transition');
if (!_this6.controlCoordinates.zoomed) {
_this6.controlCoordinates.initialScale = _this6.options.doubleTapZoom;
_this6.setZoomData(_this6.controlCoordinates.initialScale, 0, 0);
_this6.zoomPanElement(0 + "px", 0 + "px", _this6.controlCoordinates.initialScale);
if (!_this6.domNodes.caption.style.opacity && _this6.domNodes.caption.style.display !== 'none') {
_this6.fadeOut(_this6.domNodes.caption, 200);
}
_this6.controlCoordinates.zoomed = true;
} else {
_this6.controlCoordinates.initialScale = 1;
_this6.setZoomData(_this6.controlCoordinates.initialScale, 0, 0);
_this6.zoomPanElement(0 + "px", 0 + "px", _this6.controlCoordinates.initialScale);
_this6.controlCoordinates.zoomed = false;
if (_this6.domNodes.caption.style.display === 'none') {
_this6.fadeIn(_this6.domNodes.caption, 200);
}
}
setTimeout(function () {
if (_this6.currentImage) {
_this6.currentImage.classList.remove('sl-transition');
}
}, 200);
_this6.controlCoordinates.capture = true;
return false;
});
}
}, {
key: "getDimensions",
value: function getDimensions(element) {
var styles = window.getComputedStyle(element),
height = element.offsetHeight,
width = element.offsetWidth,
borderTopWidth = parseFloat(styles.borderTopWidth),
borderBottomWidth = parseFloat(styles.borderBottomWidth),
paddingTop = parseFloat(styles.paddingTop),
paddingBottom = parseFloat(styles.paddingBottom),
borderLeftWidth = parseFloat(styles.borderLeftWidth),
borderRightWidth = parseFloat(styles.borderRightWidth),
paddingLeft = parseFloat(styles.paddingLeft),
paddingRight = parseFloat(styles.paddingRight);
return {
height: height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom,
width: width - borderLeftWidth - borderRightWidth - paddingLeft - paddingRight
};
}
}, {
key: "updateHash",
value: function updateHash() {
var newHash = 'pid=' + (this.currentImageIndex + 1),
newURL = window.location.href.split('#')[0] + '#' + newHash;
this.hashReseted = false;
if (this.pushStateSupport) {
window.history[this.historyHasChanges ? 'replaceState' : 'pushState']('', document.title, newURL);
} else {
// what is the browser target of this?
if (this.historyHasChanges) {
window.location.replace(newURL);
} else {
window.location.hash = newHash;
}
}
if (!this.historyHasChanges) {
this.urlChangedOnce = true;
}
this.historyHasChanges = true;
}
}, {
key: "resetHash",
value: function resetHash() {
this.hashReseted = true;
if (this.urlChangedOnce) {
history.back();
} else {
if (this.pushStateSupport) {
history.pushState('', document.title, window.location.pathname + window.location.search);
} else {
window.location.hash = '';
}
} //
//in case an history operation is still pending
clearTimeout(this.historyUpdateTimeout);
}
}, {
key: "updateURL",
value: function updateURL() {
clearTimeout(this.historyUpdateTimeout);
if (!this.historyHasChanges) {
this.updateHash(); // first time
} else {
this.historyUpdateTimeout = setTimeout(this.updateHash.bind(this), 800);
}
}
}, {
key: "setCaption",
value: function setCaption(captionText, imageWidth) {
var _this7 = this;
if (this.options.captions && captionText && captionText !== '' && typeof captionText !== "undefined") {
this.hide(this.domNodes.caption);
this.domNodes.caption.style.width = imageWidth + 'px';
this.domNodes.caption.innerHTML = captionText;
this.domNodes.image.appendChild(this.domNodes.caption);
setTimeout(function () {
_this7.fadeIn(_this7.domNodes.caption, 300);
}, this.options.captionDelay);
}
}
}, {
key: "slide",
value: function slide(speed, pos) {
if (!this.transitionCapable) {
return this.domNodes.image.style.left = pos;
}
this.domNodes.image.style[this.transitionPrefix + 'transform'] = 'translateX(' + pos + ')';
this.domNodes.image.style[this.transitionPrefix + 'transition'] = this.transitionPrefix + 'transform ' + speed + 's linear';
}
}, {
key: "getRelated",
value: function getRelated(rel) {
var elems;
if (rel && rel !== false && rel !== 'nofollow') {
elems = Array.from(this.elements).filter(function (element) {
return element.getAttribute('rel') === rel;
});
} else {
elems = this.elements;
}
return elems;
}
}, {
key: "openImage",
value: function openImage(element) {
var _this8 = this;
element.dispatchEvent(new Event('show.' + this.eventNamespace));
if (this.options.disableScroll) {
this.globalScrollbarWidth = this.toggleScrollbar('hide');
}
if (this.options.htmlClass && this.options.htmlClass !== '') {
document.querySelector('html').classList.add(this.options.htmlClass);
}
document.body.appendChild(this.domNodes.wrapper);
this.domNodes.wrapper.appendChild(this.domNodes.image);
if (this.options.overlay) {
document.body.appendChild(this.domNodes.overlay);
}
this.relatedElements = this.getRelated(element.rel);
if (this.options.showCounter) {
if (this.relatedElements.length == 1 && this.domNodes.wrapper.contains(this.domNodes.counter)) {
this.domNodes.wrapper.removeChild(this.domNodes.counter);
} else if (this.relatedElements.length > 1 && !this.domNodes.wrapper.contains(this.domNodes.counter)) {
this.domNodes.wrapper.appendChild(this.domNodes.counter);
}
}
this.isAnimating = true;
this.currentImageIndex = this.relatedElements.indexOf(element);
var targetURL = element.getAttribute(this.options.sourceAttr);
this.currentImage = document.createElement('img');
this.currentImage.style.display = 'none';
this.currentImage.setAttribute('src', targetURL);
this.currentImage.dataset.scale = 1;
this.currentImage.dataset.translateX = 0;
this.currentImage.dataset.translateY = 0;
if (this.loadedImages.indexOf(targetURL) === -1) {
this.loadedImages.push(targetURL);
}
this.domNodes.image.innerHTML = '';
this.domNodes.image.setAttribute('style', '');
this.domNodes.image.appendChild(this.currentImage);
this.fadeIn(this.domNodes.overlay, 300);
this.fadeIn([this.domNodes.counter, this.domNodes.navigation, this.domNodes.closeButton], 300);
this.show(this.domNodes.spinner);
this.domNodes.counter.querySelector('.sl-current').innerHTML = this.currentImageIndex + 1;
this.domNodes.counter.querySelector('.sl-total').innerHTML = this.relatedElements.length;
this.adjustImage();
if (this.options.preloading) {
this.preload();
}
setTimeout(function () {
element.dispatchEvent(new Event('shown.' + _this8.eventNamespace));
}, this.options.animationSpeed);
} // utility
}, {
key: "addEventListener",
value: function addEventListener(elements, events, callback, opts) {
elements = this.wrap(elements);
events = this.wrap(events);
var _iterator = _createForOfIteratorHelper(elements),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var element = _step.value;
if (!element.namespaces) {
element.namespaces = {};
} // save the namespaces addEventListener the DOM element itself
var _iterator2 = _createForOfIteratorHelper(events),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var event = _step2.value;
var options = opts || false;
element.namespaces[event] = callback;
element.addEventListener(event.split('.')[0], callback, options);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
}, {
key: "removeEventListener",
value: function removeEventListener(elements, events) {
elements = this.wrap(elements);
events = this.wrap(events);
var _iterator3 = _createForOfIteratorHelper(elements),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var element = _step3.value;
var _iterator4 = _createForOfIteratorHelper(events),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var event = _step4.value;
element.removeEventListener(event.split('.')[0], element.namespaces[event]);
delete element.namespaces[event];
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
}, {
key: "fadeOut",
value: function fadeOut(elements, duration, callback) {
var _this9 = this;
elements = this.wrap(elements);
var _iterator5 = _createForOfIteratorHelper(elements),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var element = _step5.value;
element.style.opacity = 1;
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
var step = 16.66666 / (duration || 300),
fade = function fade() {
var currentOpacity = parseFloat(elements[0].style.opacity);
if ((currentOpacity -= step) < 0) {
var _iterator6 = _createForOfIteratorHelper(elements),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var element = _step6.value;
element.style.display = "none";
element.style.opacity = '';
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
callback && callback.call(_this9, elements);
} else {
var _iterator7 = _createForOfIteratorHelper(elements),
_step7;
try {
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
var _element = _step7.value;
_element.style.opacity = currentOpacity;
}
} catch (err) {
_iterator7.e(err);
} finally {
_iterator7.f();
}
requestAnimationFrame(fade);
}
};
fade();
}
}, {
key: "fadeIn",
value: function fadeIn(elements, duration, callback, display) {
var _this10 = this;
elements = this.wrap(elements);
var _iterator8 = _createForOfIteratorHelper(elements),
_step8;
try {
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
var element = _step8.value;
element.style.opacity = 0;
element.style.display = display || "block";
}
} catch (err) {
_iterator8.e(err);
} finally {
_iterator8.f();
}
var opacityTarget = parseFloat(elements[0].dataset.opacityTarget || 1),
step = 16.66666 * opacityTarget / (duration || 300),
fade = function fade() {
var currentOpacity = parseFloat(elements[0].style.opacity);
if (!((currentOpacity += step) > opacityTarget)) {
var _iterator9 = _createForOfIteratorHelper(elements),
_step9;
try {
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
var element = _step9.value;
element.style.opacity = currentOpacity;
}
} catch (err) {
_iterator9.e(err);
} finally {
_iterator9.f();
}
requestAnimationFrame(fade);
} else {
var _iterator10 = _createForOfIteratorHelper(elements),
_step10;
try {
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
var _element2 = _step10.value;
_element2.style.opacity = '';
}
} catch (err) {
_iterator10.e(err);
} finally {
_iterator10.f();
}
callback && callback.call(_this10, elements);
}
};
fade();
}
}, {
key: "hide",
value: function hide(elements) {
elements = this.wrap(elements);
var _iterator11 = _createForOfIteratorHelper(elements),
_step11;
try {
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
var element = _step11.value;
element.dataset.initialDisplay = element.style.display;
element.style.display = 'none';
}
} catch (err) {
_iterator11.e(err);
} finally {
_iterator11.f();
}
}
}, {
key: "show",
value: function show(elements, display) {
elements = this.wrap(elements);
var _iterator12 = _createForOfIteratorHelper(elements),
_step12;
try {
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
var element = _step12.value;
element.style.display = element.dataset.initialDisplay || display || 'block';
}
} catch (err) {
_iterator12.e(err);
} finally {
_iterator12.f();
}
}
}, {
key: "wrap",
value: function wrap(input) {
return typeof input[Symbol.iterator] === 'function' && typeof input !== 'string' ? input : [input];
}
}, {
key: "on",
value: function on(events, callback) {
events = this.wrap(events);
var _iterator13 = _createForOfIteratorHelper(this.elements),
_step13;
try {
for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
var element = _step13.value;
if (!element.fullyNamespacedEvents) {
element.fullyNamespacedEvents = {};
}
var _iterator14 = _createForOfIteratorHelper(events),
_step14;
try {
for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
var event = _step14.value;
element.fullyNamespacedEvents[event] = callback;
element.addEventListener(event, callback);
}
} catch (err) {
_iterator14.e(err);
} finally {
_iterator14.f();
}
}
} catch (err) {
_iterator13.e(err);
} finally {
_iterator13.f();
}
return this;
}
}, {
key: "off",
value: function off(events) {
events = this.wrap(events);
var _iterator15 = _createForOfIteratorHelper(this.elements),
_step15;
try {
for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
var element = _step15.value;
var _iterator16 = _createForOfIteratorHelper(events),
_step16;
try {
for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
var event = _step16.value;
if (typeof element.fullyNamespacedEvents !== 'undefined' && event in element.fullyNamespacedEvents) {
element.removeEventListener(event, element.fullyNamespacedEvents[event]);
}
}
} catch (err) {
_iterator16.e(err);
} finally {
_iterator16.f();
}
}
} catch (err) {
_iterator15.e(err);
} finally {
_iterator15.f();
}
return this;
} // api
}, {
key: "open",
value: function open(elem) {
elem = elem || this.elements[0];
if (typeof jQuery !== "undefined" && elem instanceof jQuery) {
elem = elem.get(0);
}
this.initialImageIndex = this.elements.indexOf(elem);
if (this.initialImageIndex > -1) {
this.openImage(elem);
}
}
}, {
key: "next",
value: function next() {
this.loadImage(1);
}
}, {
key: "prev",
value: function prev() {
this.loadImage(-1);
} //close is exposed anyways..
}, {
key: "destroy",
value: function destroy() {
//remove all custom event listeners from elements
this.off(['close.' + this.eventNamespace, 'closed.' + this.eventNamespace, 'nextImageLoaded.' + this.eventNamespace, 'prevImageLoaded.' + this.eventNamespace, 'change.' + this.eventNamespace, 'nextDone.' + this.eventNamespace, 'prevDone.' + this.eventNamespace, 'error.' + this.eventNamespace, 'changed.' + this.eventNamespace, 'next.' + this.eventNamespace, 'prev.' + this.eventNamespace, 'show.' + this.eventNamespace, 'shown.' + this.eventNamespace]);
this.removeEventListener(this.elements, 'click.' + this.eventNamespace);
this.removeEventListener(document.body, 'contextmenu.' + this.eventNamespace);
this.removeEventListener(document.body, 'keyup.' + this.eventNamespace);
this.removeEventListener(this.domNodes.navigation.getElementsByTagName('button'), 'click.' + this.eventNamespace);
this.removeEventListener(this.domNodes.closeButton, 'click.' + this.eventNamespace);
this.removeEventListener(window, 'resize.' + this.eventNamespace);
this.removeEventListener(window, 'hashchange.' + this.eventNamespace);
this.close();
if (this.isOpen) {
document.body.removeChild(this.domNodes.wrapper);
document.body.removeChild(this.domNodes.overlay);
}
this.elements = null;
}
}, {
key: "refresh",
value: function refresh() {
if (!this.initialSelector) {
throw 'refreshing only works when you initialize using a selector!';
}
var options = this.options,
selector = this.initialSelector;
this.destroy();
this.constructor(selector, options);
return this;
}
}, {
key: "hash",
get: function get() {
return window.location.hash.substring(1);
}
}]);
return SimpleLightbox;
}();
(function ($, window, document, undefined) {
'use strict';
$.fn.simpleLightbox = function (options) {
return new SimpleLightbox(this.get(), options);
};
})(jQuery, window, document);
// nextgen-simple-light-box.js
jQuery(function($) {
var selector = null;
var lightbox = null;
var nextgen_simplebox_options = {
history: false,
animationSlide: false,
animationSpeed: 100,
captionSelector: 'self'
};
var nextgen_simplelightbox_init = function() {
selector = nextgen_lightbox_filter_selector($, $(".ngg-simplelightbox"));
if (selector.length > 0) {
lightbox = selector.simpleLightbox(nextgen_simplebox_options);
}
};
nextgen_simplelightbox_init();
$(window).on('refreshed', function() {
if (typeof lightbox !== 'undefined') {
lightbox.destroy();
}
selector = nextgen_lightbox_filter_selector($, $(".ngg-simplelightbox"));
if (selector.length > 0) {
lightbox = selector.simpleLightbox(nextgen_simplebox_options);
}
});
});
How To Add JavaScript Functions into WordPress
Assuming that the ‘Code Snippets’ plugin has already been installed, here’s a demonstration of adding a lightbox_context.js?ver=3.17
<?php
// closeout php to output JavaScript directly
?>
<script type="text/javascript">
function nextgen_lightbox_filter_selector($, selector)
{
if (nextgen_lightbox_settings && nextgen_lightbox_settings.context) {
var context = nextgen_lightbox_settings.context;
if (context == 'all_images') {
selector = selector.add($('a > img').parent());
}
else if (context == 'all_images_direct') {
selector = selector.add($('a[href] > img').parent()
.filter(function() {
var href = $(this).attr('href').toLowerCase();
var ext = href.substring(href.length - 3);
var ext2 = href.substring(href.length - 4);
return (ext == 'jpg' || ext == 'gif' || ext == 'png' || ext2 == 'tiff' || ext2 == 'jpeg' || ext2 == 'webp');
}));
}
else if (context == 'nextgen_and_wp_images') {
selector = selector.add($('a > img[class*="wp-image-"]').parent());
}
selector = selector.not('.gallery_link');
selector = selector.not('.use_imagebrowser_effect');
}
return selector;
};
</script>
WordPress Code Snippet Crashed My Site
Error Message:
ParseError thrown
syntax error, unexpected ‘$’, expecting variable (T_VARIABLE)
Resolution:
1. If still login to the site as Admin, call the safe-mode method via the site’s URL: https://kimconnect.com/wp-admin/admin.php?page=snippets&snippets-safe-mode=true
2. If Admin login session has expired or one cannot login add: define('CODE_SNIPPETS_SAFE_MODE', true);
to wp-config.php
WordPress Plugin to Customize How Posts are Displayed
A. Install the ‘Display Posts’ plugin
B. Install the ‘Code Snippets’ plugin
C. Add this code snippet
/**
* Display Posts, use first attached image
* @link https://displayposts.com/2019/10/16/display-image-from-post-content-if-no-featured-image/
*/
function be_dps_first_image( $output, $original_atts, $image, $title, $date, $excerpt, $inner_wrapper, $content, $class, $author, $category_display_text ) {
// Only run if image_size is set and no featured image
if( empty( $original_atts['image_size'] ) || !empty( $image ) )
return $output;
$images = new WP_Query( array(
'post_parent' => get_the_ID(),
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => 1,
'order' => 'ASC',
'fields' => 'ids',
));
if( !empty( $images->posts ) ) {
$image = '<a href="' . get_permalink() . '" class="image">' . wp_get_attachment_image( $images->posts[0], $original_atts['image_size'] ) . '</a>';
$output = '<' . $inner_wrapper . ' class="' . implode( ' ', $class ) . '">' . $image . $title . $date . $author . $category_display_text . $excerpt . $content . '</' . $inner_wrapper . '>';
}
return $output;
}
add_filter( 'display_posts_shortcode_output', 'be_dps_first_image', 10, 11 );
D. Add this CSS into Appearance > Customize > Additional CSS
.display-posts-listing.image-left .listing-item {
overflow: hidden;
margin-bottom: 32px;
width: 100%;
}
.display-posts-listing.image-left .image {
float: left;
margin: 0 16px 0 0;
}
.display-posts-listing.image-left .title {
display: block;
}
.display-posts-listing.image-left .excerpt-dash {
display: none;
}
WordPress NextGen Gallery Plugin Error
Error Message:
Failed to load plugin url: /bitnami/wordpress/wp-content/plugins/nextgen-gallery/products/photocrati_nextgen/modules/attach_to_post/static/ngg_attach_to_post_tinymce_plugin.js?ver=3.17
Resolution:
Although the root cause hasn’t been determined. This issue has automatically resolved when the running WordPress ‘container’ or ‘pod’ has been destroyed and recreated.
Posting this note here in case someone Googles similar error messages. Also, this maybe is a symptom of an unhealthy container in a pod.
PowerShell: Update Cryptocurrency Prices in WordPress WooCommerce
In the absence of true integrated plugins in WordPress to perform scripted actions (updating certain fields of a WooCommerce item page), here’s an improvised PowerShell script that performs this rudimentary function. This is a slight improvement over the method of manually updating prices of certain cryptocurrencies; although, this should only be considered an intermediary development before devising a much more robust method that could run ‘headless’ in Python rather than PowerShell. Better yet, direct database updates would be the final solution for best performance and security.
# updateCoinPrices.ps1
# version: 0.01
# $bitcoinUri='https://api.coinstats.app/public/v1/coins/bitcoin?currency=USD'
# $etherUri='https://api.coinstats.app/public/v1/coins/ethereum?currency=USD'
# $dogeUri='https://api.coinstats.app/public/v1/coins/dogecoin?currency=USD'
$coinName='nano'
$coinApi='https://api.coinstats.app/public/v1/coins/nano?currency=USD'
$coinPage='https://dragoncoin.com/wp-admin/post.php?post=3302&action=edit'
$username='SERVICEACCOUNTUSERNAMEHERE'
$password='SOMEVERYCOMPLEXPASSWORDHERE'
$expectedPageTitle='Edit product ‹ Dragon Coin — WordPress'
$coinFieldId='_regular_price'
$buttonId='publish'
$updateSeconds=120
$markupPercent=10
$decimalPoints=2
$timesToDeterminePause=3
function autologinFirefox{
param(
$url,
$username,
$password,
$usernameElementId='user_login',
$passwordElementId='user_pass',
$submitButtonId='wp-submit',
$exitWhenDone=$false
)
$ErrorActionPreference = 'continue'
# Initial validation
if(!$url){write-warning "No URL specified.";return $false}
function includeSelenium{
Import-Module Selenium -ea SilentlyContinue
if (!(get-module selenium -EA SilentlyContinue)){
try{
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
if(!(Get-PackageProvider Nuget -ea SilentlyContinue)){Install-PackageProvider -Name NuGet -Force}
# Defining $ENV:ChocotaleyInstall so that it would be called by refreshenv
$ENV:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
Install-Module Selenium -Force -Confirm:$False
Update-SessionEnvironment
Import-Module Selenium
return $true
}catch{
write-warning $_
return $false
}
}else{
return $true
}
}
function includeFirefox{
$firefoxInstalled=get-command "C:\Program Files\Mozilla Firefox\firefox.exe"
if (!$firefoxInstalled){
try{
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))}
choco install firefox --ignore-checksums -y
return $true
}catch{
write-warning $_
return $false
}
}else{
return $true
}
}
function invokeSelenium($url,$userName,$password,$usernameElementId,$passwordElementId,$submitButtonId){
$ErrorActionPreference = "Stop"
function closeSelenium($selenium){
if($selenium){
$selenium.close()
$selenium.quit()
}
}
function noLogin($url){
$seleniumFirefox = New-Object "OpenQA.Selenium.firefox.FirefoxDriver"
$seleniumFirefox.Navigate().GoToURL($url)
$title=$seleniumFirefox.Title
write-host "Page reached: '$title'"
$trustedSiteError=$title -match '^Error'
if($trustedSiteError){
write-host "An site trust issue has been detected. Adding root domain to the trusted sites list to resolve this issue."
addDomainToTrustedSites $url
closeSelenium $seleniumIe
return $false
}
else{
return $seleniumFirefox
}
}
function login($url,$username,$password,$usernameElementId,$passwordElementId,$submitButtonId){
$seleniumFirefox = New-Object "OpenQA.Selenium.firefox.FirefoxDriver"
$seleniumFirefox.Navigate().GoToURL($url)
$userField=$seleniumFirefox.FindElementById($usernameElementId)
$userField.clear()
$userField.SendKeys($username)
$passwordField=$seleniumFirefox.FindElementById($passwordElementId)
$passwordField.SendKeys('')
$passwordField.clear()
$passwordField.SendKeys($password)
$submitButton=$seleniumFirefox.FindElementById($submitButtonId)
$submitButton.Click()
$title=$seleniumFirefox.Title
write-host "Page reached: '$title'"
$trustedSiteError=$title -match '^Error'
if($trustedSiteError){
write-warning "A site trust issue has been detected."
closeSelenium $seleniumFirefox
return $false
}else{
return $seleniumFirefox
}
}
try{
$isLogin=$userName,$password,$usernameElementId,$passwordElementId,$submitButtonId|?{!(!$_)}
if($isLogin){
write-host "Login to $url as $userName..."
$firefox=login $url $userName $password $usernameElementId $passwordElementId $submitButtonId
}else{
write-host "Accesing $url without login..."
$firefox=nologin $url
}
return $firefox
}
catch{
Write-Warning $Error[0].Exception.Message
return $false
}
}
try{
write-host "Username`t: $username`r`nPassword`t: $(!(!$password))`r`nusernameElementId`t: $usernameElementId`r`npasswordElementId`t: $passwordElementId`r`nsubmitButtonId`t: $submitButtonId"
if(!(includeSelenium)){
write-warning "cannot proceed without selenium"
return $null
}
if(!(includeFirefox)){
write-warning "cannot proceed without Firefox"
return $null
}
$null=get-process firefox -ea silentlycontinue|stop-process -force -ea silentlycontinue
if(get-module selenium -ea SilentlyContinue){
$isLogin=$userName,$password,$usernameElementId,$passwordElementId,$submitButtonId|?{!(!$_)}
if($isLogin){
$selenium=invokeSelenium $url $userName $password $usernameElementId $passwordElementId $submitButtonId
}else{
write-host "No username or password are given. Proceeding to access only the provided URL."
$selenium=invokeSelenium $url
}
}else{
write-warning "Please manually verify that the Selenium module is installed before retrying this function."
}
if($selenium){
if($exitWhenDone){
return $true
}else{
return $selenium
}
}else{
write-warning "There were errors preventing a successful login."
return $false
}
}
catch {
write-warning "$_"
return $false
}
}
function getCoinPrice{
param(
$commodityName='name',
$commodityUri
)
$priceData=Invoke-RestMethod $commodityUri
$price=$priceData.coin.price
write-host "$(get-date) --- $commodityName price is $price"
return [hashtable]@{
$commodityName=$price
}
}
function updateFieldValues{
param(
$browser,
$fieldId,
$value,
$countMax=3
)
$erroractionpreference='stop'
$success=$false
$count=0
do{
try{
$field=$browser.FindElementById($fieldId)
$field.clear()
$field.SendKeys($value)
$success=$true
}catch{
write-warning $_
$count++
sleep 1
}
}until($success -or ($count -ge $countMax))
}
function updateCoinPage{
param(
$coinName='nano',
$coinApi='https://api.coinstats.app/public/v1/coins/nano?currency=USD',
$coinPage='https://dragoncoin.com/wp-admin/post.php?post=3302&action=edit',
$username,
$password,
$expectedPageTitle='Edit product ‹ Dragon Coin — WordPress',
$coinFieldId='_regular_price',
$buttonId='publish',
$markupPercent=15,
$decimalPoints=2,
$updateSeconds=120,
$timesToDeterminePause=3
)
function getFirefoxSession{
param(
$url,
$username,
$password
)
$firefoxSession=autologinFirefox $url $username $password
$title=$firefoxSession.Title
if($title -notlike $expectedPageTitle){
$null=get-process firefox | stop-process -force
$firefox=autoLoginFirefox $coinPage $username $password
if($firefox.Title -ne $expectedPageTitle){$firefoxSession.Navigate().GoToURL($url)}
clear-Host
write-host "Connected to $url"
}
return $firefoxSession
}
$countDown=0
Do{
if($countDown -lt $timesToDeterminePause){
$changesDetected=$false
$title=$firefox.Title
if($title -notlike $expectedPageTitle){
$firefox=getFirefoxSession $coinPage $username $password
}
$coinPrice=[math]::round($(getCoinPrice $coinName $coinApi).$coinName*$(1+($markupPercent/100)),$decimalPoints)
if(!$coinPrice){
write-warning "Cannot update if $coinName price value is Null"
}elseif($previousCoinPrice -ne $coinPrice){
updateFieldValues $firefox $coinFieldId $coinPrice
$changesDetected=$true
}else{
write-host "$coinName prices haven't changed."
}
if($changesDetected){
$submitButton=$firefox.findElementById($buttonId)
if($submitButton.enabled){
try{
$submitButton.Click()
write-host "$(get-date) --- $coinName price has been updated to $coinPrice"
}catch{
write-warning $_
}
$countDown=0
}else{
write-warning "Firefox session is not working. Timing out 5 minutes..."
Start-Sleep 300
}
}else{
$countDown++
}
$previousCoinPrice=$coinPrice
write-host "time-out $updateSeconds seconds until next iteration"
Start-Sleep -s $updateSeconds
}else{
Start-Sleep -s $updateSeconds
$countDown=0
}
}until($false)
}
updateCoinPage -coinName $coinName `
-coinApi $coinApi `
-coinPage $coinPage `
-username $username `
-password $password `
-expectedPageTitle $expectedPageTitle `
-coinFieldId $coinFieldId `
-buttonId $buttonId `
-markupPercent $markupPercent `
-decimalPoints $decimalPoints `
-updateSeconds $updateSeconds `
-timesToDeterminePause $timesToDeterminePause
WordPress: Remove ‘Built with Storefront & WooCommerce’ in footer
Credit: @jobthomas Automattic Happiness Engineer
https://wordpress.org/support/topic/remove-built-with-storefront-footer-link-2/
How to apply: search and install Code Snippets > add this snippet > apply everywhere
if ( ! function_exists( 'storefront_credit' ) ) {
/**
* Display the theme credit
*
* @since 1.0.0
* @return void
*/
function storefront_credit() {
?>
<div class="site-info">
<?php echo esc_html( apply_filters( 'storefront_copyright_text', $content = '© ' . get_bloginfo( 'name' ) . ' ' . date( 'Y' ) ) ); ?>
</div>
<?php
}
}
CSS: How To Set Color Gradient and Animation to Text and Background
// Static color gradient
.colorGradientClass {
background-color: #ffffff !important;
background-image: linear-gradient(315deg, #ffffff 0%, #d9d9d9 74%) !important;
}
// Animated color gradient
.colorTransitionClass {
background-image:
linear-gradient(to right, transparent, white),
linear-gradient(to right,yellow, white, yellow, white);
background-size: 100% 100%, 2000% 100%;
animation: move 5s infinite;
}
@keyframes move {
from {background-position: center center, left center;}
to {background-position: center center, right center;}
}
// This will result in blinking text
.blinkingText {
animation: blinker 5s linear infinite;
color: red !important;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
How To Move WordPress Site To Kubernetes Cluster
a. Create backups of source files and database
- Logon to Current Hosting Provider to make backups
- Files:
- Assuming cPanel:
- Login to cPanel
- Click on 'File Manager'
- Select public_html or the directory containing WordPress files
- Select Compress from the top-right menu
- Select 'Bzip2ed Tar Archive' (better compression than Gzip)
- Click 'Compress File(s)' and wait for the process to finish
- Right-click the newly generated public_html.tar.bz2 from cPanel File Manager > select Download
- Find the file in a default download directory (e.g. /home/$(whoami)/Downloads/public_html.tar.bz2)
- Database:
- Assuming cPanel with phpMyAdmin
- Click 'phpMyAdmin' from the 'DATABASES' control group
- Click 'Export'
- Set Export method = Quick, Format = Custom
- Click Go
- Find the *.sql file being downloaded into a default download directory (e.g. /home/$(whoami)/Downloads/localhost.sql)
b. Install Bitnami WordPress in a Kubernetes Cluster
# Add helm chart if not already available
helm repo add bitnami https://charts.bitnami.com/bitnami
# Install WordPress with Dynamic NFS Provisioning
# Documentation: https://hub.kubeapps.com/charts/bitnami/wordpress/10.0.1
# Set variables
appName=kimconnectblog
domainName=blog.kimconnect.com
wordpressusername=kimconnect
wordpressPassword=SOMEPASSWORDHERE
rootPassword=SOMEPASSWORDHERE2
storageClass=nfs-client
# Install
helm install $appName bitnami/wordpress \
--set persistence.accessMode=ReadWriteMany,persistence.storageClass=nfs-client \
--set mariadb.primary.persistence.storageClass=nfs-client \
--set wordpressUsername=$wordpressusername,wordpressPassword=$wordpressPassword \
--set mariadb.auth.rootPassword=$rootPassword \
--set mariadb.auth.password=$rootPassword \
--set ingress.enabled=true,ingress.hostname=$domainName
# Patch the deployed ingress with an existing SSL cert
# Assuming the $appName-cert has already been generated
appName=kimconnectblog
domainName=blog.kimconnect.com
certName=$appName-cert
serviceName=$appName-wordpress
servicePort=80
cat <<EOF > $appName-patch.yaml
spec:
tls:
- hosts:
- $domainName
secretName: $certName
rules:
- host: $domainName
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: $serviceName
port:
number: $servicePort
EOF
kubectl patch ingress/$appName-wordpress -p "$(cat $appName-patch.yaml)"
c. Import files and database onto new hosting server
- Database:
- Access DB server and import sql dump
podName=kimconnectblog-mariadb-0
kubectl exec --stdin --tty $podName -- /bin/bash
rootPassword=SOMEPASSWORD
echo "show databases;" | mysql -u root -p$rootPassword
MariaDB [(none)]> show databases;exit;
+--------------------+
| Database |
+--------------------+
| bitnami_wordpress |
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.009 sec)
oldDb=kimconne_blog
sqlDump=/bitnami/mariadb/data/kimconnect.sql
mysql -uroot -p$rootPassword test < $sqlDump
grantUser=bn_wordpress # this is the default Bitnami WordPress user
echo "GRANT ALL PRIVILEGES ON $oldDb.* TO $grantUser;" | mysql -uroot -p$rootPassword
#echo "create database $databaseName;" | mysql -uroot -p$rootPassword
#mysql -uroot -p$rootPassword $oldDb -sNe 'show tables' | while read table; do mysql -uroot -p$rootPassword -sNe "RENAME TABLE $oldDb.$table TO $newDb.$table"; done
#echo "create user kimconne_blog@localhost;grant all privileges on kimconne_blog.* to 'kimconne_blog';"| mysql -uroot -p$rootPassword
#ALTER USER 'kimconne_blog'@'localhost' IDENTIFIED BY 'SOMEPASSWORDHERE';
- Files:
- Assuming nfs:
nfsShare=k8s
nfsServer=10.10.10.5
sharePath=/volume1/$nfsShare
mountPoint=/mnt/$nfsShare
sudo mkdir $mountPoint
sudo mount -t nfs $nfsServer:$sharePath $mountPoint # Test mounting
sudo mount | grep $nfsShare # validate mount
# Assuming Kubernetes NFS
# sudo mv /home/$(whoami)/Downloads/localhost.sql $mountPoint/path_to_default-data-sitename-mariadb/data/localhost.sql
# sudo mv /home/$(whoami)/Downloads/public_html.tar.bz2 $mountPoint/public_html.tar.bz2
bz2File=/mnt/k8s/kimconnectblog/public_html.tar.bz2
containerPath=/mnt/k8s/default-kimconnectblog-wordpress-pvc-9f1dd4bd-81f3-489f-9b76-bf70f4fd291c/wordpress/wp-content
tar -xf $bz2File -C $containerPath
cd $containerPath
mv public_html/wp-content wp-content
vim wp-config.php # edit wp config to match the imported database and its prefix