<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Zen Cart Documentation – Admin</title>
    <link>https://docs.zen-cart.com/dev/admin/</link>
    <description>Recent content in Admin on Zen Cart Documentation</description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="https://docs.zen-cart.com/dev/admin/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Dev: Admin Request Sanitization</title>
      <link>https://docs.zen-cart.com/dev/admin/admin_sanitization/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/admin_sanitization/</guid>
      <description>
        
        
        &lt;p&gt;The Admin Sanitization features use a number of sanitization groups. Each group performs a sanitization on specific GET/POST parameters.
For GET/POST parameters that are not already sanitized within these groups we then run a default sanitization
(i.e.: simply running &lt;code&gt;htmlspecialchars()&lt;/code&gt; on it).&lt;/p&gt;
&lt;h2 id=&#34;why-sanitize&#34;&gt;Why Sanitize?&lt;/h2&gt;
&lt;p&gt;Historically, weaker sanitization was used for two reasons:&lt;/p&gt;
&lt;p&gt;Firstly, Admin allows lots of parameters to include what would be considered dangerous characters.
e.g. product descriptions allow script tags, and other inputs allow some html, such as product names.&lt;/p&gt;
&lt;p&gt;Secondly, core code uses CSRF tokens for all form interactions. The use of these tokens mitigates against any exploiting of XSS, unless an admin session is already available.&lt;/p&gt;
&lt;p&gt;However, reports such as &lt;a href=&#34;https://www.trustwave.com/Resources/SpiderLabs-Blog/TWSL2016-006--Multiple-XSS-Vulnerabilities-reported-for-Zen-Cart/&#34;&gt;https://www.trustwave.com/Resources/SpiderLabs-Blog/TWSL2016-006--Multiple-XSS-Vulnerabilities-reported-for-Zen-Cart/&lt;/a&gt;
made us reconsider.
While we still contend that the CSRF protection mitigates these supposed XSS vulnerabilities, there are three good reasons to address them with extra sanitization:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We cannot guarantee that 3rd party plugins use the CSRF token system (although there are some safeties to ensure they do).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PCI scanning software may detect XSS vulnerabilities, even given the CSRF mitigation. (particularly where the scanner bypasses/grants admin logins)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Good security practice.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;temporarily-disabling-strict-sanitization&#34;&gt;TEMPORARILY Disabling Strict Sanitization&lt;/h2&gt;
&lt;p&gt;If you find that some of your pre-v1.5.5 admin plugins are no longer working properly then you should look first to see if new
versions of those plugins are available, i.e.: that support the sanitization methods implemented since v1.5.5.&lt;/p&gt;
&lt;p&gt;If new versions are not available, or you need to keep your current admin working while you update, then you can disable
the strict(default) sanitization by doing the following:&lt;/p&gt;
&lt;p&gt;Create a new &lt;code&gt;disable_strict_sanitize.php&lt;/code&gt; file in your &lt;code&gt;/admin/includes/extra_configures/&lt;/code&gt; directory.
The contents of this file should be&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  &amp;lt;?php
  define(&amp;#39;DO_STRICT_SANITIZATION&amp;#39;, false);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We encourage you to NOT do that unless truly necessary, and even then only as a temporary measure until your affected plugins have written their own custom sanitizers as described later in this document.&lt;/p&gt;
&lt;h2 id=&#34;logging&#34;&gt;Logging&lt;/h2&gt;
&lt;p&gt;The AdminSanitizer class can log the actions it takes, and this may be helpful in debugging problems with plugins.&lt;/p&gt;
&lt;p&gt;Logging is enabled/disabled using the DO_DEBUG_SANITIZATION define.&lt;/p&gt;
&lt;p&gt;To enable logging create a new file in &lt;code&gt;/admin/includes/extra_configures/&lt;/code&gt; that contains&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  &amp;lt;?php
  define(&amp;#39;DO_DEBUG_SANITIZATION&amp;#39;, true);
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;for-developers-how-to-use-the-sanitization-in-plugins&#34;&gt;For Developers. How to use the sanitization in plugins.&lt;/h2&gt;
&lt;p&gt;If you are a developer who wants to update your current code, or you are developing a new plugin, the following
are some tips to keep your plugin compatible with core functionality.&lt;/p&gt;
&lt;h3 id=&#34;parameter-naming&#34;&gt;Parameter Naming&lt;/h3&gt;
&lt;p&gt;GET/POST parameters will be sanitized based on their parameter name and the sanitization group assigned to them.
Therefore, if you are writing a plugin and use a parameter name that already exists in Zen Cart that parameter will be
sanitized according to the group it is already assigned to in core code.&lt;/p&gt;
&lt;p&gt;For example, the &lt;code&gt;action&lt;/code&gt; parameter is assigned to the &lt;code&gt;SIMPLE_ALPHANUM_PLUS&lt;/code&gt; group, and the sanitization for that group
will always be applied to it.&lt;/p&gt;
&lt;p&gt;There will be occasions where a plugin uses a parameter name that is already added to a sanitization group, and rewriting
plugin code may be onerous. For these cases it is possible to override sanitization on a per page basis.&lt;/p&gt;
&lt;h3 id=&#34;adding-parametersgroups&#34;&gt;Adding Parameters/Groups&lt;/h3&gt;
&lt;p&gt;If a plugin needs to define its own sanitization or override the sanitization for an already defined parameter, it
should create a php file in &lt;code&gt;/admin/includes/extra_datafiles/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;An example of the contents might be&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$sanitizer = AdminRequestSanitizer::getInstance();
$group = array(
    &#39;id&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CONVERT_INT&#39;, &#39;method&#39; =&amp;gt; &#39;both&#39;, &#39;pages&#39; =&amp;gt; array(&#39;edit_orders&#39;), &#39;params&#39; =&amp;gt; array()),
    );
$sanitizer-&amp;gt;addComplexSanitization($group);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$sanitizer = AdminRequestSanitizer::getInstance();
$group = array(
  &#39;col_html_text&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;PRODUCT_DESC_REGEX&#39;, &#39;method&#39; =&amp;gt; &#39;post&#39;),
    );
$sanitizer-&amp;gt;addComplexSanitization($group);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The structure of the defining array is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;sanitizerType = The name of a sanitizer group (see the group names below)&lt;/li&gt;
&lt;li&gt;method = get|post|both&lt;/li&gt;
&lt;li&gt;pages = (optional) an array of pages which this sanitizer rule will be applied to; (if not supplied, will apply to all pages)&lt;/li&gt;
&lt;li&gt;params = (optional) this is used only for the MULTI_DIMENSIONAL sanitizer, which is explained below.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;rsquo;s a specific example from the &lt;a href=&#34;https://www.zen-cart.com/downloads.php?do=file&amp;amp;id=2264&#34;&gt;News Box Manager&lt;/a&gt; plugin.  The file &lt;code&gt;admin/includes/extra_datafiles/news_box_manager_sanitization.php&lt;/code&gt; sanitizes the fields &lt;code&gt;news_title&lt;/code&gt; and &lt;code&gt;news_content&lt;/code&gt; when they are updated:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;if (class_exists(&amp;#39;AdminRequestSanitizer&amp;#39;) &amp;amp;&amp;amp; method_exists(&amp;#39;AdminRequestSanitizer&amp;#39;, &amp;#39;getInstance&amp;#39;)) {
    $news_mgr_sanitizer = AdminRequestSanitizer::getInstance();
    $news_mgr_sanitizer-&amp;gt;addSimpleSanitization(&amp;#39;PRODUCT_DESC_REGEX&amp;#39;, array(&amp;#39;news_title&amp;#39;, &amp;#39;news_content&amp;#39;));
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;pages&lt;/code&gt; parameter is not specified here because this particular plugin
is designed for easy extension, so that pages can be added simply by copying a single file (and requiring someone to modify this file as well
to add the new page would be contrary to that intention.)&lt;/p&gt;
&lt;h3 id=&#34;general-sanitization-groups&#34;&gt;General Sanitization Groups&lt;/h3&gt;
&lt;p&gt;Zen Cart defines the following default case-insensitive sanitizers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SIMPLE_ALPHANUM_PLUS&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;GET and POST Values&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;[^\/ 0-9a-zA-Z_:@.-]&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;CONVERT_INT&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;GET and POST values&lt;/p&gt;
&lt;p&gt;converts value to Integer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;FILE_DIR_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST values only&lt;/p&gt;
&lt;p&gt;uses &lt;code&gt;[^0-9a-z.!@#$%^&amp;amp;()_-~`+^ \\]&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ALPHANUM_DASH_UNDERSCORE&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;GET and POST values&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;[^a-z0-9_-]&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;WORDS_AND_SYMBOLS_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;GET and POST values&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;(&amp;lt;\/?scri|on(load|mouse|error|read|key)(up|down)? ?=|[^(class|style)] ?= ?(\(|&amp;quot;)|&amp;lt;!)&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;META_TAGS&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST Values only (Deep)&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;htmlspecialchars($_POST[$parameterName][$pKey], ENT_COMPAT, $this-&amp;gt;charset, false)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SANITIZE_EMAIL&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;GET and POST values&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;filter_var($_POST[$key], FILTER_SANITIZE_EMAIL)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SANITIZE_EMAIL_AUDIENCE&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST values only&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;htmlspecialchars($_POST[$parameterName], ENT_COMPAT, $this-&amp;gt;charset, true)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;PRODUCT_URL_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST values only (Deep)&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;([^0-9a-z&#39;.!@#$%&amp;amp;()_-~/;:=?[]]|[&amp;gt;&amp;lt;])&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;PRODUCT_DESC_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST Values only (Deep)&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;(load=|= ?\(|&amp;lt;![^-])&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;CURRENCY_VALUE_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST Values only&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;[^a-z0-9_,\.\-]&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;FLOAT_VALUE_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST Values only&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;[^0-9,\.\-\+]&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;PRODUCT_NAME_DEEP_REGEX&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;POST Values only (Deep)&lt;/p&gt;
&lt;p&gt;Uses &lt;code&gt;(&amp;lt;\/?scri|on(load|mouse|error|read|key)(up|down)? ?=|[^(class|style)] ?= ?(\(|&amp;quot;)|&amp;lt;!)&lt;/code&gt; regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;NULL_ACTION&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;GET/POST Values&lt;/p&gt;
&lt;p&gt;Skips sanitization for the relevant parameter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;STRICT_SANITIZE_VALUES&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Any parameters not previously sanitized will be sanitized with this method.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;STRICT_SANITIZE_KEYS&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;All POST and GET &amp;ldquo;keys&amp;rdquo; containing any &lt;code&gt;&amp;lt;&lt;/code&gt; or &lt;code&gt;&amp;gt;&lt;/code&gt; symbols in the key will be &lt;code&gt;unset()&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;multi_dimensional-sanitization&#34;&gt;MULTI_DIMENSIONAL Sanitization&lt;/h3&gt;
&lt;p&gt;The MULTI_DIMENSIONAL sanitizer is special in that it defines sanitization for an array of parameters, rather
than one parameter as other sanitizers do.&lt;/p&gt;
&lt;p&gt;For example, if you post the following array&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[update_products] =&amp;gt; Array
    (
        [13] =&amp;gt; Array
            (
                [qty] =&amp;gt; 1
                [name] =&amp;gt; Microsoft IntelliMouse Explorer
                [onetime_charges] =&amp;gt; 0.0000
                [attr] =&amp;gt; Array
                    (
                        [3] =&amp;gt; Array
                            (
                                [value] =&amp;gt; 11
                                [type] =&amp;gt; 0
                            )

                    )

                [model] =&amp;gt; MSIMEXP
                [tax] =&amp;gt; 0
                [final_price] =&amp;gt; 70.95  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;normal sanitizers would only address the outer &lt;code&gt;update_products&lt;/code&gt; parameter, while what you really want to do is define
parameters for &lt;code&gt;qty&lt;/code&gt; &lt;code&gt;name&lt;/code&gt; &lt;code&gt;onetime_charges&lt;/code&gt; etc, and you also want to sanitize the attr sub array recursively.&lt;/p&gt;
&lt;p&gt;to address this, you can define a MULTI_DIMENSIONAL sanitizer like this:-&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$sanitizer = AdminRequestSanitizer::getInstance();
$group = array(
    &#39;update_products&#39; =&amp;gt; array(
        &#39;sanitizerType&#39; =&amp;gt; &#39;MULTI_DIMENSIONAL&#39;,
        &#39;method&#39; =&amp;gt; &#39;post&#39;,
        &#39;pages&#39; =&amp;gt; array(&#39;edit_orders&#39;),
        &#39;params&#39; =&amp;gt; array(
            &#39;update_products&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CONVERT_INT&#39;),
            &#39;qty&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CONVERT_INT&#39;),
            &#39;name&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;WORDS_AND_SYMBOLS_REGEX&#39;),
            &#39;onetime_charges&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CURRENCY_VALUE_REGEX&#39;),
            &#39;attr&#39; =&amp;gt; array(
                &#39;sanitizerType&#39; =&amp;gt; &#39;MULTI_DIMENSIONAL&#39;,
                &#39;params&#39; =&amp;gt; array(
                    &#39;attr&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CONVERT_INT&#39;),
                    &#39;value&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CONVERT_INT&#39;),
                    &#39;type&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;CONVERT_INT&#39;)
                )
            ),
            &#39;model&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;WORDS_AND_SYMBOLS_REGEX&#39;),
            &#39;tax&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;WORDS_AND_SYMBOLS_REGEX&#39;),
            &#39;final_price&#39; =&amp;gt; array(&#39;sanitizerType&#39; =&amp;gt; &#39;WORDS_AND_SYMBOLS_REGEX&#39;),
        )
    )
);
$sanitizer-&amp;gt;addComplexSanitization($group);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that sanitizers for sub parameters are defined in the &lt;code&gt;params&lt;/code&gt; array and that you can recursively define
deeper arrays with a further MULTI_DIMENSIONAL sanitizer array.&lt;/p&gt;
&lt;h3 id=&#34;custom-sanitizers&#34;&gt;Custom Sanitizers&lt;/h3&gt;
&lt;p&gt;tbd&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: Admin cron jobs</title>
      <link>https://docs.zen-cart.com/dev/admin/admin_cron/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/admin_cron/</guid>
      <description>
        
        
        &lt;p&gt;&lt;a href=&#34;https://docs.zen-cart.com/user/first_steps/hosting/#cron&#34;&gt;Cron&lt;/a&gt; is a utility on Linux hosting accounts that allows you to automatically schedule jobs to run at specific intervals.  An example of a job you might want to run is the &lt;a href=&#34;https://docs.zen-cart.com/user/admin_pages/localization/currencies/#update-currencies&#34;&gt;exchange rate updater&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What if you want to create your own custom cron job?&lt;/p&gt;
&lt;p&gt;The easiest way to do this is simply to follow the example of the exchange rate updater.  The key points to note are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy the file &lt;code&gt;admin/currency_cron.php&lt;/code&gt; to &lt;code&gt;admin/my-script_cron.php&lt;/code&gt; Change the references to &lt;code&gt;currency_cron&lt;/code&gt; to &lt;code&gt;my-script_cron&lt;/code&gt;, and call your own function in place of &lt;code&gt;zen_update_currencies&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the file &lt;code&gt;admin/includes/auto_loaders/currency_cron.core.php&lt;/code&gt; to &lt;code&gt;admin/includes/auto_loaders/my-script_cron.core.php&lt;/code&gt;  Change the inclusion of &lt;code&gt;localization.php&lt;/code&gt; to your own functions file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now you are ready to create a cron job in your hosting company&amp;rsquo;s control panel to run the update automatically on a scheduled basis. The command to give it is as follows. Work with your hosting company&amp;rsquo;s tech support team if you need help with determining the correct path and the correct php binary to call.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;php /full/server/path/to/admin/my-script_cron.php
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;existing-cron-jobs-within-zen-cart&#34;&gt;Existing Cron Jobs within Zen Cart&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;admin/products_cron.php&lt;/code&gt; (added in 2.2) will allow you to activate products at a time of your own choosing.  Note that if you use this feature, you will want to set Admin &amp;gt; Configuration &amp;gt; Stock &amp;gt; &lt;code&gt;ENABLE_DISABLED_UPCOMING_PRODUCT&lt;/code&gt; to &lt;code&gt;Manual&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;admin/currency_cron.php&lt;/code&gt; will allow you to update your store&amp;rsquo;s exchange rates.&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: Admin Templating Capability</title>
      <link>https://docs.zen-cart.com/dev/admin/templating/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/templating/</guid>
      <description>
        
        
        &lt;p&gt;In Zen Cart v1.x.x, the Admin section is driven by pages that combine a lot of business logic with presentation logic.
That is, there isn&amp;rsquo;t much of a &amp;ldquo;template&amp;rdquo; system, especially when compared to the Storefront side of the application.&lt;/p&gt;
&lt;p&gt;While it embraces an MVC structure, it doesn&amp;rsquo;t currently fully separate presentation from backend logic.&lt;/p&gt;
&lt;p&gt;That said, since v1.5.7 many (v1.5.8 expands it to &lt;em&gt;all&lt;/em&gt;) admin pages support some degree of per-page CSS and JS file inclusion.
(This is driven by the use of &lt;code&gt;admin_html_head.php&lt;/code&gt; instead of directly outputting all the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag content directly within the page itself.)&lt;/p&gt;
&lt;p&gt;In the examples below, &lt;code&gt;PAGENAME&lt;/code&gt; and &lt;code&gt;pagename&lt;/code&gt; refer to either the &lt;code&gt;cmd=pagename&lt;/code&gt; value or the &lt;code&gt;/admin/pagename.php&lt;/code&gt; value, depending on the page/URL.&lt;/p&gt;
&lt;h2 id=&#34;per-page-css-files&#34;&gt;Per-Page CSS Files&lt;/h2&gt;
&lt;p&gt;You may put your custom CSS for individual Admin pages into page-specific files that will automatically load on those pages.&lt;/p&gt;
&lt;p&gt;The convention (and loading order) is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/css/stylesheet.css&lt;/code&gt; (this is a core file, but is loaded on every page; only edit if your changes are for everywhere)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/css/PAGENAME.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/css/global_stylesheet.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/css/PAGENAME.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/css/PAGENAME_*.css&lt;/code&gt; (note the &lt;code&gt;_&lt;/code&gt;, followed by additional characters) &lt;strong&gt;(THIS IS WHERE YOU PUT YOUR CUSTOM CSS)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is a good practice to put your own page-specific customizations into a non-core file
(eg: &lt;code&gt;pagename_mystore.css&lt;/code&gt;) so that there are fewer file conflicts when upgrading.&lt;/p&gt;
&lt;p&gt;Plugins not using the &lt;code&gt;zc_plugins&lt;/code&gt; structure should put their page-specific CSS additions into a file using a naming convention akin to: &lt;code&gt;pagename_pluginname.css&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;per-page-js-files&#34;&gt;Per-Page JS Files&lt;/h2&gt;
&lt;p&gt;You may put your custom JavaScript for individual Admin pages into page-specific files that will automatically load on those pages.&lt;/p&gt;
&lt;p&gt;The convention (and loading order) is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/javascript/PAGENAME.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/javascript/PAGENAME.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/javascript/global_jscript.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/javascript/global_jscript.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/javascript/PAGENAME.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/javascript/PAGENAME.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/javascript/PAGENAME_*.php&lt;/code&gt;  (note the &lt;code&gt;_&lt;/code&gt;, followed by additional characters)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/zc_plugins/plugin_path...../admin/includes/javascript/PAGENAME_*.js&lt;/code&gt;  (note the &lt;code&gt;_&lt;/code&gt;, followed by additional characters)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/javascript/PAGENAME_*.js&lt;/code&gt; (note the &lt;code&gt;_&lt;/code&gt;, followed by additional characters)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/YOURADMIN/includes/javascript/PAGENAME_*.php&lt;/code&gt; (note the &lt;code&gt;_&lt;/code&gt;, followed by additional characters)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is a good practice to put your own page-specific customizations into a non-core file
(eg: &lt;code&gt;pagename_mystore.js&lt;/code&gt;) so that there are fewer file conflicts when upgrading.&lt;/p&gt;
&lt;p&gt;Plugins not using the &lt;code&gt;zc_plugins&lt;/code&gt; structure should put their page-specific custom JavaScript into a file using a naming convention akin to: &lt;code&gt;pagename_pluginname.js&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;site-specific-overrides&#34;&gt;Site Specific Overrides&lt;/h2&gt;
&lt;p&gt;Starting in Zen Cart 1.5.8, an &lt;a href=&#34;https://docs.zen-cart.com/user/admin/site_specific_overrides/&#34;&gt;admin site-specific override&lt;/a&gt; capability exists.&lt;/p&gt;
&lt;h2 id=&#34;related&#34;&gt;Related&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.zen-cart.com/user/customizing/admin_customizing&#34;&gt;Customizing your Admin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: Building a Home Page widget</title>
      <link>https://docs.zen-cart.com/dev/admin/widget/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/widget/</guid>
      <description>
        
        
        &lt;p&gt;Creating a widget of your own is just a matter of modifying &lt;code&gt;admin/index_dashboard.php&lt;/code&gt; and adding in your logic.  For example, one store wanted to monitor orders in a specific status, and make them visible on the home page.  Here&amp;rsquo;s what they did:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    &amp;lt;div class=&amp;#34;reportBox&amp;#34;&amp;gt;
        &amp;lt;div class=&amp;#34;header&amp;#34;&amp;gt;&amp;lt;?php echo &amp;#34;Held Orders&amp;#34;; ?&amp;gt; &amp;lt;/div&amp;gt;
        &amp;lt;?php  $orders = $db-&amp;gt;Execute(&amp;#34;SELECT o.orders_id AS orders_id, o.customers_name AS customers_name, o.date_purchased AS date_purchased, ot.text AS order_total FROM &amp;#34; . TABLE_ORDERS . &amp;#34; o LEFT JOIN &amp;#34; . TABLE_ORDERS_TOTAL . &amp;#34; ot ON (o.orders_id = ot.orders_id and class = &amp;#39;ot_total&amp;#39;) WHERE orders_status = 7 ORDER BY orders_id DESC&amp;#34;);

        if ($orders-&amp;gt;EOF) {
          echo &amp;#39;              &amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;No Held Orders&amp;lt;/div&amp;gt;&amp;#39; . &amp;#34;\n&amp;#34;; 
        } else { 
          while (!$orders-&amp;gt;EOF) {
            echo &amp;#39;              &amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;&amp;lt;span class=&amp;#34;left&amp;#34;&amp;gt;&amp;lt;a href=&amp;#34;&amp;#39; . zen_href_link(FILENAME_ORDERS, &amp;#39;oID=&amp;#39; . $orders-&amp;gt;fields[&amp;#39;orders_id&amp;#39;] . &amp;#39;&amp;amp;action=edit&amp;amp;origin=&amp;#39; . FILENAME_DEFAULT, &amp;#39;NONSSL&amp;#39;) . &amp;#39;&amp;#34; class=&amp;#34;contentlink&amp;#34;&amp;gt; &amp;#39; . $orders-&amp;gt;fields[&amp;#39;customers_name&amp;#39;] . &amp;#39;&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;#34;center&amp;#34;&amp;gt;&amp;#39; . $orders-&amp;gt;fields[&amp;#39;order_total&amp;#39;] . &amp;#39;&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;#34;right&amp;#34;&amp;gt;&amp;#39; . &amp;#34;\n&amp;#34;;
            echo zen_date_short($orders-&amp;gt;fields[&amp;#39;date_purchased&amp;#39;]);
            echo &amp;#39;              &amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;#39; . &amp;#34;\n&amp;#34;;
            $orders-&amp;gt;MoveNext();
          }
        }
        ?&amp;gt;
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A plugin called &lt;a href=&#34;https://www.zen-cart.com/downloads.php?do=file&amp;amp;id=2284&#34;&gt;Orders in Status Dashboard Widget&lt;/a&gt; can be used to build something similar for your site.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: Building a Report</title>
      <link>https://docs.zen-cart.com/dev/admin/reports/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/reports/</guid>
      <description>
        
        
        &lt;p&gt;Adding a custom report to your site&amp;rsquo;s admin is a common customization.&lt;/p&gt;
&lt;p&gt;The easiest way to do this is simply to follow one of the built-in examples.
We&amp;rsquo;ll use the &lt;a href=&#34;https://docs.zen-cart.com/user/admin_pages/reports/products_low_stock/&#34;&gt;Products Low Stock&lt;/a&gt; report.&lt;/p&gt;
&lt;p&gt;There are two files that make up this report:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;admin/stats_products_lowstock.php&lt;/li&gt;
&lt;li&gt;admin/includes/languages/english/stats_products_lowstock.php&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Copy those files to files with names that match the data shown on the report.  For example, if the report is designed to show products with zero weight, call the new files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;admin/stats_products_zero_weight.php&lt;/li&gt;
&lt;li&gt;admin/includes/languages/english/stats_products_zero_weight.php&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then edit the new code file &lt;code&gt;admin/stats_products_zero_weight.php&lt;/code&gt; and change the query to do what you want.  In our case, the query for products with zero weight might be:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;            $products_query_raw = &amp;#34;SELECT p.products_id, pd.products_name, p.products_quantity, p.products_type
                                   FROM &amp;#34; . TABLE_PRODUCTS . &amp;#34; p,
                                        &amp;#34; . TABLE_PRODUCTS_DESCRIPTION . &amp;#34; pd
                                   WHERE p.products_id = pd.products_id
                                   AND p.products_weight = 0 
                                   AND pd.language_id = &amp;#34; . (int)$_SESSION[&amp;#39;languages_id&amp;#39;] . &amp;#34;
                                   ORDER BY pd.products_name&amp;#34;;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You may need to make other changes to this file of course depending on your needs.&lt;/p&gt;
&lt;p&gt;Then edit the new language file &lt;code&gt;admin/includes/languages/english/stats_products_zero_weight.php&lt;/code&gt; and change the title, then make any other appropriate changes.&lt;/p&gt;
&lt;p&gt;You can now run your report using the URL&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://MYSTORE.com/MYADMINNAME/index.php?cmd=stats_products_zero_weight
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;but you don&amp;rsquo;t see it in the dropdown Admin &amp;gt; Reports.  Why not?&lt;/p&gt;
&lt;p&gt;The answer is, it needs to be added to the admin pages table, which requires some defined constants.  If you look at any of the &lt;a href=&#34;https://www.zen-cart.com/downloads.php?do=cat&amp;amp;id=1&#34;&gt;reports in the Plugins area&lt;/a&gt;, you&amp;rsquo;ll see how this is done. We will look at &lt;a href=&#34;https://www.zen-cart.com/downloads.php?do=file&amp;amp;id=2302&#34;&gt;Disabled Products Report&lt;/a&gt; to see one example:&lt;/p&gt;
&lt;p&gt;This report creates a third file called &lt;code&gt;admin/includes/extra_datafiles/products_disabled.php&lt;/code&gt;.  So create your own file, using the naming convention above, called &lt;code&gt;admin/includes/extra_datafiles/products_zero_weight.php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll want the contents to be something like:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;?php
define(&amp;#39;FILENAME_ZERO_WEIGHT&amp;#39;,&amp;#39;stats_products_zero_weight&amp;#39;);
define(&amp;#39;BOX_REPORTS_ZERO_WEIGHT&amp;#39;,&amp;#39;Zero Weight Report&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you have to populate the database with these constants so the system knows to show this option in the Reports dropdown.&lt;/p&gt;
&lt;p&gt;You can provide an external SQL and run it by hand in Admin &amp;gt; Tools &amp;gt; Install SQL Patches, as this report does.&lt;/p&gt;
&lt;p&gt;The query would be something like&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;INSERT INTO admin_pages (page_key, language_key, main_page, page_params, menu_key, display_on_menu, sort_order) VALUES (&amp;#39;productsZeroWeight&amp;#39;, &amp;#39;BOX_REPORTS_ZERO_WEIGHT&amp;#39;, &amp;#39;FILENAME_ZERO_WEIGHT&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;reports&amp;#39;, &amp;#39;Y&amp;#39;, 500);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;alternately, you can run this query in a file in &lt;code&gt;admin/functions/extra_functions&lt;/code&gt; automatically, to make installing this report easier. It&amp;rsquo;s your choice.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: Creating a new Admin menu item</title>
      <link>https://docs.zen-cart.com/dev/admin/creating_menu/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/creating_menu/</guid>
      <description>
        
        
        &lt;p&gt;Let&amp;rsquo;s say that you have a new tool (plugin, addon, etc) named &lt;code&gt;new_tool.php&lt;/code&gt; that you want to plug into the &lt;em&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/em&gt; menu.&lt;/p&gt;
&lt;p&gt;Most of the files that you distribute in the &lt;code&gt;new_tool.zip&lt;/code&gt; file are identical with previous Zen Cart versions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/YOUR_ADMIN/new_tool.php&lt;/code&gt;.  Contains the code that implements your new tool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/YOUR_ADMIN/includes/extra_datafiles/new_tool_filenames.php&lt;/code&gt;.  Contains the filename (without extension) definition for your new tool, e.g. &lt;code&gt;define(&#39;FILENAME_NEW_TOOL&#39;, &#39;new_tool&#39;);&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Be careful to leave off the &lt;code&gt;.php&lt;/code&gt; extension when doing this.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/YOUR_ADMIN/includes/languages/english/extra_definitions/new_tool_name.php&lt;/code&gt;.  Contains the menu entry text definition for your new tool, e.g. &lt;code&gt;define(&#39;BOX_TOOLS_NEW_TOOL&#39;, &#39;New Tool&#39;);&lt;/code&gt;. Can be repeated as multiple files for additional languages if needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/YOUR_ADMIN/includes/languages/english/new_tool.php&lt;/code&gt;.  Contains the language-specific defines for your new tool; the filename of the language file &lt;em&gt;must be the same&lt;/em&gt; as  the filename of the tool itself. Multiple language files may be used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To install the actual menu entry, you can use either one file to do the install without any messages being displayed, using &lt;code&gt;/YOUR_ADMIN/includes/functions/extra_functions/init_new_tool.php&lt;/code&gt;,
or if you want to display a message indicating that your tool has been installed, you&amp;rsquo;ll need two files  (&lt;code&gt;/YOUR_ADMIN/includes/auto_loaders/config.new_tool.php&lt;/code&gt; and &lt;code&gt;/YOUR_ADMIN/includes/init_includes/init_new_tool.php&lt;/code&gt; instead of the &lt;code&gt;extra_functions&lt;/code&gt; file):&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;config.new_tool.php&lt;/code&gt; file will contain something similar to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000&#34;&gt;$autoLoadConfig&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;][]&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;array&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;autoType&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;init_script&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;loadFile&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;init_new_tool.php&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In &lt;em&gt;either&lt;/em&gt; case, the &lt;code&gt;init_new_tool.php&lt;/code&gt; will contain something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;defined&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;IS_ADMIN_FLAG&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;die&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;Illegal Access&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//----
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Register the New Tools tool into the admin menu structure.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// NOTES:  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// 1) Once this file has run once and you see the Tools &amp;gt; New Tool link in the admin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// menu structure, it is safe to delete this file (unless you have other functions that
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// are initialized in the file).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// 2) If you have multiple items to add to the admin-level menus, then you should 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// register each of the pages here, just make sure that the &amp;#34;page key&amp;#34; is unique or 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// a debug-log will be generated!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;function_exists&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;zen_register_admin_page&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;zen_page_key_exists&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;toolsNewTool&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#000&#34;&gt;zen_register_admin_page&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;toolsNewTool&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;BOX_TOOLS_NEW_TOOL&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;FILENAME_NEW_TOOL&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;tools&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;// Optionally display a message here, using the $messageStack
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#000&#34;&gt;$messageStack&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c4a000&#34;&gt;add_session&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;BOX_TOOLS_NEW_TOOL&lt;/span&gt; &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39; installed&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;success&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The value &lt;em&gt;toolsNewTool&lt;/em&gt; is a (hopefully) unique value that identifies your new tool.&lt;/li&gt;
&lt;li&gt;The values &lt;code&gt;BOX_TOOLS_NEW_TOOL&lt;/code&gt; and &lt;code&gt;FILENAME_NEW_TOOL&lt;/code&gt; are defined within the other files within your toolset.&lt;/li&gt;
&lt;li&gt;The fourth parameter (&amp;rsquo;&amp;rsquo;) has any parameters that your tool might require.  Rarely used, except when you&amp;rsquo;re adding a configuration-page element.&lt;/li&gt;
&lt;li&gt;The fifth parameter (&lt;code&gt;&#39;tools&#39;&lt;/code&gt; in the example) identifies which of the high-level menu items your tool &amp;ldquo;attaches&amp;rdquo; to, one of: configuration,  catalog, modules, customers, taxes, localization, reports, tools, gv,  access, or extras.&lt;/li&gt;
&lt;li&gt;The sixth parameter (&amp;lsquo;Y&amp;rsquo;) identifies whether (&amp;lsquo;Y&amp;rsquo;) or not (&amp;lsquo;N&amp;rsquo;) to display the page on the admin menu.&lt;/li&gt;
&lt;li&gt;The seventh (optional) parameter is the sort order for the page, i.e. where it lives on the drop-down menu in relation to the sort order of others.  Leave this entry empty and the function will place &lt;code&gt;new_tool&lt;/code&gt; at the bottom of the selected menu dropdown.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To remove your menu item, in the case a store-owner chooses to  un-install your plugin, simply include a file in your distribution zip-file named  &lt;code&gt;/uninstall_new_page.sql&lt;/code&gt; that contains&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;DELETE&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;admin_pages&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;page_key&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;toolsNewTool&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Instead of distributing the &lt;code&gt;init_new_tool.php&lt;/code&gt; file, you could include instructions to install using the &lt;em&gt;&lt;strong&gt;Admin Access  Management &amp;gt; Admin Page Registration&lt;/strong&gt;&lt;/em&gt; tool.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;em&gt;Page Key&lt;/em&gt; to &lt;code&gt;toolsNewTool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;em&gt;Page Name&lt;/em&gt; to &lt;code&gt;BOX_TOOLS_NEW_TOOL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;em&gt;Page File Name&lt;/em&gt; to &lt;code&gt;FILENAME_NEW_TOOL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Leave &lt;em&gt;Page Parameters&lt;/em&gt; blank&lt;/li&gt;
&lt;li&gt;Select &amp;ldquo;Tools&amp;rdquo; from the &lt;em&gt;Menu&lt;/em&gt; dropdown&lt;/li&gt;
&lt;li&gt;Check the &lt;em&gt;Show on Menu&lt;/em&gt; box&lt;/li&gt;
&lt;li&gt;(optional) Set the &lt;em&gt;Sort Order&lt;/em&gt; value to position your new tool on the displayed menu dropdown.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you don&amp;rsquo;t see your newly added item, it&amp;rsquo;s likely somewhere in the middle of the menu&amp;rsquo;s dropdown list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use 999 (or any other large number) for the sort order value if you want to ensure that your item is at the bottom of the menu&amp;rsquo;s list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To reposition an item within one of the admin menus, use your cPanel&amp;rsquo;s phpMyAdmin tool and  browse the &lt;code&gt;admin_pages&lt;/code&gt; table to find the added menu item and adjust its sort_order value as desired.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;one-thing-not-to-do&#34;&gt;One thing NOT to do!&lt;/h3&gt;
&lt;p&gt;Rather than simply using the call &lt;code&gt;toolsNewTool&lt;/code&gt; to see if the menu entry has already been added, some developers will delete the registration file.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@unlink(DIR_WS_INCLUDES . &amp;#39;functions/extra_functions/somescript_admin_page_reg.php&amp;#39;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PLEASE don&amp;rsquo;t do this. If you do, it becomes difficult to create copies of the site for testing.  Instead, simply test the existence of whatever you&amp;rsquo;re trying not to re-do.  For example, to see if an admin menu exists, use &lt;code&gt;zen_page_key_exists&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;alternate-approaches-to-menu-creation&#34;&gt;Alternate Approaches to Menu Creation&lt;/h2&gt;
&lt;p&gt;Rather than write code as shown above, some developers prefer to provide a SQL file that can be run from Admin &amp;gt; Tools &amp;gt; Install SQL Patches.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;INSERT INTO admin_pages (page_key, language_key, main_page, page_params, menu_key, display_on_menu, sort_order) VALUES (&amp;#39;mod_list&amp;#39;, &amp;#39;BOX_TOOLS_MOD_LIST&amp;#39;, &amp;#39;FILENAME_MOD_LIST&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;tools&amp;#39;, &amp;#39;Y&amp;#39;, 999);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The advantage of this approach is that it&amp;rsquo;s a one time operation with no checking overhead in the future.&lt;/p&gt;
&lt;p&gt;Still others simply point users to the &lt;a href=&#34;https://docs.zen-cart.com/user/admin_pages/admins/admin_page_registration/&#34;&gt;Admin Page Registration&lt;/a&gt; page. Note that this approach is not encouraged.&lt;/p&gt;
&lt;h2 id=&#34;using-the-encapsulated-plugin-manager&#34;&gt;Using the Encapsulated Plugin Manager&lt;/h2&gt;
&lt;p&gt;For developers targeting 1.5.7 and above, the &lt;a href=&#34;https://docs.zen-cart.com/dev/plugins/encapsulated/&#34;&gt;encapsulated plugin&lt;/a&gt; architecture is the new standard.  For details on SQL actions in encapsulated plugins, see &lt;a href=&#34;https://docs.zen-cart.com/dev/plugins/encapsulated/sql_installation/&#34;&gt;Plugin SQL Installation&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: Sorting an Admin menu</title>
      <link>https://docs.zen-cart.com/dev/admin/sorting_menu/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/sorting_menu/</guid>
      <description>
        
        
        &lt;h2 id=&#34;top-level-menus-configuration-tools-etc&#34;&gt;Top Level Menus (Configuration, Tools, etc.)&lt;/h2&gt;
&lt;p&gt;By default, the list under each of the main admin menu titles  (Configuration, Catalog, Modules etc&amp;hellip;) are ordered according to each menu items &lt;code&gt;sort_order&lt;/code&gt; in the database (which is set on initial installation). However, it is possible to alpha-sort these entries which may be more desirable as they often become extended with Plugins.&lt;/p&gt;
&lt;p&gt;In Zen Cart 1.5.8 and above, this functionality is controlled in the admin main language file, eg.  &lt;code&gt;admin/includes/languages/lang.english.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In Zen Cart 1.5.7, this functionality is controlled in the admin main language file, eg.  &lt;code&gt;admin/includes/languages/english.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The constant which is set in these files is&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MENU_CATEGORIES_TO_SORT_BY_NAME&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;which sets a comma-separated list of the &lt;code&gt;menu_key&lt;/code&gt; values to be sorted alphabetically.
(Note these values come from the &lt;code&gt;admin_menus&lt;/code&gt; database table.)&lt;/p&gt;
&lt;p&gt;The default value of the constant &lt;code&gt;MENU_CATEGORIES_TO_SORT_BY_NAME&lt;/code&gt; is &lt;code&gt;reports,tools&lt;/code&gt;, which means the Reports menu and the Tools menu are all sorted alphabetically.  To sort more menus alphabetically, add the desired menus to this list.&lt;/p&gt;
&lt;p&gt;eg:
&lt;code&gt;&#39;configuration,catalog,modules,customers,taxes,localization,reports,tools,gv,acccess,extras&#39;&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;sorting-sub-menus-under-the-configuration-menu&#34;&gt;Sorting Sub-Menus under the Configuration Menu&lt;/h2&gt;
&lt;p&gt;Under the Configuration menu (My Store, Minimum values etc,), the list in each submenu can also be alphasorted.&lt;/p&gt;
&lt;h3 id=&#34;zen-cart-158&#34;&gt;Zen Cart 1.5.8&lt;/h3&gt;
&lt;p&gt;In release 1.5.8 and forward, the new constant &lt;code&gt;CONFIGURATION_MENU_ENTRIES_TO_SORT_BY_NAME&lt;/code&gt; is used to determine which submenus are sorted by adding a comma-separated list of the configuration IDs (&lt;code&gt;gID&lt;/code&gt;) of each submenu,
e.g. &amp;lsquo;1,2,3,4&amp;rsquo; etc&lt;/p&gt;
&lt;p&gt;The gID of each submenu can be ascertained by hovering the cursor over each submenu item and noting the number of the final parameter gID of the link,&lt;/p&gt;
&lt;p&gt;eg. for Minimum Values:  https://MYWEBSITE/MY_ADMIN/index.php?cmd=configuration&amp;amp;&lt;strong&gt;gID=2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The default value of this constant is &amp;lsquo;1&amp;rsquo;, which means that by default, only Configuration &amp;gt; My Store is alphabetically sorted; other configuration menus are sorted according to the &lt;code&gt;sort_order&lt;/code&gt; value of each entry in a configuration group.&lt;/p&gt;
&lt;h3 id=&#34;zen-cart-157&#34;&gt;Zen Cart 1.5.7&lt;/h3&gt;
&lt;p&gt;In release 1.5.7, to sort a Configuration submenu listing (such as My Store) by name, &lt;code&gt;admin/configuration.php&lt;/code&gt; must be modified manually to check for the &lt;code&gt;gID&lt;/code&gt; of the desired menu and alter the SELECT query at the start of the tbody, to &lt;code&gt;ORDER BY configuration_title&lt;/code&gt; instead of &lt;code&gt;ORDER BY sort_order&lt;/code&gt; for that menu.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Dev: View Builders</title>
      <link>https://docs.zen-cart.com/dev/admin/view-builders/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://docs.zen-cart.com/dev/admin/view-builders/</guid>
      <description>
        
        
        &lt;p&gt;These are a set of classes used to aid the rapid development of
pages/views that display tabular data.&lt;/p&gt;
&lt;p&gt;Initially they are meant to aid in the building of admin pages,
however some aspects will also be able to be used catalog side as well.&lt;/p&gt;
&lt;p&gt;The structure of view builder classes and the data formats they use allow
for much easier integration with plugins that need to add extra columns
or actions in admin pages.&lt;/p&gt;

      </description>
    </item>
    
  </channel>
</rss>
