cjhaas blog https://cjhaas.com Basically a place that Chris can post solutions to problems so he can easily find them later Tue, 04 Aug 2020 16:36:53 +0000 en-US hourly 1 https://wordpress.org/?v=5.4.2 How to fix “Error: Another update is currently in progress.” https://cjhaas.com/2020/08/04/how-to-fix-error-another-update-is-currently-in-progress/ https://cjhaas.com/2020/08/04/how-to-fix-error-another-update-is-currently-in-progress/#respond Tue, 04 Aug 2020 16:36:51 +0000 https://cjhaas.com/?p=978 First, if you aren’t technical AND you don’t have CLI access to your server AND you don’t have WordPress’s CLI tool installed, maybe read this article instead (but don’t install the plugin, just use phpMyAdmin). If you’ve got all of the above, just run:

The post How to fix “Error: Another update is currently in progress.” appeared first on cjhaas blog.

]]>
First, if you aren’t technical AND you don’t have CLI access to your server AND you don’t have WordPress’s CLI tool installed, maybe read this article instead (but don’t install the plugin, just use phpMyAdmin).

If you’ve got all of the above, just run:

wp option delete core_updater.lock

The post How to fix “Error: Another update is currently in progress.” appeared first on cjhaas blog.

]]>
https://cjhaas.com/2020/08/04/how-to-fix-error-another-update-is-currently-in-progress/feed/ 0
Remove buttons from a WYSIWYG editor for a specific ACF field type https://cjhaas.com/2020/06/03/remove-buttons-from-a-wysiwyg-editor-for-a-specific-acf-field-type/ https://cjhaas.com/2020/06/03/remove-buttons-from-a-wysiwyg-editor-for-a-specific-acf-field-type/#respond Wed, 03 Jun 2020 16:45:16 +0000 https://cjhaas.com/?p=973 You can pretty easily customize the advanced custom fields WYSIWYG toolbars globally, however doing so on a case-by-case basis needs to be done in JS since the editing experience is so dynamic. This code is looking for a specific ACF field called step_text and sets the WYSIWYG editor to only allow bold, italic and links. […]

The post Remove buttons from a WYSIWYG editor for a specific ACF field type appeared first on cjhaas blog.

]]>
You can pretty easily customize the advanced custom fields WYSIWYG toolbars globally, however doing so on a case-by-case basis needs to be done in JS since the editing experience is so dynamic.

This code is looking for a specific ACF field called step_text and sets the WYSIWYG editor to only allow bold, italic and links.

add_action(
    'acf/input/admin_footer',
    static function () {
        ?>
        <script type="text/javascript">
            (function ( $ ) {

                acf
                    .add_filter(
                        'wysiwyg_tinymce_settings',
                        function( mceInit, id, field ) {
                            if ( field.context.dataset.hasOwnProperty( 'type' ) && field.context.dataset.hasOwnProperty( 'name' ) && 'step_text' === field.context.dataset.name && 'wysiwyg' === field.context.dataset.type ) {
                                console.dir(mceInit.toolbar1);
                                mceInit.toolbar1 = 'bold,italic,link';
                            }
                            return mceInit;
                        }
                    )
                ;

            }
            )( jQuery );
        </script>
        <?php
    }
);

The post Remove buttons from a WYSIWYG editor for a specific ACF field type appeared first on cjhaas blog.

]]>
https://cjhaas.com/2020/06/03/remove-buttons-from-a-wysiwyg-editor-for-a-specific-acf-field-type/feed/ 0
YouTube’s hidden “Crane Kick” mode https://cjhaas.com/2020/05/20/youtubes-hidden-crane-kick-mode/ https://cjhaas.com/2020/05/20/youtubes-hidden-crane-kick-mode/#respond Wed, 20 May 2020 17:31:29 +0000 https://cjhaas.com/?p=969 I’m guessing this is from their Karate Kid thing a couple of years ago, but the YouTube CSS still includes references to a crane kick file: https://www.gstatic.com/youtube/img/originals/ckee/crane-kick@2x.png To activate, you need to add a custom attribute of ytp-scrubber-container to some parent of .ytp-scrubber-container and then you’ll need to also manually turn off the opacity and […]

The post YouTube’s hidden “Crane Kick” mode appeared first on cjhaas blog.

]]>
I’m guessing this is from their Karate Kid thing a couple of years ago, but the YouTube CSS still includes references to a crane kick file:

https://www.gstatic.com/youtube/img/originals/ckee/crane-kick@2x.png

To activate, you need to add a custom attribute of ytp-scrubber-container to some parent of .ytp-scrubber-container and then you’ll need to also manually turn off the opacity and transform. There’s a hover attribute this is supposed to do this but it is to a sibling item which won’t invoke with the selectors.

If you get it right, you’ll end up with:

The post YouTube’s hidden “Crane Kick” mode appeared first on cjhaas blog.

]]>
https://cjhaas.com/2020/05/20/youtubes-hidden-crane-kick-mode/feed/ 0
How to install a specific version of Drupal using composer https://cjhaas.com/2020/05/07/how-to-install-a-specific-version-of-drupal-using-composer/ https://cjhaas.com/2020/05/07/how-to-install-a-specific-version-of-drupal-using-composer/#respond Thu, 07 May 2020 20:39:17 +0000 https://cjhaas.com/?p=966 When you are migrating a site from a legacy install of Drupal to a composer-based one, sometimes it is easiest to just get a new install running, add all of the modules using composer, then importing to the database so that Drupal just “wakes up” without realizing anything has changed. To install a specific version […]

The post How to install a specific version of Drupal using composer appeared first on cjhaas blog.

]]>
When you are migrating a site from a legacy install of Drupal to a composer-based one, sometimes it is easiest to just get a new install running, add all of the modules using composer, then importing to the database so that Drupal just “wakes up” without realizing anything has changed.

To install a specific version of Drupal in the current (empty) directory, just run:

composer create-project drupal/drupal:8.6.10 .

The post How to install a specific version of Drupal using composer appeared first on cjhaas blog.

]]>
https://cjhaas.com/2020/05/07/how-to-install-a-specific-version-of-drupal-using-composer/feed/ 0
How to create a command that holds other commands in wp-cli (WordPress CLI) https://cjhaas.com/2019/12/18/how-to-create-a-command-that-holds-other-commands-in-wp-cli-wordpress-cli/ https://cjhaas.com/2019/12/18/how-to-create-a-command-that-holds-other-commands-in-wp-cli-wordpress-cli/#respond Wed, 18 Dec 2019 19:44:08 +0000 https://cjhaas.com/?p=958 Almost every major site I work on has at least one custom wp-cli command that I’ve built to manage or automate things. But I always run into the same problem, I don’t want my command to be a root command, I want it to live in a namespace of my own. But, I also don’t […]

The post How to create a command that holds other commands in wp-cli (WordPress CLI) appeared first on cjhaas blog.

]]>
Almost every major site I work on has at least one custom wp-cli command that I’ve built to manage or automate things. But I always run into the same problem, I don’t want my command to be a root command, I want it to live in a namespace of my own. But, I also don’t want to create a blank command that doesn’t do anything just for the sake of this namespace.

For instance, if I register a command using this:

WP_CLI::add_command('custom-command do-thing', DoThingCommand::class);

WordPress will show the below if I just type wp:

  cache                 Adds, removes, fetches, and flushes the WP Object Cache object.
  cap                   Adds, removes, and lists capabilities of a user role.
  cli                   Review current WP-CLI info, check for updates, or see defined aliases.
  comment               Creates, updates, deletes, and moderates comments.
  config                Generates and reads the wp-config.php file.
  core                  Downloads, installs, updates, and manages a WordPress installation.
  cron                  Tests, runs, and deletes WP-Cron events; manages WP-Cron schedules.
  custom-command        
  db                    Performs basic database operations using credentials stored in wp-config.php.
  embed                 Inspects oEmbed providers, clears embed cache, and more.
  eval                  Executes arbitrary PHP code.
  eval-file             Loads and executes a PHP file.

If you don’t notice or are unable to see the problem, each command listed has an “intro” description except for my command which instead just has a blank space.

Instead of grepping all of wp-cli’s code, I luckily had Yoast installed, too, so I grepped their code and saw a special class from core that you can extend call CommandNamespace which has the following comment:

Adds a command namespace without actual functionality.

This is meant to provide the means to attach meta information to a namespace when there’s no actual command needed.

In case a real command gets registered for the same name, it replaces the command namespace.

https://github.com/wp-cli/wp-cli/blob/bc37f66e25b9992813b0c50b933aefbf88718e6a/php/WP_CLI/Dispatcher/CommandNamespace.php#L8

So, just create a class that extends that (and probably make it final), register it like a normal command, and WordPress will do the rest for you.

The post How to create a command that holds other commands in wp-cli (WordPress CLI) appeared first on cjhaas blog.

]]>
https://cjhaas.com/2019/12/18/how-to-create-a-command-that-holds-other-commands-in-wp-cli-wordpress-cli/feed/ 0
How to move a Google Analytics property without admin access to both accounts https://cjhaas.com/2019/11/21/how-to-move-a-google-analytics-property-without-admin-access-to-both-accounts/ https://cjhaas.com/2019/11/21/how-to-move-a-google-analytics-property-without-admin-access-to-both-accounts/#comments Thu, 21 Nov 2019 15:57:13 +0000 https://cjhaas.com/?p=955 If you have a Google Analytics property that you want to transfer to a different account, you need to be an admin (technically have Edit Property permissions) on both accounts, and there’s no way around this. So, how can you move an account if you don’t want to grant admin access to your client, and […]

The post How to move a Google Analytics property without admin access to both accounts appeared first on cjhaas blog.

]]>
If you have a Google Analytics property that you want to transfer to a different account, you need to be an admin (technically have Edit Property permissions) on both accounts, and there’s no way around this.

So, how can you move an account if you don’t want to grant admin access to your client, and they don’t want to grant you admin access?

The solution is super obvious when you think about it, and it was this morning, but for some reason last night it didn’t even cross my mind.

Create a third account! Duh.

Just make a brand new account with both you and the client listed as admins, then you move the property into that account, and the client can move the property out of that account. Once done, delete the temporary account.

Side note: whenever you create an account, you are required to also create a property, even if you aren’t going to use it. Just call it Delete Me or similar and remember to delete it when this is all done.

The post How to move a Google Analytics property without admin access to both accounts appeared first on cjhaas blog.

]]>
https://cjhaas.com/2019/11/21/how-to-move-a-google-analytics-property-without-admin-access-to-both-accounts/feed/ 1
mySQL Recursive CTE https://cjhaas.com/2019/10/25/mysql-recursive-cte/ https://cjhaas.com/2019/10/25/mysql-recursive-cte/#respond Fri, 25 Oct 2019 09:28:14 +0000 https://cjhaas.com/?p=947 Almost 10 years ago I asked this question on Stack Overflow about how to find the deepest nodes in a recursive table using a Common Table Expression (CTE). Fast forward to today, and I need a mySQL equivalent, specifically for MariaDB. Please read the original question to get the gist, below is the table, records […]

The post mySQL Recursive CTE appeared first on cjhaas blog.

]]>
Almost 10 years ago I asked this question on Stack Overflow about how to find the deepest nodes in a recursive table using a Common Table Expression (CTE). Fast forward to today, and I need a mySQL equivalent, specifically for MariaDB.

Please read the original question to get the gist, below is the table, records and CTE converted to mySQL (tested against MariaDB 10.2.22).

Create the table

CREATE TABLE Employees
(
   EmployeeId int NOT NULL AUTO_INCREMENT,
   ParentEmployeId int NULL,
   Name varChar(255),
   PRIMARY KEY (EmployeeId),
   CONSTRAINT FOREIGN KEY (ParentEmployeId) REFERENCES Employees(EmployeeId)
)

Insert rows

INSERT INTO Employees VALUES (1, NULL, 'Company President 1');
INSERT INTO Employees VALUES (2, NULL, 'Company President 2');
INSERT INTO Employees VALUES (3, 1, 'Company President 1 - VP');
INSERT INTO Employees VALUES (4, 2, 'Company President 2 - VP');
INSERT INTO Employees VALUES (5, 3, 'Company President 1 - VP - Secretary');
INSERT INTO Employees VALUES (6, 4, 'Company President 2 - VP - Secretary');
INSERT INTO Employees VALUES (7, 5, 'Company President 1 - VP - Secretary - Sandwich Delivery');

Query

WITH RECURSIVE EmployeeRec AS
(
    SELECT
        EmployeeId AS Master,
        EmployeeId,
        ParentEmployeId,
        Name,
        1 as Level
    FROM
        Employees
    WHERE
        ParentEmployeId IS NULL
        
    UNION ALL

    SELECT
         R.Master,
         E.EmployeeId,
         E.ParentEmployeId,
         E.Name,
         R.Level + 1
    FROM
         Employees E
    INNER JOIN
         EmployeeRec R
    ON
         E.ParentEmployeId = R.EmployeeId
)
SELECT
    er.Master,
    er.EmployeeId,
    er.ParentEmployeId,
    er.Name,
    m.Level
FROM
    EmployeeRec er
INNER JOIN
    (
      SELECT
            Master,
            MAX(Level) AS Level
      FROM
            EmployeeRec
      GROUP BY
            Master
   ) m
ON
    m.Master = er.Master
   AND
    m.Level = er.Level

Notes

  • For comparison sake, I left the typo of ParentEmployeId in, even though that messed me up several times as I typed it
  • In the result set, Master represents the root parent, and Level represents the depth (total number of nodes in the specific chain, including this node)

The post mySQL Recursive CTE appeared first on cjhaas blog.

]]>
https://cjhaas.com/2019/10/25/mysql-recursive-cte/feed/ 0
WPDB Insert automatically changing string format to number https://cjhaas.com/2019/10/16/wpdb-insert-automatically-changing-string-format-to-number/ https://cjhaas.com/2019/10/16/wpdb-insert-automatically-changing-string-format-to-number/#respond Wed, 16 Oct 2019 14:22:35 +0000 https://cjhaas.com/?p=941 The third parameter to wpdb::insert() is an array of formats that defaults to %s unless they are overridden in wpdb::$field_types. This is last part is very important. When WordPress boots, it statically sets that list to fields that should always be numbers unless someone specifies an explicit format as the third parameter. Currently there these […]

The post WPDB Insert automatically changing string format to number appeared first on cjhaas blog.

]]>
The third parameter to wpdb::insert() is an array of formats that defaults to %s unless they are overridden in wpdb::$field_types. This is last part is very important. When WordPress boots, it statically sets that list to fields that should always be numbers unless someone specifies an explicit format as the third parameter. Currently there these 34 in the file (I was tripped up by object_id which my system is storing as a string).

    'post_author'      => '%d',
    'post_parent'      => '%d',
    'menu_order'       => '%d',
    'term_id'          => '%d',
    'term_group'       => '%d',
    'term_taxonomy_id' => '%d',
    'parent'           => '%d',
    'count'            => '%d',
    'object_id'        => '%d',
    'term_order'       => '%d',
    'ID'               => '%d',
    'comment_ID'       => '%d',
    'comment_post_ID'  => '%d',
    'comment_parent'   => '%d',
    'user_id'          => '%d',
    'link_id'          => '%d',
    'link_owner'       => '%d',
    'link_rating'      => '%d',
    'option_id'        => '%d',
    'blog_id'          => '%d',
    'meta_id'          => '%d',
    'post_id'          => '%d',
    'user_status'      => '%d',
    'umeta_id'         => '%d',
    'comment_karma'    => '%d',
    'comment_count'    => '%d',
    // multisite:
    'active'           => '%d',
    'cat_id'           => '%d',
    'deleted'          => '%d',
    'lang_id'          => '%d',
    'mature'           => '%d',
    'public'           => '%d',
    'site_id'          => '%d',
    'spam'             => '%d',

You might be tempted to do something like wpdb->insert('table', $values, ['object_id' => '%s']) but that won’t work, either. The logic for looking up a format by columns is only used for the core fields, which you can see here.

If everything to be inserted is a string (or should be inserted as a string) then you can just pass %s or [%s] as the third parameter (the former gets converted to the latter) and WordPress will use it for items.

Unfortunately, if anything else needs to be inserted in a non-string way, you need to explicitly set each placeholder.

(Okay, technically, if your first parameter is a string, you only need to provide formats up till the last non-string, because the logic for missing placeholders is to use the first provided one, but that’s just begging to either break or get yourself punched, possibly by your future self.

The post WPDB Insert automatically changing string format to number appeared first on cjhaas blog.

]]>
https://cjhaas.com/2019/10/16/wpdb-insert-automatically-changing-string-format-to-number/feed/ 0
WP 5.3 – Breaking changes https://cjhaas.com/2019/10/09/wp-5-3-breaking-changes/ https://cjhaas.com/2019/10/09/wp-5-3-breaking-changes/#respond Wed, 09 Oct 2019 13:31:20 +0000 https://cjhaas.com/?p=935 This is pretty big, and I’m guessing that a good number of people that have WP_DEBUG_LOG turned on (like me, sorry Scott) might see it filling up fast when 5.3 lands, and there might be some fatal errors, too. The discussion is here: https://core.trac.wordpress.org/ticket/47678 The gist is that they are introducing some modern PHP-isms (where […]

The post WP 5.3 – Breaking changes appeared first on cjhaas blog.

]]>
This is pretty big, and I’m guessing that a good number of people that have WP_DEBUG_LOG turned on (like me, sorry Scott) might see it filling up fast when 5.3 lands, and there might be some fatal errors, too.

The discussion is here:

https://core.trac.wordpress.org/ticket/47678

The gist is that they are introducing some modern PHP-isms (where “modern” is 5.6 from 2014) and although they fix some performance issues, they do break compatibility with some code.

The fix is overall pretty trivial, basically any code that is overriding core’s code that is changing will need to update function signatures (and it appears that there were about 50 cases of this).

For instance, the old signature might be:

function walk( $elements, $max_depth )

And the new signature would be:

function walk( $elements, $max_depth, ...$args )

No actual logic needs to be changed, just the function/method signature. This is similar to when PHP enforced the __construct() method in 7.0.

The most problematic change is a fatal error (not a warning) with the Walker class which WordPress uses for a lot of different things.

The recommendation is to grep for something like:

find /var/www/ -type f -name "*.php" | grep -v "/wp-includes/" | xargs grep -PHns "function (?:paged_)?walk\s*\(\s*\\$"

Ignore anything from core and only focus on plugins and themes. There will false-positives (specifically there’s something in ACF that matches this but isn’t affected) but you are generally looking for something that has two parameters, $elements and $max_depth. Then just update with the signature above.

For other warnings no related to the Walker class you might just need to poke around and see what’s changed.

The post WP 5.3 – Breaking changes appeared first on cjhaas blog.

]]>
https://cjhaas.com/2019/10/09/wp-5-3-breaking-changes/feed/ 0
Turn on spellcheck for any web page https://cjhaas.com/2019/07/09/turn-on-spellcheck-for-any-web-page/ https://cjhaas.com/2019/07/09/turn-on-spellcheck-for-any-web-page/#respond Tue, 09 Jul 2019 13:38:51 +0000 https://cjhaas.com/?p=930 Bring up the console and enter these two: document.body.contentEditable='true';document.body.spellcheck='true';

The post Turn on spellcheck for any web page appeared first on cjhaas blog.

]]>
Bring up the console and enter these two:

document.body.contentEditable='true';document.body.spellcheck='true';

The post Turn on spellcheck for any web page appeared first on cjhaas blog.

]]>
https://cjhaas.com/2019/07/09/turn-on-spellcheck-for-any-web-page/feed/ 0