{"id":1829,"date":"2020-07-31T21:16:00","date_gmt":"2020-07-31T14:16:00","guid":{"rendered":"https:\/\/wptips.dev\/?p=1829"},"modified":"2021-03-01T19:48:16","modified_gmt":"2021-03-01T12:48:16","slug":"spaghetti-code-wp","status":"publish","type":"post","link":"https:\/\/pixelstudio.id\/blog\/spaghetti-code-wp\/","title":{"rendered":"7 Tips to Avoid Spaghetti Code in WordPress (and PHP)"},"content":{"rendered":"\n<p>PHP is infamous to be a messy language in the developer world. That&#8217;s because it allows bad code to run.<\/p>\n\n\n\n<p>And WordPress runs on PHP which <strong>inherits the same problem<\/strong>.<\/p>\n\n\n\n<p>Let&#8217;s take a look at several tips to avoid that:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #1: Group Up Filters &amp; Actions<\/h2>\n\n\n\n<p>The snippet below is a common mistake I see in themes and plugins. You can&#8217;t see what this file does unless you scroll until the very end.<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-wrong\"><code lang=\"php\" class=\"language-php\">add_action( 'after_setup_theme', 'my_theme_supports' );\nfunction my_theme_supports() {\n  \/\/ ...\n}\n\nadd_action( 'wp_enqueue_scripts', 'my_public_assets', 99 );\nfunction my_public_assets() {\n  \/\/ ...\n}\n\nadd_action( 'widgets_init', 'my_register_sidebar' );\nfunction my_register_sidebar() {\n  \/\/ ...\n}<\/code><\/pre>\n\n\n\n<p>This is fixed simply by grouping the <code>add_action<\/code> and <code>add_filter<\/code> in one place:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-correct\"><code lang=\"php\" class=\"language-php\">add_action( 'after_setup_theme', 'my_theme_supports' );\nadd_action( 'wp_enqueue_scripts', 'my_public_assets', 99 );\nadd_action( 'widgets_init', 'my_register_sidebar' );\n\n\nfunction my_theme_supports() {\n  \/\/ ...\n}\n\nfunction my_public_assets() {\n  \/\/ ...\n}\n\nfunction my_register_sidebar() {\n  \/\/ ...\n}<\/code><\/pre>\n\n\n\n<p>Now you only need to read the top part to see everything that file does.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #2: Use Variable for Long Expression<\/h2>\n\n\n\n<p>For example, you want to check if a visitor is using Internet Explorer. You might create a function like this:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-wrong\"><code lang=\"php\" class=\"language-php\">function is_browser_ie() {\n  \/\/ is IE10 or IE11\n  return preg_match('~MSIE|Internet Explorer~i', $_SERVER['HTTP_USER_AGENT']) ||\n    preg_match('~Trident\/7.0(; Touch)?; rv:11.0~',$_SERVER['HTTP_USER_AGENT']);\n}<\/code><\/pre>\n\n\n\n<p>There&#8217;s nothing wrong with that, but it&#8217;s clearer if you write it like this:<\/p>\n\n\n\n<pre title=\"\" class=\"wp-block-code is-style-correct\"><code lang=\"php\" class=\"language-php\">function is_browser_ie() {\n  $is_ie10 = preg_match('~MSIE|Internet Explorer~i', $_SERVER['HTTP_USER_AGENT']);\n  $is_ie11 = preg_match('~Trident\/7.0(; Touch)?; rv:11.0~',$_SERVER['HTTP_USER_AGENT']);\n\n  return $is_ie10 || $is_ie11;\n}<\/code><\/pre>\n\n\n\n<p>The general idea is to <strong>use fewer inline comments.<\/strong> Because a lot of inline comments actually made your code harder to read.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #3: Conditional Return Early<\/h2>\n\n\n\n<p>Let&#8217;s say you want to register a new Gutenberg style. You must first check whether Gutenberg is enabled or not. So you might do this:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-wrong\"><code lang=\"php\" class=\"language-php\">add_action( 'init', my_register_block_styles );\n\nfunction my_register_block_styles() {\n  \/\/ if Gutenberg is active\n  if ( function_exists( 'register_block_type' ) ) {\n    register_block_style( 'core\/heading', [\n      'name' =&gt; 'has-underline',\n      'label' =&gt; 'Has Underline'\n    ] );\n\n    register_block_style( 'core\/buttons', [\n      'name' =&gt; 'transparent',\n      'label' =&gt; 'Transparent'\n    ] );\n  }\n}<\/code><\/pre>\n\n\n\n<p>Seems good? Yes, but there&#8217;s a better way:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-correct\"><code lang=\"php\" class=\"language-php\">add_action( 'init', my_register_block_styles );\n\nfunction my_register_block_styles() {\n  \/\/ if Gutenberg is not active\n  if ( !function_exists( 'register_block_type' ) ) { return; }\n  \n  register_block_style( 'core\/heading', [\n    'name' =&gt; 'has-underline',\n    'label' =&gt; 'Has Underline'\n  ] );\n\n  register_block_style( 'core\/buttons', [\n    'name' =&gt; 'transparent',\n    'label' =&gt; 'Transparent'\n  ] );\n}<\/code><\/pre>\n\n\n\n<p>You break the function early when the condition is not met. This way you keep the indentation as low as possible, making it easier to read. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #4: Split functions.php into Several Files<\/h2>\n\n\n\n<p>Your functions file can easily grow big. It is best if you split the related chunk of codes into its own file.<\/p>\n\n\n\n<p>It&#8217;s up to you how you organize it. My personal preference is to create a folder named <code>functions\/<\/code> and split them like this:<\/p>\n\n\n\n<ul><li><code>admin.php<\/code> &#8211; Hooks that affect the admin panel.<\/li><li><code>frontend.php<\/code> &#8211; Hooks that affect the front-end site.<\/li><li><code>helpers.php<\/code> &#8211; Reusable utility functions.<\/li><li><code>setup.php<\/code> &#8211; Hooks that initialize the site. It includes: theme support, custom post type, enqueue assets, register widget.<\/li><li><code>timber.php<\/code> &#8211; If you&#8217;re using <a rel=\"noreferrer noopener\" href=\"https:\/\/pixelstudio.id\/blog\/what-is-timber-library\/\" target=\"_blank\">Timber plugin<\/a>. Contains the global variable and custom filter (<a rel=\"noreferrer noopener\" href=\"https:\/\/pixelstudio.id\/blog\/global-var-n-filters-in-timber\/\" target=\"_blank\">Learn How<\/a><a href=\"https:\/\/www.toptal.com\/designers\/htmlarrows\/punctuation\/double-right-pointing-angle-quotation-mark\/\"> \u00bb<\/a>)<\/li><li><code>shop.php<\/code> &#8211; If you&#8217;re using WooCommerce.<\/li><\/ul>\n\n\n\n<p>Then your functions.php only acts as a gateway:<\/p>\n\n\n\n<pre title=\"functions.php\" class=\"wp-block-code\"><code lang=\"php\" class=\"language-php\">$function_dir = __DIR__ . '\/functions';\n\nrequire_once $function_dir . '\/helpers.php';\nrequire_once $function_dir . '\/setup.php';\n\nif( is_admin() ) {\n  require_once $function_dir . '\/admin.php';\n} else {\n  require_once $function_dir . '\/frontend.php';\n  require_once $function_dir . '\/timber.php';\n}\n\nif( class_exists('WooCommerce') ) {\n  require_once $function_dir . '\/shop.php';\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #5: Utilize WordPress Native Functions<\/h2>\n\n\n\n<p>I often see themes and plugins re-create a function that is already provided by WordPress. Most likely because they&#8217;re not aware of them.<\/p>\n\n\n\n<p>So I recommend scanning through the list of functions here <a href=\"https:\/\/codex.wordpress.org\/Function_Reference\">codex.wordpress.org\/Function_Reference<\/a><\/p>\n\n\n\n<p>One day when you need it, you will vaguely remember that there&#8217;s a function for that. Then you can find it with Google search.<\/p>\n\n\n\n<p>Below are some useful native WP functions:<\/p>\n\n\n\n<ul><li><code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_is_mobile\/\" target=\"_blank\">wp_is_mobile<\/a><\/code> &#8211; Check if the visitor is using a mobile browser.<\/li><li><code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/human_time_diff\/\" target=\"_blank\">human_time_diff<\/a><\/code> &#8211; Compares two dates and shows them in a relative format like &#8220;3 days ago&#8221;.<\/li><li><code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_trim_words\/\" target=\"_blank\">wp_trim_words<\/a><\/code> &#8211; Cut a string into a certain number of words.<\/li><li><code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_redirect\/\" target=\"_blank\">wp_redirect<\/a><\/code> &#8211; Redirect to specified URL.<\/li><li><code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_remote_post\/\" target=\"_blank\">wp_remote_post<\/a><\/code> &#8211; Post API request.<\/li><li><code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_remote_get\/\" target=\"_blank\">wp_remote_get<\/a><\/code> &#8211; Get API request.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #6: Define Available Arguments<\/h2>\n\n\n\n<p>If you create a function that accepts arguments, define the available one with <code><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_parse_args\/\" target=\"_blank\" rel=\"noreferrer noopener\">wp_parse_args<\/a><\/code>. This will also set the default value.<\/p>\n\n\n\n<p>For example, take a look at the native <code><a rel=\"noreferrer noopener\" href=\"https:\/\/developer.wordpress.org\/reference\/functions\/get_posts\/\" target=\"_blank\">get_posts()<\/a><\/code> function:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-correct\"><code lang=\"php\" class=\"language-php\">function get_posts( $args = null ) {\n  \n  $parsed_args = wp_parse_args( $args, [\n    'numberposts'      =&gt; 5,\n    'category'         =&gt; 0,\n    'orderby'          =&gt; 'date',\n    'order'            =&gt; 'DESC',\n    'include'          =&gt; [],\n    'exclude'          =&gt; [],\n    'meta_key'         =&gt; '',\n    'meta_value'       =&gt; '',\n    'post_type'        =&gt; 'post',\n    'suppress_filters' =&gt; true,\n  ] );\n\n  \/\/ ...\n}<\/code><\/pre>\n\n\n\n<p>Having all the possible arguments laid out like that will make it easy for another developer to know what to pass on. It&#8217;s also a good reminder for you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tip #7: Separate Template Into Its Own File<\/h2>\n\n\n\n<p>Mixing logic and template code will lead to messy code. That&#8217;s just how it is. <\/p>\n\n\n\n<p>For example, we are making a function to display <strong>Related Posts<\/strong> like this:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-wrong\"><code lang=\"php\" class=\"language-php\">&lt;?php\nfunction output_related_posts() {\n  global $post;\n\n  \/\/ get categories\n  $category = get_the_category( $post->ID );\n  $category_ids = [];\n  foreach( $category as $c ) {\n    $category_ids[] = $c->term_id;\n  }\n\n  \/\/ get posts with same categories, randomly\n  $posts = get_posts([\n    'category' => $category_ids,\n    'post_type'\u00a0=>\u00a0'post',\n    'posts_per_page' => 3,\n    'orderby' => 'rand',\n    'post__not_in' => [$post->ID]\n  ]);\n\n  ?>\n  &lt;ul class=\"recent-posts\">\n  &lt;?php foreach( $posts as $p ): ?>\n    \n    &lt;li class=\"post-thumbnail\">\n      &lt;a href=\"&lt;?php echo get_permalink( $p ); ?>\">\n        &lt;?php echo get_the_post_thumbnail( $p, 'thumbnail' ); ?>\n        &lt;h3>&lt;?php echo $p->post_title; ?>&lt;\/h3>\n        &lt;time>&lt;?php echo get_the_date( '', $p ); ?>&lt;\/time>\n        &lt;p>&lt;?php echo $p->post_excerpt; ?>&lt;\/p>\n      &lt;\/a>\n    &lt;\/li>\n\n  &lt;?php endforeach; ?>\n  &lt;\/ul>\n  &lt;?php\n}<\/code><\/pre>\n\n\n\n<p>That coding style is common in PHP. But if you have ventured to other programming languages, you will notice how dirty it actually is.<\/p>\n\n\n\n<p>One way to fix this is to <strong>split the template into its own file<\/strong> and use <code>get_template_part()<\/code> like shown below:<\/p>\n\n\n\n<pre class=\"wp-block-code is-style-correct\"><code lang=\"php\" class=\"language-php\">&lt;?php\nfunction output_related_posts() {\n\u00a0\u00a0global\u00a0$post;\n\n\u00a0\u00a0\/\/\u00a0get\u00a0categories\n\u00a0\u00a0$category\u00a0=\u00a0get_the_category(\u00a0$post->ID\u00a0);\n\u00a0\u00a0$category_ids\u00a0=\u00a0[];\n\u00a0\u00a0foreach(\u00a0$category\u00a0as\u00a0$c\u00a0)\u00a0{\n\u00a0\u00a0\u00a0\u00a0$category_ids[]\u00a0=\u00a0$c->term_id;\n\u00a0\u00a0}\n\n\u00a0\u00a0\/\/\u00a0get\u00a0posts\u00a0with\u00a0same\u00a0categories,\u00a0randomly\n\u00a0\u00a0$posts\u00a0=\u00a0get_posts([\n\u00a0\u00a0\u00a0\u00a0'category'\u00a0=>\u00a0$category_ids,\n\u00a0\u00a0\u00a0\u00a0'post_type'\u00a0=>\u00a0'post',\n\u00a0\u00a0\u00a0\u00a0'posts_per_page'\u00a0=>\u00a03,\n\u00a0\u00a0\u00a0\u00a0'orderby'\u00a0=>\u00a0'rand',\n\u00a0\u00a0\u00a0\u00a0'post__not_in'\u00a0=>\u00a0[$post->ID]\n\u00a0\u00a0]);\n\n\u00a0\u00a0get_template_part(\u00a0'views\/related-posts',\u00a0'',\u00a0[\n\u00a0\u00a0\u00a0\u00a0'posts'\u00a0=>\u00a0$posts\n\u00a0\u00a0]\u00a0);\n}<\/code><\/pre>\n\n\n\n<pre title=\"views\/related-posts.php\" class=\"wp-block-code is-style-correct\"><code lang=\"php\" class=\"language-php\">&lt;ul\u00a0class=\"recent-posts\">\n&lt;?php\u00a0foreach(\u00a0$args['posts']\u00a0as\u00a0$p\u00a0):\u00a0?>\n\u00a0\u00a0\n\u00a0\u00a0&lt;li\u00a0class=\"post-thumbnail\">\n\u00a0\u00a0\u00a0\u00a0&lt;a\u00a0href=\"&lt;?php\u00a0echo\u00a0get_permalink(\u00a0$p\u00a0);\u00a0?>\">\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;?php\u00a0echo\u00a0get_the_post_thumbnail(\u00a0$p,\u00a0'thumbnail'\u00a0);\u00a0?>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;h3>&lt;?php\u00a0echo\u00a0$p->post_title;\u00a0?>&lt;\/h3>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;time>&lt;?php\u00a0echo\u00a0get_the_date(\u00a0'',\u00a0$p\u00a0);\u00a0?>&lt;\/time>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;p>&lt;?php\u00a0echo\u00a0$p->post_excerpt;\u00a0?>&lt;\/p>\n\u00a0\u00a0\u00a0\u00a0&lt;\/a>\n\u00a0\u00a0&lt;\/li>\n\n&lt;?php\u00a0endforeach;\u00a0?>\n&lt;\/ul><\/code><\/pre>\n\n\n\n<p class=\"has-light-blue-background-color has-background has-small-font-size\">Note: This only works in WordPress version 5.5 and above.<\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-dots\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>There are a lot of themes and plugins with messy codes out there. We can&#8217;t control them, but at the very least our code shouldn&#8217;t fall into the same pit hole.<\/p>\n\n\n\n<p>After this, I suggest reading <a href=\"https:\/\/phptherightway.com\/\">phptherightway.com<\/a>. It has a complete collection of popular PHP coding standards.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Do you have a best practice that you want to share? Feel free to share it in the comment section below \ud83d\ude42<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>PHP is infamous to be a messy language. And WordPress runs on PHP which inherits the same problem. Let&#8217;s learn how to avoid that<\/p>\n","protected":false},"author":1,"featured_media":1842,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[47,31],"class_list":["post-1829","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general","tag-best-practice","tag-php"],"blocksy_meta":"","_links":{"self":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts\/1829","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/comments?post=1829"}],"version-history":[{"count":11,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts\/1829\/revisions"}],"predecessor-version":[{"id":2096,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/posts\/1829\/revisions\/2096"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/media\/1842"}],"wp:attachment":[{"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/media?parent=1829"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/categories?post=1829"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pixelstudio.id\/blog\/wp-json\/wp\/v2\/tags?post=1829"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}