Corey Salzano

  • CONTACT
  • Escaping and Translating Text in WordPress

    WordPress core provides developers with a handful of functions to escape string content and enable translations into other languages.

    Translatable Strings

    Access the translated version of text used in plugins or themes with one of the following functions.

    <?php
    echo __( 'Hello', 'text-domain' );
    _e( 'Hello', 'text-domain' );
    echo _x( 'Hello', 'The welcome message', 'text-domain' );

    The first, __(), returns the text.

    The “e” in _e() stands for echo. This function outputs the text.

    The “x” in _x() stands for context and accepts an argument to explain to translators the context of the text.

    Escape for HTML

    Escapes strings so they are not parsed as HTML. Characters like < are converted to &lt;.

    <?php
    echo esc_html( 'Hello' );
    echo esc_html__( 'Hello', 'text-domain' );
    esc_html_e( 'Hello', 'text-domain' );
    echo esc_html_x( 'Hello', 'The welcome message', 'text-domain' );

    Example

    <p><?php esc_html_e( 'Hi there! >:)', 'my-plugin' ); ?></p>

    The above code will render the following HTML:

    <p>Hi there! &gt;:)</p>

    Escape for HTML attributes

    Escape strings used in HTML attributes like class="" so they do not break the HTML.

    <?php
    echo esc_attr( 'Value' );
    echo esc_attr__( 'Value', 'text-domain' );
    esc_attr_e( 'Value', 'text-domain' ); // Outputs the value.
    echo esc_attr_x( 'Value', 'The control value', 'text-domain' );

    Example

    <p><input type="text" value="<?php esc_attr_e( 'Something seems "off"', 'my-plugin' ); ?>" /></p>

    The above code will render the following HTML:

    <p><input type="text" value="Something seems &quot;off&quot;" /></p>

    Escape a URL

    Escape strings inside href="" or src="" attributes.

    <?php
    echo esc_url( 'https://coreysalzano.com/' );

    Escape for textareas

    Prevents the text content of a <textarea> from closing the element early.

    <?php
    echo esc_textarea( 'WordPress core provides developers with a handful of functions to escape string content and enable translations into other languages.' );
    October 26, 2022
  • Microsoft Azure SqlServer

    Check the status of CREATE DATABASE and ALTER DATABASE queries

    SELECT * FROM sys.dm_database_copies

    List all users and roles

    SELECT * FROM sys.database_principals
    October 13, 2022
  • How to convert a Network Active plugin to active on each site

    WordPress multisite allows plugins and themes to be Network Active. This prevents them from being deactivated on any site in the network.

    To change a plugin from Network Active on every site to individually active on each site:

    1. Manually Network Deactivate the plugin from the network plugins page. The wp network command does not yet support plugin deactivation.
    2. Connect to the server via SSH and run this WP CLI command: wp site list --field=url | xargs -n1 -I % wp --url=% plugin activate hello.php (where hello.php is the plugin file or folder name)

    What does the command do?

    wp site list --field=url produces a list of URLs for all of the sites on the network.

    The | operator passes the results from wp site list to xargs. xargs can take the output from one command and send it to another command as parameters.

    The -n1 flag to xargs processes each line of output from the site list command one at a time. -n2 would send two site URLs to the next command.

    wp --url=% plugin activate hello.php is the command to which xargs is passing the site URLs. It activates the Hello Dolly plugin on each site specified by URL. The % sign is our replacement character where each URL will populate.

    May 23, 2022
  • Akismet Alternatives

    Blocking spam on WordPress websites is heavy work. Akismet comes pre-installed on every site, but it’s not free for businesses or the only way to stop spam.

    1. OOPSpam https://www.oopspam.com/
    2. CleanTalk https://cleantalk.org/
    3. Stop Forum Spam https://www.stopforumspam.com/
    4. Project Honey Pot https://www.projecthoneypot.org/
    5. Zero Spam https://www.zerospam.org

    There are a ton of anti-spam WordPress plugins. The criteria for this list of alternatives is “offers an API.”

    Thanks to Austin and Kerch for inspiration and help creating this list.

    April 22, 2022
  • TypeError: c is not a function

    If you’re building blocks for WordPress, and the error TypeError: c is not a function is logged in your browser’s developer console, you may have created a TextControl component and failed to include both value and onChange attributes.

    This code will cause the error:

    <TextControl
    	label={ __( 'Cash/trade', 'invp-payment-calculator' ) }
    	id={ 'trade' }
    	onChange={ changeTradeValue }
    </TextControl>

    This is a correct syntax:

    	label={ __( 'Cash/trade', 'invp-payment-calculator' ) }
    	id={ 'trade' }
    	value={ attributes.trade }
    	onChange={ changeTradeValue }
    </TextControl>
    April 7, 2022
  • Gravity Forms confirmation not working. Instead, “Thanks for contacting us! We will get in touch with you shortly.”

    If you see the default “Thanks for contacting us! We will get in touch with you shortly.” even if you’ve created a custom confirmation for your Gravity Form, your entry may have been marked as spam.

    All entries deemed spam are shown the default message. Login and try again–logged in users will not get caught in the spam filter.

    Also, visit the Entries list in the dashboard, and look for the Spam folder. Your entry may have been saved with the other Spam.

    Where in the Gravity Forms source code does this happen?

    plugins/gravityforms/form_display.php line 3894

    February 23, 2022
  • TypeError: b.map is not a function

    If you’re building blocks for WordPress, and the error TypeError: b.map is not a function is logged in your browser’s developer console, you may have created a SelectControl component and failed to wrap the options in brackets to create an array.

    This code will cause the error:

    			<SelectControl
    				label="Minimum Rating"
    				value={ attributes.minimumRating }
    				options={ 
    					{ label: 'Great Deal', value: 'GREAT_PRICE' },
    					{ label: 'Good Deal', value: 'GOOD_PRICE' },
    					{ label: 'Fair Deal', value: 'FAIR_PRICE' }
    				 }
    				onChange={ onChangeMinimumRating }
    			/>

    This is the correct syntax:

    			<SelectControl
    				label="Minimum Rating"
    				value={ attributes.minimumRating }
    				options={ [
    					{ label: 'Great Deal', value: 'GREAT_PRICE' },
    					{ label: 'Good Deal', value: 'GOOD_PRICE' },
    					{ label: 'Fair Deal', value: 'FAIR_PRICE' }
    				] }
    				onChange={ onChangeMinimumRating }
    			/>
    January 28, 2022
  • Router Circle Jig Calculator

    Router Circle Jig Calculator

    I recently gifted myself a Bosch 1617EVSPK router, and the first project is mounting it to a old Craftsman 171.253512 router table that came with the used contractor table saw I bought myself for my 37th birthday.

    An adapter plate is needed. None of the threaded mounting holes on the fixed router base line up with holes in the table. A friend advised me to cut the plate out of metal or acrylic rather than wood. I may do that. First, I’m making a prototype out of 1/2 inch birch plywood.

    The challenge is that a hole is needed in the center to line up with the hole in the center of the router table. The hole is 2 and 7/8 inches. The first thing you learn when you get a router is that you need a guide for every cut. To cut a hole, you need a bigger hole, or circle jig, in which to run the tool.

    How Big of a Hole do I need to cut a Hole?

    What size circle jig is needed to cut a 2 and 7/8″ circle? Well, what size is the router base plate, and what size is the bit? The answer for me was 9 inches. I made a circle jig calculator spreadsheet to help you calculate your own answer: https://docs.google.com/spreadsheets/d/1j-HHztDr0gRN3G3gc9z6VhBRuo2sOvzG_dBccMmtVgg/edit?usp=sharing

    A screenshot of a calculator built in a Google Sheet

    Is this silly? Is there an easier way to do this? Please, let me know.

    January 24, 2022
  • Trouble with PHP versions after migrating to an M1 Macbook

    I migrated a Time Machine backup from a 2015 Intel High Sierra to a 2021 M1 Monterey. I love the computer, and the migration was largely a success.

    I use Laravel Valet to run and develop local websites. They break every time I restart the new machine. php -v from Terminal always returns 8.0, but calling phpInfo(); from one of the local sites reveals PHP 7.2.34 is running and none of the sites can find MySQL.

    If I run valet use [email protected], I get: Valet is already using version: [email protected]. To re-link and re-configure use the --force parameter.

    Then I run valet use [email protected] --force and I get this output:

    Unlinking current version: [email protected]
    Linking new version: [email protected]
    Updating PHP configuration...
    Restarting [email protected]
    Restarting nginx...
    Valet is now using [email protected]
    

    And I’m fine until I reboot the machine again.

    What’s broken?

    I suspect this has something to do with having to install a different version of homebrew for the M1 processor architecture and the old version of homebrew still existing because of the migration, but I don’t understand what is happening.

    Things I’ve Tried

    • valet install
      Updating valet does not fix this problem.
    January 13, 2022
  • Gravity View is_approved enumeration

    Entry approval is a Gravity View feature I use often. Even if I’m not using Gravity View on a project that needs to filter out some entries, I’ll save the same data in the $wpdb->_gf_entry_meta table to be compatible. The meta key is_approved contains one of the values in the table below.

    Entry is_approved meta values

    IconValueDefinition
    1Approved
    2Disapproved
    3No choice made/reset

    March 24, 2021
  • Mimic the WordPress.org developer reference for your project

    I replicated wordpress.org’s code reference system for my own project.

    WordPress provides a template tag get_the_title() and it’s documented at https://developer.wordpress.org/reference/functions/get_the_title/.

    A plugin I just launched provides a template tag invp_get_the_price() and it’s documented at https://inventorypresser.com/docs/reference/functions/invp_get_the_price/

    I learned that the .org docs page content is generated by scanning the project source code, extracting PHPDoc comments, and parsing them into custom post types. The piece of software that does that is https://github.com/WordPress/phpdoc-parser.

    Build the Data

    1. Add PHPDoc comments to all classes and methods in your plugin.
    2. Use a server that provides the WordPress Command Line Interface.
    3. Upload your plugin to the site where you want to generate documentation.
    4. Activate the phpdoc-parser plugin on the same site
    5. Connect via SSH and run a wp-cli command similar to wp parser create ../../sites/inventorypress/wp-content/plugins/inventory-presser/ --user=corey
      1. Replace the path with a path to the plugin for which you want documentation.
      2. Change the user name to the name of an administrator on your site.

    Build the Theme

    WordPress.org uses a handful of themes at once. The developer reference pieces live in the wporg-developer theme.

    Take Files from wporg-developer

    SIDE NOTE: I would like to include wporg-developer in my theme or child theme instead of copying files, but step 2 below makes it hard to use wporg-developer as a dependency. It must be edited. I would enjoy having easy access to updates, and perhaps I could contribute to the theme to add necessary filters someday in the future.

    How to download wordpress.org source code

    This SVN command will download the whole theme. Paste the command into a terminal or command prompt window:

    svn co https://meta.svn.wordpress.org/sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/

    Copy these files from wporg-developer into your child theme

    • /inc
    • /js
    • /reference
    • /stylesheets
    • content-reference.php
    • content-reference-archive.php
    • functions.php (comingle it with your functions.php)

    Theme Mods

    1. Change option value wp_parser_root_import_dir to contain a path to the project. For me, this path points to a plugin in the wp-content/plugins folder.
    2. Change get_template_directory_uri() calls to get_stylesheet_directory_uri() calls
    3. Create single.php by taking a copy from the parent theme. Modify it to serve a different content template for the post types populated by phpdoc-parser. Here is a code sample that shows what to change to create a Twenty Twenty-One child theme.
    4. Optional: Change “View on Trac” links
      I added two filters that wrap the URL and the text in the “View on Trac” link below the source code section of each page. These changes allow me to change the links to “View on Github” or wherever I want.
      1. wp-parser_source_url_base line 1173 of template-tags.php
      2. wp-parser_view_on_trac_link_text in a few places in template-source.php

    Twenty Twenty-One Child Theme

    Download a Twenty Twenty-One child theme with the files listed and mods 1-3 completed: https://github.com/csalzano/twentytwentyone-wporg-child

    Also Run This Plugin

    SyntaxHighlighter Evolved styles the source code editors.

    Troubleshooting

    Missing Source Code

    If no source code is displaying, edit the option wp_parser_root_import_dir to contain a full path to the directory of the plugin. Example: /corey/sites/inventorypress/wp-content/plugins/inventory-presser

    My Observations So Far

    1. I love it, but I didn’t try anything else. Writing code comments is now also writing web pages and a great motivator to do it right.
    2. Done! See Add-on Plugins phpdoc-parser reruns do not delete items. I need to write code that deletes functions, methods, hooks, and classes that are removed from the project.
    3. Done! See Automating Updates to Docs I want to write a Github action to automate wp-parser runs on new versions of the plugin. When I push updates to the public repo, a copy of the plugin is written to the webserver, and wp-parser is run to generate new docs.

    Automating Updates to Docs

    Four months after I published this post, I designed a Github Action to automate the creation and updating of the docs pages. When I push to the master branch of my plugin’s repo, the plugin is deployed to the site on WP Engine where the docs pages are hosted, and the wp-cli command that generates the docs is run.

    Here is the workflow file that defines the Action at Github: https://github.com/fridaysystems/inventory-presser/blob/master/.github/workflows/main.yml

    It contains one job with two steps that are marked with these comments:

    • # Deploy to WP Engine
    • # Run phpdoc-parser to Build Documentation

    Add-on Plugins

    I wrote two add-on plugins to modify the behavior of phpdoc-parser.

    1. phpdoc-ignorer instructs phpdoc-parser to ignore the /vendor folder in my plugin
    2. phpdoc-deleter keeps track of every post created or updated by phpdoc-parser. After the run is complete, it deletes all posts that were not touched and then empty taxonomy terms.
    March 16, 2021
  • Entries To Google Sheet, an add-on for Gravity Forms

    I built a WordPress plugin that saves a copy of all Gravity Forms entries in a Google Sheet as they are received. Entries to Google Sheet is the glue between a Gravity Form and a Google Sheet.

    https://entriestogooglesheet.com

    February 16, 2021
1 2 3 … 9
Next Page→

Corey Salzano

Proudly powered by WordPress