WordPress.org

Theme Review Team

Updates from Chip Bennett Toggle Comment Threads | Keyboard Shortcuts

  • Chip Bennett 1:44 pm on June 15, 2015 Permalink |  

    Customizer Code Examples on GitHub 

    As was discussed in previous meetings, we have begun work on the Theme Review Team’s GitHub repository to build a library of code examples. The first area to tackle is example Customizer code, which currently includes examples for adding panels, sections, settings, basic core controls, specialized core text controls (email, URL, etc.), advanced core controls (color control, image control), and an example custom control (radio image).

    We will continue to add to the library, including more examples of custom controls, and more advanced examples, such as postMessage and other JavaScript fun, modifying the style of the Customizer panel, and others as suggested/requested.

    Suggestions, requests, questions, and pull requests welcome!

     
  • Chip Bennett 12:58 am on June 13, 2015 Permalink |  

    Meeting Minutes 06/11/15 

    Per our meeting yesterday and the comments on the earlier post, the Theme review requirements have been modified. Additions are highlighted in red, and deletions are struck-out:

    A theme must meet all of the following requirements to be included in the WordPress.org theme repository.

    Along with these checks you should also make sure you run the theme through the theme check plugin. It automatically checks for all the required items. You can find a full list of what it checks here.

    Accessibility

    • If the theme has the tag ‘accessibility-ready’ then it needs to meet these requirements.

    Code

    • No PHP or JS errors.
    • Include at least index.php and style.css.
    • Have a valid DOCTYPE declaration and include language_attributes.
    • Sanitize everything.
    • No removing or modifying non-presentational hooks.
    • No shortcodes are allowed.
    • Support the following WordPress-generated CSS classes:
      • alignleft
      • alignright
      • wp-caption
      • wp-caption-text
      • gallery-caption
      • sticky (can be unstyled)
      • bypostauthor (can be unstyled)
      • screen-reader-text
    • Must meet all uploader/Theme Check required tests
    • Provide a unique prefix for everything the Theme defines in the public namespace, including options, functions, global variables, constants, post meta, etc.

    Core Functionality and Features

    • Use WordPress functionality and features first, if available.
    • Don’t include admin/feature pointers.
    • No custom post types and no custom taxonomies.
    • No pay wall restricting any WordPress feature.
    • No disabling of the admin tool bar.
    • Use get_template_directory() rather than TEMPLATEPATH to return the template path.
    • Use get_stylesheet_directory() rather than STYLESHEETPATH to return the stylesheet path.
    • Avoid hard coding to modify content. Instead, use function parameters, filters and action hooks where appropriate. For example wp_title should be modified using a filter.
    • Able to have child themes made from them. (Child theme ready)
    • Include comments_template().
    • The theme tags and description must match the what the theme actually does in respect to functionality and design.
    • Use template tags and action/filter hooks properly.

    Presentation vs. Functionality

    • Must not not generate user content, or configure non-theme site options or site functionality.

    Documentation

    • Any custom features, options or any limitations (for example menu restrictions), should be explained. Enough documentation should be provided.

    Favicons

    • If implemented, disable favicons by default and have the ability for users to override.

    Language

    • All theme text strings are to be translatable.
    • Include a text domain in style.css
    • Use a single unique theme slug – as the theme slug appears in style.css. If it uses a framework then no more than 2 unique slugs.
    • Can use any language for text, but only use the same one for all text.

    Licensing

    • Be 100% GPL and/or 100% GPL-compatible licensed.
    • Declare copyright and license explicitly. Use the license and license uri header slugs to style.css.
    • Declare licenses of any resources included such as fonts or images.
    • All code and design should be your own or legally yours. Cloning of designs is not acceptable.

    Naming

    • Theme names must not use: WordPress, Theme.
    • Spell “WordPress” correctly in all public facing text: all one word, with both an uppercase W and P.

    Options and Settings

    • Save options in a single array.
    • Use sane defaults and don’t write default setting values to the database.
    • Use edit_theme_options capability for determining user permission to edit options, rather than rely on a role (e.g. “administrator”), or a different capability (e.g. “edit_themes”, “manage_options”).
    • Use the Customizer for implementing theme options.

    Plugins

    • Don’t include any plugins. A theme can recommend plugins but not include those plugins in the theme code.
    • Don’t do things in a theme considered plugin territory.

    Screenshot

    • The Screenshot should be of the actual theme as it appears with default options, not a logo or mockup.
    • The screenshot should be no bigger than 1200 x 900px.

    Security and Privacy

    • Don’t phone home without informed user consent. Find out more about security here.
    • Make any collection of user data “opt-in” only and have a theme option that is set to disabled by default. Validate and sanitize untrusted data before entering into the database. All untrusted data should be escaped before output. (See: Data Validation.)
    • No URL shorteners used in the theme.
    • Use esc_attr() for text inputs and esc_textarea() for textareas.

    Selling, credits and links

    • If you are a theme shop you should be selling under GPL to be in the WordPress.org repo.
    • If the theme adds a footer credit link, there should only be one (link to WordPress does not count)

    Stylesheets and Scripts

    • No hard coding of scripts, styles and Favicons unless a browser workaround script. Everything should be enqueued.
    • No analytics or tracking.
    • No minification of scripts or files unless provide original files.
    • Required to use core-bundled scripts rather than including their own version of that script. For example jQuery.
    • Include all scripts and resources it uses rather than hot-linking. The exception to this is Google libraries.
    • If a tag is used in style.css the theme should support that feature or adhere to what that tag stands for. For example custom background or header.

    Templates

    It’s worth noting we are working to automate a lot of the above requirements.

    Along with the required items, you should also consider the recommended items. The recommended items are there to make sure your theme is the best it can be and good advice to include as best practice.

    If you have any questions regarding what was updated/clarified, please ask in the comments.

    Please note that we will very likely continue to look for ways to clarify and simplify the Requirements, including more extensive usage of code examples, explanations, and clarifications linked from the Requirements elsewhere in the Theme Review Handbook.

     
    • Hardeep Asrani 1:06 am on June 13, 2015 Permalink | Log in to Reply

      Hi Chip,

      I’ve a couple of questions:

      No custom post types and no custom taxonomies. No shortcodes are allowed.

      So now WordPress.org themes can include CPT and shortcodes, right?

      Must not not generate user content, or configure non-theme site options or site functionality.

      So what does it means for themes like Zerif Lite? They generate user content, and Matt was fine with it, right?

      And also – it would be great if you could explain this point. Thanks for the update. :)

      • Venkat Raj 1:25 am on June 13, 2015 Permalink | Log in to Reply

        I second that…
        Isn’t CPT is user content?

      • Justin Tadlock 1:26 am on June 13, 2015 Permalink | Log in to Reply

        CPTs, CTs, and shortcodes are not allowed. Those items now fall under the “Presentation vs. Functionality” section, which was the original section we had until it got removed/modified a few months back. What we’ll be doing is adding specifics to the “Examples and Explanations” page. So, on that page, we’ll list out specifics like CPTs, CTs, and shortcodes.

        Basically, the meeting was for minimizing the guidelines where possible.

        • Hardeep Asrani 1:31 am on June 13, 2015 Permalink | Log in to Reply

          Thanks for the clarification. One more question – how would you describe themes adding widgets to style the front-page? Is it allowed, or will it fall under “user generated content?” Thanks again. :)

          • Justin Tadlock 5:58 pm on June 14, 2015 Permalink | Log in to Reply

            The question is too general. If there’s a ticket you can CC me on or specific example you can point me to, I’d be happy to look at it.

    • Dovy Paukstys 5:14 am on June 13, 2015 Permalink | Log in to Reply

      Question, in reference to: https://github.com/Otto42/theme-check/issues/65#issuecomment-111516643

      Long story short, my framework is used by many developers and has the ability to add both add_menu_page and add_theme_page. Now add_menu_page is not approved and flags Theme-Check.

      The issue is, our devs KNOW to not use that particular function at all when submitting.

      Is there any way we can make the Required a warning/notice, and let them know it’s not permitted allowing my framework to pass Theme-Check? Or can we remove that requirement all together and allow devs to do what they would like? 😉

      Honestly, with the customizer it will never be used anyways, but I’d rather not take it out of my code even if it’s not used by WP.org themes.

      Thoughts?

    • dmccan 10:12 pm on June 13, 2015 Permalink | Log in to Reply

      This is a good improvement.

  • Chip Bennett 1:08 am on June 11, 2015 Permalink |  

    Moving to the Customizer API from the Settings API, using Options API 

    Theme developers using a custom implementation of Options API/Settings API, or who use one of the many excellent frameworks/libraries that use Options API/Settings API, to handle Theme options and create settings pages, will soon need to modify their Theme options to use of the Customizer API. This post will discuss some of the issues potentially encountered with moving from Options API/Settings API to Options API/Customizer API.

    Note: there are other tutorials that describe basic Customizer API implementation. My focus with this post is specifically porting from Options API/Settings API to Options API/Customizer API.

    What API?

    First, a note regarding APIs.

    The Options API and the Theme Mods API are used to store/retrieve options to/from the database. The Settings API and the Customizer API are used to expose settings to the user to configure options. Either of the storage/retrieval APIs can be used with either of the user-configuration APIs.

    The new Theme Review requirement stipulates use of the Customizer API in lieu of the Settings API, but does not require use of either the Options API or the Theme Mods API in lieu of the other. So, both Theme Mods API/Customizer API implementations and Options API/Customizer API implementations remain acceptable.

    Now, for new Themes, it is certainly recommended – and easier – to use a Theme Mods API/Customizer API implementation. However, existing Themes with existing users, it is not feasible to move from an Options API/Settings API implementation to a Theme Mods API/Customizer API implementation. Fortunately, the Options API/Customizer API implementation is a feasible alternative.

    Options Configuration Array

    For the purposes of this post, I’ll assume that your existing Options API/Settings API implementation is built around a configuration array that defines each of the Theme options, and the various parameters for each option. Each setting will have certain standard parameters, including ID, title, description, field type (checkbox, radio, text, textarea, etc.), a sanitization/data type (HTML text, no-HTML text, email, hex color, etc.), and default value. Additionally, each setting may have a defined settings page section, and, if applicable, settings page tab. Finally, for settings that have select-type fields (select, radio, etc.), the parameters will include an array of choices.

    For the purposes of this post, we’ll assume that the configuration array looks like so:

    $settings_parameters = array(
    	'text_setting_1' => array(
    		'id' => 'text_setting_1',
    		'title' => __( 'Text Setting 1', 'theme-slug' ),
    		'description' => __( 'Text setting 1 description', 'theme-slug' ),
    		'field_type' => 'text',
    		'sanitize' => 'html',
    		'tab' => 'tab_1',
    		'section' => 'section_1',
    		'default' => __( 'Default Text Setting 1 text', 'theme-slug' )
    	),
    	'text_setting_2' => array(
    		'id' => 'text_setting_2',
    		'title' => __( 'Text Setting 2', 'theme-slug' ),
    		'description' => __( 'Text setting 2 description', 'theme-slug' ),
    		'field_type' => 'text',
    		'sanitize' => 'email',
    		'tab' => 'tab_1',
    		'section' => 'section_2',
    		'default' => __( 'noreply@example.com', 'theme-slug' )
    	),
    	'select_setting_1' => array(
    		'id' => 'select_setting_1',
    		'title' => __( 'Select Setting 1', 'theme-slug' ),
    		'description' => __( 'Select setting 1 description', 'theme-slug' ),
    		'field_type' => 'select',
    		'sanitize' => 'select',
    		'tab' => 'tab_2',
    		'section' => 'section_1',
    		'default' => 'blue',
    		'choices' => array(
    			'blue' => __( 'Blue', 'text-slug' ),
    			'red' => __( 'Red', 'text-slug' ),
    			'green' => __( 'Green', 'text-slug' ),
    		)
    	),
    );
    

    Assuming that your implementation has a tabbed settings page, with settings sections for each tab, you will have another array defined, perhaps like so:

    $settings_page_tabs = array(
    	'tab_1' => array(
    		'id' => 'tab_1',
    		'title' => __( 'Page Tab 1', 'theme-slug' ),
    		'description' => __( 'Page tab 1 description', 'theme-slug' ),
    		'sections' => array(
    			'section_1' => array(
    				'id' => 'section_1',
    				'title' => __( 'Section 1 Title', 'theme-slug' ),
    				'description' => __( 'Section 1 description', 'theme-slug' )
    			),
    			'section_2' => array(
    				'id' => 'section_2',
    				'title' => __( 'Section 2 Title', 'theme-slug' ),
    				'description' => __( 'Section 2 description', 'theme-slug' )
    			),
    		),
    	'tab_2' => array(
    		'id' => 'tab_2',
    		'title' => __( 'Page Tab 2', 'theme-slug' ),
    		'description' => __( 'Page tab 2 description', 'theme-slug' ),
    		'sections' => array(
    			'section_1' => array(
    				'id' => 'section_1',
    				'title' => __( 'Section 1 Title', 'theme-slug' ),
    				'description' => __( 'Section 1 description', 'theme-slug' )
    			),
    			'section_2' => array(
    				'id' => 'section_2',
    				'title' => __( 'Section 2 Title', 'theme-slug' ),
    				'description' => __( 'Section 2 description', 'theme-slug' )
    			),
    		)
    	)
    );
    

    Moving from Settings API to Customizer API

    Settings Page Tabs => Customizer Panels

    With the Settings API, you have to write your own code to implement settings page tabs. With the Customizer, tabs are built in, and they are called Panels. Using our settings page configuration above, setting up Panels is simple:

    foreach ( $settings_page_tabs as $panel ) {
    	$wp_customize->add_panel(
    		'theme_slug_' . $panel['id'], 
    		array(
    			'priority' 	=> 10,
    			'capability' 	=> 'edit_theme_options',
    			'title' 	=> $panel['title'],
    			'description' 	=> $panel['description'],
    		) 
    	);
    }
    

    Note here that you can sort your Theme’s panels, using the 'priority' parameter. Also, passing 'capability' => 'edit_theme_options', you’re taking care of the capability check that you would do elsewhere, via add_theme_page(), with the Settings API.

    Settings Page Sections => Customizer Panel Sections

    With the Settings API, you add a settings page section using add_settings_section():

    foreach ( $settings_page_tabs as $tab ) {
    	// Loop through tabs for sections
    	foreach ( $tab['sections'] as $section ) {
    		add_settings_section(
    			// $id
    			'theme_slug_' . $section['id'] . '_section',
    			// $title
    			$section['title'],
    			// $callback
    			'theme_slug_section_callback',
    			// $page (menu slug)
    			'theme-slug'
    		);
    	}
    }
    

    You would then have to define the callback for each section (normally used for the descriptive text for the section), and you would also have to take care to pass the correct string for $page. Then, in your settings page, you would have to call do_settings_section( $id ) for each settings section.

    With the Customizer API, again, this process is simplified and the code is similar:

    foreach ( $settings_page_tabs as $panel ) {
    	// Loop through tabs for sections
    	foreach ( $panel['sections'] as $section ) {
    		$wp_customize->add_section(
    			// $id
    			'theme_slug_' . $section['id'],
    			// parameters
    			array(
    				'title'		=> $section['title'],
    				'description'	=> $section['description'],
    				'panel'		=> 'theme_slug_' . $panel['id']
    			)
    		);
    	}
    }
    

    Settings Page Settings => Customizer Settings

    The next step is to register each of the settings fields. With the Settings API, you use add_settings_field() to define the setting, and you pass as a parameter a callback that defines the form field markup for that setting. Using the settings parameters array, you might be doing something dynamic, like so:

    foreach ( $settings_parameters as $option ) {
    	add_settings_field(
    		// $settingid
    		'them_slug_setting_' . $option['id'],
    		// $title
    		$option['title'],
    		// $callback
    		'theme_slug_setting_callback',
    		// $pageid
    		'theme_slug_' . $option['tab'] . '_tab',
    		// $sectionid
    		'theme_slug_' . $option['section'] . '_section',
    		// $args
    		$option
    	);
    

    The code for the Customizer API is similar:

    foreach ( $settings_parameters as $option ) {
    	$wp_customize->add_setting(
    		// $id
    		'theme_slug_options[' . $option['id'] . ']',
    		// parameters array
    		array(
    			'default'		=> $option['default'],
    			'type'			=> 'option',
    			'sanitize_callback'	=> 'theme_slug_sanitize_' . $option['sanitize']
    
    		)
    	);
    

    A couple things to note here:

    First, 'type' => 'option' tells the Customizer to use the Options API, rather than the Theme Mods API, to retrieve/store settings.

    Second, the 'sanitize_callback' is required. We will address why later.

    Settings API Settings Page Setting Field Callback => Customizer Control

    With the Settings API, when you call add_settings_field(), you might have defined a single setting callback that switches through output based on field type, or you may have separate callbacks for each field type. Either way, with the Customizer API, this process is much simpler for field types defined by the API (text, checkbox, radio, select, dropdown_pages, textarea):

    foreach ( $settings_parameters as $option ) {
    	// Add setting control
    	$wp_customize->add_control(
    		// $id
    		'theme_slug_options[' . $option['id'] . ']',
    		// parameters array
    		array(
    			'label'		=> $option['title'],
    			'section'	=> 'theme_slug_' . $option['section'],
    			'settings'	=> 'theme_slug_options['. $option['id'] . ']',
    			'type'		=> $option['field_type'],
    			'label'		=> $option['title'],
    			'description'   => $option['description'], // If applicable (select, radio, etc.) 'choices' => $option['choices'] ) ); }

    Something very important to note here: the value you pass for the 'settings' parameter must be the same as the option ID you define in register_setting(). Also, assuming that you are properly using a single options array, the structure 'theme_slug_options[id]' is important, since that is what gets passed to the Settings API settings page form fields, so you want to ensure that you pass the same structure to the Customizer. That way, the Customizer will properly retrieve and save the user’s current settings.

    For simplicity, I use the same structure 'theme_slug_options['. $option['id'] . ']' for the ID of the setting, the ID of the control, and the value of the 'settings' key passed to the control.

    Also, if you need to add custom controls, you can loop through the option types separately. For example, if you want to add a core color control:

    foreach ( $settings_parameters as $option ) {
    	// Add controls for built-in control types		
    	if ( in_array( $option['field_type'], array( 'text', 'checkbox', 'radio', 'select', 'dropdown_pages', 'textarea' ) ) ) {
    		// Add setting control
    		$wp_customize->add_control(
    			// $id
    			'theme_slug_options[' . $option['id'] . ']',
    			// parameters array
    			array()
    		);
    	}
    	// Add color control
    	else if ( 'color' == $option['field_type'] ) {
    		$wp_customize->add_control( 
    			new WP_Customize_Color_Control( 
    				$wp_customize, 
    				'link_color', 
    				array() 
    			) 
    		);
    	}
    }
    

    You can use the same method for any of the core controls, or for custom controls.

    Sanitization/Validation

    All-Settings Callback via register_setting()

    With the Options API, you register your Theme options array using register_setting(), the third parameter of which is the sanitization/validation callback:

    register_setting(
    	// $optiongroup
    	'theme_slug_options',
    	// $option
    	'theme_slug_options',
    	// $sanitize_callback
    	'theme_slug_options_validate'
    );
    

    When the Settings API settings page form is submitted, the Theme’s $option object is passed as $_POST data through the $sanitize_callback before being saved to the database.

    With the Customizer API, the same thing happens. If you have called register_setting(), when the Customizer form is submitted, the Theme’s $option object is passed as $_POST data through the $sanitize_callback before being saved to the database.

    Customizer API: All-Settings Callback via sanitize_options_$option Hook

    With the Customizer API, you don’t necessarily have to retain the register_setting() call. You can also hook the $sanitize_callback into the 'sanitize_option_{$option}' hook, which would allow you to remove the register_setting() call altogether:

    add_action( 'sanitize_option_theme_slug_options', 'theme_slug_options_validate' );
    

    Customizer API: Per-Setting Sanitization

    However, the Customizer is different from a settings page, in a way that makes the Customizer much more powerful: the live preview. By configuring settings in the Customizer, the user can see those settings changes applied immediately, via the live preview. But real-time configured settings are not passed through the 'sanitize_option_{$option}' hook until the settings are saved (i.e. when the Customizer form is submitted). That means that, without proper sanitization of the Customizer settings, the potential exists for XSS or other exploits.

    The input will be passed through 'sanitize_callback' passed to $wp_customize->add_setting() not only when the settings are saved, but also when passed to the live previewer. Thus, per-setting sanitization, via the 'sanitize_callback' parameter passed to $wp_customize->add_setting(), is critical.

    Dynamic Sanitization Callbacks

    Let’s look at $wp_customize->add_setting() again:

    $wp_customize->add_setting(
    	// $id
    	'theme_slug_options[' . $option['id'] . ']',
    	// parameters array
    	array(
    		'default'		=> $option['default'],
    		'type'			=> 'option',
    		'sanitize_callback'	=> 'theme_slug_sanitize_' . $option['sanitize']
    	)
    );
    

    Using this method, you need only define one callback for each sanitization type (HTML text, no-HTML text, email, checkbox true/false, etc. For example:

    function theme_slug_sanitize_checkbox( $input ) {
    	return ( ( isset( $input ) && true == $input ) ? true : false );
    }
    function theme_slug_sanitize_html( $input ) {
    	return wp_filter_kses( $input );
    }
    
    function theme_slug_sanitize_nohtml( $input ) {
    	return wp_filter_nohtml_kses( $input );
    }
    

    Dynamic Sanitization Callbacks for Select-Type Options

    The above callbacks, that receive $input, manipulate it, and then return it, are fine for data that only requires sanitization. But what if the data requires validation, such as verifying that $input matches one of the valid choices defined for a select dropdown or radio list? An arbitrary callback such as the ones above will not have the list of valid choices. Fortunately, in addition to $input, the Customizer API passes a second parameter to 'sanitize_callback': the $setting object. We can use this object to grab the list of choices from the control:

    function theme_slug_sanitize_select( $input, $setting ) {
    	// Ensure input is a slug
    	$input = sanitize_key( $input );
    	// Get list of choices from the control
    	// associated with the setting
    	$choices = $setting->manager->get_control( $setting->id )->choices;
    	// If the input is a valid key, return it;
    	// otherwise, return the default
    	return ( array_key_exists( $input, $choices ) ? $input : $setting->default );
    }
    

    Caveat: for this little bit of magic to work, it is imperative that the setting ID is identical to the control ID; otherwise, the callback won’t be able to retrieve the control:

    // Setting
    $wp_customize->add_setting(
    	// $id
    	'theme_slug_options[' . $option['id'] . ']',
    	// parameters array
    	array()
    );
    
    // Control
    $wp_customize->add_control(
    	// $id
    	'theme_slug_options[' . $option['id'] . ']',
    	// parameters array
    	array()
    );
    

    Notice that in both calls, the $id is 'theme_slug_options[' . $option['id'] . ']'.

    Eliminating Unused Options API/Settings API Code

    At this point, your Theme options should be retrieved from the database and exposed in the Customizer, configurable with live preview in the Customizer, and saved properly to the database from the Customizer. Everything in the Settings API settings page should now be redundant with the customizer. The next step is to remove unneeded code.

    Settings API Settings Page

    Now that the Settings API settings page is redundant with the Customizer, it can be removed. The call to add_theme_page() and its callback, calls to add_settings_section() and their callbacks, calls to add_settings_field and their callbacks, as well as any Contextual Help, can all be safely removed.

    register_setting() and All-Settings Sanitization Callback

    As mentioned above, with per-setting sanitization in the Customizer, the all-settings sanitization callback is no longer needed. Also, because the customizer implementation explicitly adds settings and controls for all options in the Theme options array, the call to register_setting() is also no longer required. Both can be removed safely.

    Conclusion

    That’s it! If you have other questions or issues regarding moving from Options API/Settings API to Options API/Customizer API, please post them in the comments below.

     
    • progmastery 12:25 pm on June 11, 2015 Permalink | Log in to Reply

      Thanks for the post @chipbennett.
      Most of the things that can be done using the settings API, can be done also using Customizer.
      However I encountered one drawback the Customizer has.
      Since Settings custom pages are forms submitted to options.php, it is possible to send parameters in arrays with arbitrary depth, like [slider][duration], [slider][effect], and [slider][iamges][0][title]. The same thing is not possible to do using the Customizer.
      Customizer allows only parameters in array if this is multiple select. However semantically not always it is good to separate compound parameters in array.
      Is there any natural simple way to solve this problem? Or maybe customizer has to be improved and enhanced?

      • Chip Bennett 12:38 pm on June 11, 2015 Permalink | Log in to Reply

        A slider is a post-type, and not a Theme option.

        • progmastery 1:42 pm on June 11, 2015 Permalink | Log in to Reply

          I brought this this just as an example of a setting which can be a single compound option in array, but not suitable to display as multiple select in control.

          • Chip Bennett 3:35 pm on June 11, 2015 Permalink | Log in to Reply

            The Customizer can be extended to allow any sort of control that you can imagine. So, even if there were a valid option that consisted of an array (consider an image, that includes height and width parameters as part of the retrievable setting), there’s no reason the Customizer can’t handle it.

        • progmastery 1:46 pm on June 11, 2015 Permalink | Log in to Reply

          Let me disagree with you. Why should a slider in the header be custom post type and not a setting customizable through the theme backend?

      • Justin Tadlock 4:34 pm on June 11, 2015 Permalink | Log in to Reply

        I wrote a tutorial that utilizes an array for saving data. It’s not exactly what you’re going for, but it should give you a good jumping-off point.

        The actual content of the slides in a slider are definitely content. The JS/CSS/Output can be handled by a theme because they’re presentation, but the creation of the actual content shouldn’t be a theme option. That can be in a slide post type created by a plugin or it can be core post types (e.g., posts, pages, attachments).

        • progmastery 6:41 pm on June 11, 2015 Permalink | Log in to Reply

          Thanks for clarifying the issue with slider content, of course slider should include already existing content and not create its own.
          In the tutorial, it’s the most obvious way to use multiple data in customizer control. And that is what we already do. Indeed everything can be joined into plain string or JSON. But that becomes too complicated and adds quite a lot of JS code, instead of which I would like to see something simpler.

          • Justin Tadlock 7:22 pm on June 11, 2015 Permalink | Log in to Reply

            I actually need to update that tutorial. I forgot to add my more recent changes that doesn’t do the plain string. It’s much simpler.

  • Chip Bennett 7:31 pm on June 2, 2015 Permalink |  

    Meeting Notes 6/2/2015 

    The Theme Review Team met at our usual time today.

    The first item on the agenda was a discussion of the proposal for a curated, multi-tier directory/review process. @greenshady will have a follow-up post soon, for a summary of that discussion, and continued discussion.

    The second item on the agenda was a discussion of allowable content creation for Themes, per the presentation-vs-functionality requirement. Based on that discussion, the following types of content creation are allowable for Themes, as they represent trivial user content:

    • Site footer text
    • Call-to-Action (CTA) buttons/widgets
    • One-off descriptive content blocks (about us/profile/etc.)
    • Custom presentation of existing user data, with trivial content additions such as a widget/content block with a static page link, custom icon, custom title/description)

    No consensus was reached regarding repeatable-field content (testimonials, services, team members, etc.). We will have a follow-up blog post to discuss this type of content specifically.

    The third item on the agenda was a discussion of the team’s code snippet library. Based on that discussion, we will begin adding code examples to the Theme Review Team GitHub account, beginning with code examples for basic implementation of the Customizer API using core controls.

    As a reminder, if anyone has ideas for improving the Theme directory, the Theme review process, or anything related to the work of the Theme Review Team, please join in the discussion on this post.

     
  • Chip Bennett 3:16 pm on June 2, 2015 Permalink |  

    Content Creation Discussion: Examples 

    In anticipation of the content creation discussion, and as a continuation of last week’s meeting, please post in the comments examples of types of content that you believe need clarification.

    To reiterate: what we want to do is two-fold:

    1. Clarify what constitutes user content
    2. Identify what, if any, of such content is acceptable to be defined by the Theme

    Please read @greenshady‘s post, where you will find the obvious things that are out-of-scope:

    • Custom post types.
    • Custom taxonomies.
    • Non-presentational post metadata.
    • Database tables.
    • Shortcodes.
    • Custom comment types.

    Justin lists four types of other content:

    • Footer text
    • Portfolio projects
    • Profile widget
    • Front-page content sections

    If you have more, please post your examples here, before discussing them in the meeting, in the hopes that the discussion in Slack will be as orderly/organized as possible. Also, please try to be as descriptive as possible. A “custom text widget” doesn’t really help. What is the purpose of that custom text widget? What type of content is it intended to create/hold/present?

     
    • superwinner 3:24 pm on June 2, 2015 Permalink | Log in to Reply

      Can we give examples of themes?

    • progmastery 3:28 pm on June 2, 2015 Permalink | Log in to Reply

      What about these?

      Widgets for simple Advertisements (banner, text) with or without click counting.
      Widgets for custom code inserted by user.
      Post Metadata : number of post views. This can also be presentational if used for arranging posts in blog by popularity.

    • cats_456 3:39 pm on June 2, 2015 Permalink | Log in to Reply

      Input field for a link in a ‘call to action button’.

    • Maria Antonietta Perna 3:39 pm on June 2, 2015 Permalink | Log in to Reply

      Just to clarify, would an option in the Customizer for the user to change footer text be allowed?

    • Nilambar Sharma 3:40 pm on June 2, 2015 Permalink | Log in to Reply

      • Widget for Call to action; Text field for a sentence, button text, button URL,
      • Widget with title and text but with lots of design customization like, background color, border color, border width border style and bla bla style settings. It may be presentational but when switching theme, lots of hours could go waste.
      • Chip Bennett 3:43 pm on June 2, 2015 Permalink | Log in to Reply

        What would that “sentence” be? What would the “title and text” be?

      • Chip Bennett 3:46 pm on June 2, 2015 Permalink | Log in to Reply

        I think a custom Call-to-Action Widget represents extremely trivial content, and as such is reasonable for a Theme to define.

        • Nilambar Sharma 4:01 pm on June 2, 2015 Permalink | Log in to Reply

          Today, we need to mark now what is trivial. If textarea is added, then whole lot of content could be added and that may not be trivial. But it text input, it may be trivial.

          • Chip Bennett 4:06 pm on June 2, 2015 Permalink | Log in to Reply

            Again, please focus on data types, not the means of input of those data types. Input versus textarea is not really what we’re trying to clarify here.

    • ThemeZee 3:44 pm on June 2, 2015 Permalink | Log in to Reply

      A textarea option in the Customizer that allows users to add a banner ad in the header area using HTML code ( escaped with wp_kses_post )

      • Chip Bennett 3:46 pm on June 2, 2015 Permalink | Log in to Reply

        Why can that not be a core Widget area, using a core text Widget?

        • ThemeZee 3:48 pm on June 2, 2015 Permalink | Log in to Reply

          Because users tend to add any widget to the header area then and expect that they all work there properly. A simple setting seemed easier :) But I agree that widgets would be possible as well.

          • Chip Bennett 3:53 pm on June 2, 2015 Permalink | Log in to Reply

            So provide Theme documentation that explains the intended usage of a given Widget area. You can’t always make users use your Themes the way you intend. Even if you create a custom Widget, that doesn’t mean they won’t try to put a different, arbitrary widget in that area. Or try to put seven Widgets in an area designed for three. The best laid plans of mice and men, and all that…

        • acosmin 3:48 pm on June 2, 2015 Permalink | Log in to Reply

          because you can’t use some html elements with the core one

          • Chip Bennett 3:58 pm on June 2, 2015 Permalink | Log in to Reply

            What HTML elements does a banner ad need, that aren’t available using the core text widget?

            • acosmin 4:03 pm on June 2, 2015 Permalink

              :) have you seen google adsense?

            • Chip Bennett 4:07 pm on June 2, 2015 Permalink

              Google adsense (and similar) should be enqueued and hooked into wp_head or wp_footer. And more importantly, Google AdSense is something that should be Plugin-defined to begin with.

            • acosmin 4:14 pm on June 2, 2015 Permalink

              I don’t think that helps if you want the ad to appear in the area :)

            • Chip Bennett 4:20 pm on June 2, 2015 Permalink

              Why would it not help? The Theme provides the template location, and the plugin provides the output (e.g. Widget).

            • acosmin 4:15 pm on June 2, 2015 Permalink

              seems I am not allowed to write

            • acosmin 4:16 pm on June 2, 2015 Permalink

              body tag

    • ThemeZee 3:53 pm on June 2, 2015 Permalink | Log in to Reply

      Custom Widgets that display posts from a selected category. I’m using these a lot to allow users to create a custom layouted and flexible magazine homepage, for example: http://preview.themezee.com/leeway/

      These should be 100% presentational, because no content is created.

    • kevinhaig 4:05 pm on June 2, 2015 Permalink | Log in to Reply

      Static Home Pages populated by option data should be allowed.

      As a compromise I feel authors should be able to populate a static home page with option content.

      Static home pages are an important part of a WordPress website, as important as a blog, or styling in a theme. Authors need to be able to distinguish their themes not only with styling or layout, but with a distinct home page.

      I think it is more difficult to control the look and content of a home page outside a theme, unless a plugin essentially duplicates the integration of a static home page with the theme. In such a case, it seems better to have it in the theme in the first place.

      To suggest content is lost when a user switches a theme is a bit presumptuous. I would suggest you survey to find out what users build a theme without some sort of Notepad type backup of content. Configuration is lost, but I suspect in most cases content is not. When you switch themes you will always lose configuration.

      I have changed a lot of websites myself, and never had a problem re-configuring a home page. In fact it provides an opportunity to revisit your content.

      • Chip Bennett 4:09 pm on June 2, 2015 Permalink | Log in to Reply

        What specific type of front-page content?

        • kevinhaig 4:11 pm on June 2, 2015 Permalink | Log in to Reply

          images, titles, textareas with html

          • kevinhaig 4:11 pm on June 2, 2015 Permalink | Log in to Reply

            and of course links

          • Chip Bennett 4:13 pm on June 2, 2015 Permalink | Log in to Reply

            A “textarea” isn’t a content type. What is the content being displayed?

            Images: where/how are the images created?

            Titles: titles of what?

            • kevinhaig 4:17 pm on June 2, 2015 Permalink

              Is all this critical to the discussion? It is content.

              A title is a line of text.
              An image is a link to a image uploaded by media uploader
              textarea with html is ……well content with html???

            • Chip Bennett 4:22 pm on June 2, 2015 Permalink

              Yes, it is critical. The type of content is what we’re discussing.

              An image uploaded by the media uploader is an image in the media manager, and not defined by the Theme.

              An arbitrary bit of content and HTML is precisely what a core text widget is for – title included.

            • Towfiq I. 4:24 pm on June 2, 2015 Permalink

              You cant add links, bold text, italic text, images with core text widget without knowing html. do you realize that?

            • Chip Bennett 4:27 pm on June 2, 2015 Permalink

              What’s the point?

            • kevinhaig 4:26 pm on June 2, 2015 Permalink

              Using the supplied text widget is not practical. Setting it up for proper presentation would be ridiculously complicated.

            • Chip Bennett 4:27 pm on June 2, 2015 Permalink

              Why? It’s just CSS.

            • Towfiq I. 4:31 pm on June 2, 2015 Permalink

              @chipbennett you said “An arbitrary bit of content and HTML is precisely what a core text widget is for – title included.” end users cant add html content becuase they are not devs. They dont know how to use html to include links, images, bold text, italic text etc in the text widget. So creating html content with text widget is not possible for endusers hence you statement is incorrect.

            • Chip Bennett 4:33 pm on June 2, 2015 Permalink

              I find that to be an unnecessarily condescending view of end users. I would also say that a rich-text Widget, in general, is Plugin territory.

            • kevinhaig 4:34 pm on June 2, 2015 Permalink

              OK….example

              You have a linked centered image, title, and underneath, you have a paragraph in a service box. Now you have three service boxes across the page. You want to give users the choice of using a font icon instead of an image.

              To facilitate all this in a widgetized area is ridiculous.

              You would need at least 9 widgetized areas, or have the user extremely knowledgeable in html.

            • Chip Bennett 4:37 pm on June 2, 2015 Permalink

              Linked centered image, title, with paragraph beneath. This all *could* be done using nothing more than the core image handling (image, image title, image description), but I would think that this would be trivial, and don’t see a major issue with a Theme defining image title/description.

              Service boxes: this starts to border on pseudo-CPTs. This is the meat of the “gray area” that we need to discuss.

            • kevinhaig 4:39 pm on June 2, 2015 Permalink

              Wow….that’s all I can say :(

            • kevinhaig 5:24 pm on June 2, 2015 Permalink

              I am fully aware of the image caption and description….I use it in portfolio pages.

              You forgot to account for the option in the example to use a font icon instead of an image?

              If using options to upload the image, the user then has to go to the media manager, find the image and input caption and description. When it could all be done at once in the options panel. I realize there is probably a way to populate the image caption and description from the options panel, but still what about the font icon case? Overall the user experience is not as good I think.

              Also you have to remember, developers like myself are not as expert as you are in WordPress. Trivial solutions to you (I find that a slap in the face by the way), are not that obvious for some developers. It’s like you have to jump through hoops and to find a solution so we are not adding content.

              This kind of content likely has to be reviewed and re-done anyway on a theme change. Because the format of a Static Home Page will be different.

            • Chip Bennett 5:48 pm on June 2, 2015 Permalink

              I am fully aware of the image caption and description….I use it in portfolio pages.

              You forgot to account for the option in the example to use a font icon instead of an image?

              Like I said: an icon font character is trivial content.

              If using options to upload the image, the user then has to go to the media manager, find the image and input caption and description. When it could all be done at once in the options panel. I realize there is probably a way to populate the image caption and description from the options panel, but still what about the font icon case? Overall the user experience is not as good I think.

              Which is primarily the reason that I agree with you: ad-hoc title/description for an image in that case is trivial content.

              Also you have to remember, developers like myself are not as expert as you are in WordPress. Trivial solutions to you (I find that a slap in the face by the way), are not that obvious for some developers.

              I have not said that any particular implementation or solution is trivial. I have only said that certain content types are trivial – and as such, would be acceptable for Themes to define/create.

              It’s like you have to jump through hoops and to find a solution so we are not adding content.

              I’m also not looking to “jump through hoops” to avoid creating content. There are cases where I’m pointing out that there are core alternatives. Even if the ultimate conclusion is that certain content types are acceptable for Themes to define (and it’s clear that there are), why is it a problem (or an insult, even), to try to point out alternative approaches that use core methods?

              This kind of content likely has to be reviewed and re-done anyway on a theme change. Because the format of a Static Home Page will be different.

              In some cases, yes. but not in all cases.

        • Towfiq I. 4:38 pm on June 2, 2015 Permalink | Log in to Reply

          So you are saying that most users who use WordPress knows html? Are you talking from experience? I have been providing support for my themes for 6 years through 20k support tickets and I KNOW Most people who uses WordPress DONT KNOW HTML.

          What you are trying to do is make WordPress accessible to only those who knows html.

          • Chip Bennett 4:41 pm on June 2, 2015 Permalink | Log in to Reply

            No, I didn’t say that most users know HTML. I said that an arbitrary rich-text widget is Plugin territory.

            • Towfiq I. 4:42 pm on June 2, 2015 Permalink

              who said anything about a rich text widget?

            • Chip Bennett 4:43 pm on June 2, 2015 Permalink

              A rich-text widget is exactly what you’re talking about: a text widget, with the ability to add formatting and HTML links.

            • Towfiq I. 4:48 pm on June 2, 2015 Permalink

              No I am not talking about Rich Text widget. Please read again. I am saying that content creation through theme options/customizer for Theme Frontpage should be allowed as it was allowed for past 4 years. and your proposed method => “html content creation for frontpage with core text widget” is not a feasible solution. thats what I tried to say in my previous comments.

            • Chip Bennett 4:55 pm on June 2, 2015 Permalink

              And I am asking for specific types of content that you want the Theme to create. Not the format of the content, but the type of content.

            • acosmin 4:48 pm on June 2, 2015 Permalink

              I think he is talking about a widget that has a few more input fields besides a textarea

            • Towfiq I. 5:04 pm on June 2, 2015 Permalink

              @chipbennett Lets say I am talking about a theme link this one, which has few sections like a cta section and a services blocks section. https://goo.gl/eEotSz

              you are saying that, all those sections should be created with core text widget by the end users. Which will require them to learn html because they will need to add images, links, buttons etc. So ultimately, to use that theme you will have to know html..how is that a feasible solution?

            • Chip Bennett 5:06 pm on June 2, 2015 Permalink

              I am saying no such thing. I am asking for examples of different content types, for specific discussion about each specific content type. A CTA is one type of content. “Services” are a different kind of content.

          • Towfiq I. 5:16 pm on June 2, 2015 Permalink | Log in to Reply

            @chipbennett I am not sure how they are different. kindly tell me how they are different.

            and lets talk about the service blocks section. how should devs implement this type of sections in a theme without using theme options/customizer?

    • cats_456 4:47 pm on June 2, 2015 Permalink | Log in to Reply

      What is the correct way for creating section ‘our services’ on the front page without content creation?

      • Chip Bennett 4:54 pm on June 2, 2015 Permalink | Log in to Reply

        So, the content type is “services”? Again, this is that pseudo-CPT that needs to be discussed.

        • Towfiq I. 4:55 pm on June 2, 2015 Permalink | Log in to Reply

          what do you mean by pseudo-CPT? I have never header this term before. kindly elaborate?

          • Chip Bennett 4:58 pm on June 2, 2015 Permalink | Log in to Reply

            Pseudo-custom post type. It is a “custom post type” in disguise. It has all the characteristics of a custom post type, but implemented using some other method (custom widget, Theme option, etc.).

        • cats_456 5:03 pm on June 2, 2015 Permalink | Log in to Reply

          No, this is not a content type. It is a menu with links to a pages (1 link for shop index, second link for portfolio index, third link for blog index).

          • Chip Bennett 5:10 pm on June 2, 2015 Permalink | Log in to Reply

            A menu is a content type – in fact, it is a core-defined post-type.

            Now, if all you’re doing is displaying a link to a page, then you’re not creating content. If you’re displaying a page title, then you’re not creating content. If you’re pulling an excerpt from that page, then you’re not creating content. (Though you may need to enable support for excerpts for the page post-type).

            If you’re assigning an icon to that link, then you’re creating content. However, I would think that the content would be trivial, and acceptable.

    • Kadence Themes 7:06 pm on June 2, 2015 Permalink | Log in to Reply

      Hey, Another example of “Front-page content sections”. For clarity I use these in my themes if you want to look. An option to add a home page slider through the theme options. The theme options has a place to choose a media file or multiple files from the media library and assign them to a slider that shows on the front page. I think it would be important to clarify if an option like this is going to be “out-of-scope” vs a call to action in the theme options.

      • Chip Bennett 7:36 pm on June 2, 2015 Permalink | Log in to Reply

        “Front page content sections” is not specific. Front page is a location, not a content type..

        If you’re referring to sliders: the question is really a matter of what content the slider will display. Is the Theme merely flagging existing content to be displayed, or is it creating a “slide” content type?

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel