Keep search parameters when using WP_List_Table and navigation

WP_List_Table is a reasonably flexible way of creating data tables in WordPress Admin Plugins. While there are plenty of warnings and words of caution against using WP_List_Table throughout the WordPress documentation and elsewhere on the Internet, it is a very popular method in use by many plugin authors.

Whether or not it’s a good idea to use WP_List_Table for your plugin is beyond the scope of this post.

While developing a plugin that is using WP_List_Table, I came across a rather well-known issue. The issue is that once the user enters search data, you would (logically) think that the search data is maintaned while navigating the search result. Unfortunately, when the user clicks on the previous and next links, or clicks on one of the table headers to re-sort the search result, the search is “lost”.

This can, technically speaking, be avoided if you resort to using METHOD="GET" rather than METHOD="POST" in your table form. But I wanted to avoid this since the entire GET request is passed in the URL and thus ends up in logs, etc.

So, how to use POST instead of get, and still maintain the search parameter across page loads?

The WP_List_Table class makes extensive use of the set_url_scheme() function to create various headers and clickable links in the table view. Unfortunately, this function is rather generic in nature and does not take the parameters from WP_List_Table::search_box() into account. But, as is the case with most functions in WordPress, as a last action, the set_url_scheme() function calls any hooked filters before it returns.

Keep search parameters between page loads

The example assumes $your_table is an object derived from WP_List_Table.

echo '<div class="wrap">';
echo '<form action="admin.php?page=your_plugin_table" method="post" name="your_table_form">';
$your_table->prepare_items();
$your_table->mangle_url_scheme_start();
$your_table->search_box();
$your_table->display();
$your_table->mangle_url_scheme_stop();
echo '</form>';
echo '</div>';

The two functions of interest here are mangle_url_scheme_start() and its companion, mangle_url_scheme_stop(). These go into your class derived from WP_List_Table like this:

public function mangle_url_scheme_start() {
    add_filter( 'set_url_scheme', [$this, 'mangle_url_scheme'], 10, 3 );
}

and

public function mangle_url_scheme_stop() {
    remove_filter( 'set_url_scheme', [$this, 'mangle_url_scheme'], 10 );
}

The last piece of the workaround is the mangle_url_scheme() function:

public function mangle_url_scheme( string $url, 
                                   string $scheme, 
                                   $orig_scheme ) {
    if ( ! empty( $url ) 
        && mb_strpos( $url, '?page=your_plugin_table' ) !== false 
            && isset( $_REQUEST['s'] ) ) {
        $url = add_query_arg( 's', urlencode( $_REQUEST['s'] ), $url );
    }
    return( $url );
}

This is only done on your plugin table page, and it’s only done if the $_REQUEST['s'] parameter is set. I can’t see how this will cause any issues further down the road, but you may experience different results. You may want to sanitize the contents of $_REQUEST['s'] further before you urlencode it.

I am reasonably convinced that there are other, and better, ways of doing this. But I haven’t found one yet.

 

WordPress Update Services 2021

Here’s, hopefully, a resonably up to date list of URLs to use for WordPress Update Services in 2021, with duplicates removed 🙂

I don’t think there’s a “best practice” for these, and everyone’s opinion seem to differ on the subject. So I am by no means claiming that this is a complete or good list for WordPress Update Services, but it’s possibly a start.

These go into Settings > Writing > Update Services

http://api.feedster.com/ping
http://api.moreover.com/ping
http://api.my.yahoo.com/RPC2
http://api.my.yahoo.com/rss/ping
http://bing.com/webmaster/ping.aspx
http://blogdb.jp/xmlrpc
http://blog.goo.ne.jp/XMLRPC
http://blogmatcher.com/u.php
http://blogping.unidatum.com/RPC2
http://blogsearch.google.ae/ping/RPC2
http://blogsearch.google.at/ping/RPC2
http://blogsearch.google.be/ping/RPC2
http://blogsearch.google.bg/ping/RPC2
http://blogsearch.google.ca/ping/RPC2
http://blogsearch.google.ch/ping/RPC2
http://blogsearch.google.cl/ping/RPC2
http://blogsearch.google.co.cr/ping/RPC2
http://blogsearch.google.co.cr/ping/RPC2
http://blogsearch.google.co.hu/ping/RPC2
http://blogsearch.google.co.hu/ping/RPC2
http://blogsearch.google.co.id/ping/RPC2
http://blogsearch.google.co.id/ping/RPC2
http://blogsearch.google.co.il/ping/RPC2
http://blogsearch.google.co.in/ping/RPC2
http://blogsearch.google.co.it/ping/RPC2
http://blogsearch.google.co.jp/ping/RPC2
http://blogsearch.google.co.ma/ping/RPC2
http://blogsearch.google.com.ar/ping/RPC2
http://blogsearch.google.com.au/ping/RPC2
http://blogsearch.google.com.br/ping/RPC2
http://blogsearch.google.com.co/ping/RPC2
http://blogsearch.google.com.do/ping/RPC2
http://blogsearch.google.com.mx/ping/RPC2
http://blogsearch.google.com.my/ping/RPC2
http://blogsearch.google.com.pe/ping/RPC2
http://blogsearch.google.com/ping/RPC2
http://blogsearch.google.com/ping/RPC2
http://blogsearch.google.com.sa/ping/RPC2
http://blogsearch.google.com.sg/ping/RPC2
http://blogsearch.google.com.tr/ping/RPC2
http://blogsearch.google.com.tw/ping/RPC2
http://blogsearch.google.com.ua/ping/RPC2
http://blogsearch.google.com.uy/ping/RPC2
http://blogsearch.google.com.vn/ping/RPC2
http://blogsearch.google.co.nz/ping/RPC2
http://blogsearch.google.co.th/ping/RPC2
http://blogsearch.google.co.uk/ping/RPC2
http://blogsearch.google.co.ve/ping/RPC2
http://blogsearch.google.co.za/ping/RPC2
http://blogsearch.google.de/ping/RPC2
http://blogsearch.google.es/ping/RPC2
http://blogsearch.google.fi/ping/RPC2
http://blogsearch.google.fr/ping/RPC2
http://blogsearch.google.gr/ping/RPC2
http://blogsearch.google.hr/ping/RPC2
http://blogsearch.google.ie/ping/RPC2
http://blogsearch.google.it/ping/RPC2
http://blogsearch.google.jp/ping/RPC2
http://blogsearch.google.ki/ping/RPC2
http://blogsearch.google.kz/ping/RPC2
http://blogsearch.google.la/ping/RPC2
http://blogsearch.google.li/ping/RPC2
http://blogsearch.google.lk/ping/RPC2
http://blogsearch.google.lt/ping/RPC2
http://blogsearch.google.lu/ping/RPC2
http://blogsearch.google.md/ping/RPC2
http://blogsearch.google.mn/ping/RPC2
http://blogsearch.google.ms/ping/RPC2
http://blogsearch.google.mu/ping/RPC2
http://blogsearch.google.mv/ping/RPC2
http://blogsearch.google.mw/ping/RPC2
http://blogsearch.google.nl/ping/RPC2
http://blogsearch.google.no/ping/RPC2
http://blogsearch.google.nr/ping/RPC2
http://blogsearch.google.nu/ping/RPC2
http://blogsearch.google.pl/ping/RPC2
http://blogsearch.google.pn/ping/RPC2
http://blogsearch.google.pt/ping/RPC2
http://blogsearch.google.ro/ping/RPC2
http://blogsearch.google.ru/ping/RPC2
http://blogsearch.google.rw/ping/RPC2
http://blogsearch.google.sc/ping/RPC2
http://blogsearch.google.se/ping/RPC2
http://blogsearch.google.sh/ping/RPC2
http://blogsearch.google.si/ping/RPC2
http://blogsearch.google.sk/ping/RPC2
http://blogsearch.google.sm/ping/RPC2
http://blogsearch.google.sn/ping/RPC2
http://blogsearch.google.st/ping/RPC2
http://blogsearch.google.tk/ping/RPC2
http://blogsearch.google.tl/ping/RPC2
http://blogsearch.google.tm/ping/RPC2
http://blogsearch.google.to/ping/RPC2
http://blogsearch.google.tp/ping/RPC2
http://blogsearch.google.tt/ping/RPC2
http://blogsearch.google.us/ping/RPC2
http://blogsearch.google.vg/ping/RPC2
http://blogsearch.google.vu/ping/RPC2
http://blogsearch.google.ws/ping/RPC2
http://blo.gs/ping.php
http://blogs.yandex.ru/
http://blog.with2.net/ping.php
http://bulkfeeds.net/rpc
http://coreblog.org/ping/
http://geourl.org/ping
http://ipings.com
http://mod-pubsub.org/kn_apps/blogchatt
http://news2paper.com/ping
http://ping.bitacoras.com
http://ping.bloggers.jp/rpc
http://ping.blo.gs/
http://ping.blogs.yandex.ru/RPC2
http://ping.exblog.jp/xmlrpc
http://ping.fc2.com
http://ping.feedburner.com
http://ping.myblog.jp
http://pingoat.com/goat/RPC2
http://ping.rootblog.com/rpc.php
http://ping.rss.drecom.jp
http://ping.syndic8.com/xmlrpc.php
http://ping.weblogs.se/
http://rcs.datashed.net/RPC2/
http://rpc.blogbuzzmachine.com/RPC2
http://rpc.bloggerei.de/
http://rpc.bloggerei.de/ping/
http://rpc.blogrolling.com/pinger/
http://rpc.icerocket.com:10080
http://rpc.newsgator.com/
http://rpc.pingomatic.com
http://rpc.technorati.com/rpc/ping
http://rpc.twingly.com
http://rpc.urlfan.com/ping
http://rpc.weblogs.com/RPC2
http://services.newsgator.com/ngws/xmlrpcping.aspx
https://ping.blogs.yandex.ru/RPC2
http://topicexchange.com/RPC2
http://trackback.bakeinu.jp/bakeping.php
http://www.a2b.cc/setloc/bp.a2b
http://www.bitacoles.net/ping.php
http://www.blogdigger.com/RPC2
http://www.blogoole.com/ping/
http://www.blogpeople.net/servlet/weblogUpdates
http://www.blogroots.com/tb_populi.blog?id=1
http://www.blogshares.com/rpc.php
http://www.blogsnow.com/ping
http://www.blogstreet.com/xrbin/xmlrpc.cgi
http://www.lasermemory.com/lsrpc/
http://www.mod-pubsub.org/kn_apps/blogchatter/ping.php
http://www.pingerati.net
http://www.pingmyblog.com

Improving your Nextcloud upgrade experience

Nextcloud, a truly wonderful open source project, allows you to create your own co-lab hub. You can choose to host it yourself, or get a Nextcloud instance at one of the many service providers, such as WebbPlatsen i Sverige AB. Nextcloud can replace many not-so-GDPR-safe alternatives and other costly solutions. If you, by some small miracly, still do not know what Nextcloud is, go check it out at nextcloud.com.

For the past few years, Nextcloud has kept an almost alarmingly fast pace when it comes to updates. Quite often, a major version is followed by a few minor updates, and then another major version is released. Typically, a lot of new functionality has been thrown in for the major updates. Naturally, we want more functionality and toys 🙂

Updating Nextcloud is usually not a big issue, unless the Nextcloud downloads are slow. And they are, quite frequently, very slow. So slow in fact that the Nextcloud updater exits with an error when it comes to the step where it downloads the new files, even if you increase your PHP maximum execution time to 10 minutes (!)

There are ways to improve your Nextcloud upgrade experience, some of them are mentioned here. The remainder of this post assumes you have some sort of file access to your Nextcloud server.

Nextcloud updater times out when downloading

If you go to the data directory for Nextcloud during an update, there’s typically a directory called updater-nnn, where nnn is an arbitrary string. This is where Nextcloud keeps its files for the upgrader, including progression counters and downloads.

From the Nextcloud web interface, under Administration.Overview, there’s a Download now button that is actually just a link. You can copy the link and download the file manually. Once the download has completed, you can place it in the downloads sub-directory of the updater-nnn directory. Once done, re-start the upgrade process.

Nextcloud updater gets stuck during the update process

In the same updater-nnn directory, there is a “step counter” so that Nextcloud can keep track of where in the update process it is currently positioned. If Nextcloud keeps getting stuck at the download step, or you are presented with “Step 4 is currently in process. Please reload this page later.”, you may try to remove the file .step and re-start the upgrade process.

Manually upgrading Nextcloud from CLI

If you have shell access to your Nextcloud instance, you may also attempt a manual upgrade, which may have different timeout settings (or no timeout settings). The short version is listed below, the long version can be found in the official Nextcloud documentation, please make sure you read it before attempting a manual upgrade!

sudo -u www-data php /var/www/nextcloud/occ upgrade
sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --off

Replace www-data for the user PHP and/or your web server is running as and correct paths as needed.

 

Cloudbridge Mattermost 2.0.0 with OAuth2 for WordPress

Cloudbridge Mattermost is a WordPress plugin that provides integration between WordPress and Mattermost.

It has now been updated with OAuth2 authentication for WordPress via Mattermost.

It has been tested with Mattermost 5.30+ and WordPress 5.5.3 and WordPress 5.6.

Features at a glance:

  • OAuth2 authentication, login to WordPress via Mattermost
  • Notifications for successful login
  • Notifications for failed login
  • Notifications for unknown user login attempt
  • Notifications for password reset
  • Notifications for plugin activation
  • Notifications for plugin deactivation
  • Notifications for plugin uninstallation
  • Notifications for new/edited user
  • Notifications for deleted user
  • The plugin can also make use of additional functionality such as posting to a specific channel/user, overriding bot names, and additionally mention specific users.

You can download it from the official WordPress repository:
wordpress.org/plugins/cloudbridge-mattermost

You can also get it from GitHub, should you prefer that source:
github.com/joho1968/cloudbridge-mattermost

WebbPlatsen’s official website for their Open Source projects:
code.webbplatsen.net/wordpress/cloudbridge-mattermost/

 

The Lenovo ThinkPad X1 ANC headphones are a pleasant surprise

The Lenovo ThinkPad X1 ANC headphones are possibly the best on-ear active noise cancellation headphones you’ve never heard of.

 

 

They went completely under my radar while looking for wireless headphones. Some years ago, it wasn’t that hard to find decent on-ear headphones. This, however, seems to have changed recently. So when my AKG N60 NC gave up on me (due to poor construction of the ear cup hinges), it seemed like an impossible task to replace them with something similar and on-ear.

I want on-ear headphones for general music listening and audio interactions with my smartphone. I know most high-end over-ear headphones outperform on-ear equipment, but I like the on-ear experience. Unfortunately for me, in-ear seems to be out of the question as most of the ones I’ve tried simply fall out of my ears.

I ran across the Lenovo ThinkPad X1 ANC headphones by accident and dismissed them at first, mainly based on brand reputation. Don’t get me wrong, I love the high-end Lenovo laptops, and the X and T series truly bring joy to my everyday work, but just because someone knows how to make a great laptop doesn’t automatically mean they do audio well.

To make a long story short: The Lenovo ThinkPad X1 ANC headphones are really worth looking into if you are looking for a pair of on-ear, wireless, active noise cancellation headphones.

They don’t stand out very much physically. There’s a small “Lenovo” text on the side of the headband, and there’s a subtle “X1” on the actual cup. Looking at the box, and the included carrying case, there’s no doubt it’s a “ThinkPad” device, if you know your Lenovo laptops.

This is not a What Hi*Fi review, so I’ll spare you some of the details, but here’s my “short” list:

  • Great sound, listening to these songs didn’t disappoint me:
    • Fortunate Son (Clutch)
    • Welcome to the jungle (Guns ‘n’ Roses)
    • Comfortably Numb (Pink Floyd)
    • The 1968 Comeback Special (Elvis Presley)
    • What’s up (Four none blondes)
    • Hello (both Adele and Martin Almgren versions)
    • No sleep till Brooklyn (Beastie Boys)
  • Good physical controls and buttons that do what you expect them to do
  • Comfortable fit on head and ears
  • Nice and quiet design
  • Foldable (90 degree collapsible)
  • Supports USB-C quick charging and wired USB-C connection
  • Bluetooth 5.0
  • Appearance of great build quality
  • 40mm neodymium drivers
  • 8-12 hours playback on battery with ANC off
  • aptX support
  • Boomless microphone
  • On-ear 🙂
  • Active, hybrid, and no noise cancellation modes

You can read more about them here: Lenovo ThinkPad X1 ANC Headphones

The headphones also exist as “Yoga ANC Headphones” with identical specs as far as I can tell, but with some different color options.

(I am not affiliated with Lenovo in any way, other than being a long time user of their premium laptop segment.)

Lenovo ThinkPad X1 ANC Headphones

var_dump() for Javascript

PHP, for example, has var_dump() and print_r() to facilitate quick variable dumps to log files, etc.

For Javascript, one can use console.log() in combination with JSON.stringify() to achieve something similar.

  console.log( JSON.stringify(object) );

It’s also possible to “pretty-print” the output like so:

  console.log( JSON.stringify(object, null, 2) );

For more information about JSON.stringify(), check out this page

Ubuntu 20.04, Nginx, Redmine, Ruby, and Passenger-Phusion confusion

Redmine, Ruby, Passenger-Phusion, and Nginx makes for an extremely confusing situation with dependencies, installation “instructions”, and “mismatching” package versions.

Redmine wants Ruby x, your Linux distribution has Ruby y, Passenger-Phusion only works with Ruby z, and you quite often end up in a loop somewhere. This article will not do anything to help that confusion I’m afraid.

On Passenger-Phusion’s website, there’s an interesting explanation as to why you need to let Passenger-Phusion build Nginx for you, unless you can actually use everything pre-packaged, which you cannot if you want to use Ubuntu 20.04.LTS and Redmine 4.1.

Before you begin, you should know that installing Passenger in its Nginx integration mode involves extending Nginx with code from Passenger. However, Nginx does not support loadable modules. This means that in order to install Passenger’s Nginx integration mode, it is necessary to recompile Nginx from source. And that is exactly what we will do in this installation guide.

Now, if you head on over to the Nginx blog, you can read:

NGINX Open Source 1.11.5 and NGINX Plus Release R11 introduced binary compatibility for dynamic modules. This article explains how to compile third‑party modules for use with NGINX Open Source and NGINX Plus in a development environment.

That statement was made for Nginx 1.11. They are, at the time of this writing, at 1.19.

So basically, if you want to run Redmine 4.1 on Ubuntu 20.04.LTS, which ships with Ruby 2.7, and a Passenger-Phusion module that requires Ruby 2.7, you’re on your own since Redmine 4.1 does not support Ruby 2.7. If you use RVM to installed Ruby 2.6.x, you need to manually handle Passenger-Phusion, which eventually requires re-compiling Nginx, regardless of it supporting “dynamic modules”.

There is one small glimmer of hope:
Installing Passenger as a normal or dynamic Nginx module

Using Ubuntu 18.04.LTS, the included Passenger, Nginx, and Ruby all work with Redmine 4.1.x, so that may be a smoother path to take before this is all “fixed”, if it gets fixed.