<?php namespace Ubik\SEO; $options = \Ubik\init(__FILE__, ['document_title' => false, 'feed_credits' => false, 'meta_strip_shortcodes' => false, 'yoast_default_description' => false, 'yoast_open_graph' => false, 'yoast_remove_post_filter' => false], function ($options) { return \Ubik\validate($options, ['array_or_false' => ['meta_strip_shortcodes']]); }); // == DOCUMENT TITLE == // // Clean document title output for better SEO; hooks into `wp_title` // @filter: ubik_seo_document_title_raw // @filter: ubik_seo_document_title_final function document_title($title = '', $sep = '-', $seplocation = 'right') { // Remove default seperator and add spacing if (trim($sep) === '' || $sep === '»' || $sep === '»') { $sep = '-'; } $sep = ' ' . $sep . ' '; // Determine page number, if any $page_num = ''; if (is_paged()) { global $page, $paged; if ($paged >= 2 || $page >= 2) { $page_num = $sep . sprintf(esc_html__('Page %d', 'ubik'), max($paged, $page)); } } // Generate the title using our all-purpose title function $title = apply_filters('ubik_seo_document_title_raw', ubik_title()); $name = get_bloginfo('name'); $desc = get_bloginfo('description'); // Handle three scenarios: home/front page, archive feeds, and everything else
<?php namespace Ubik\Meta; $options = \Ubik\init(__FILE__, ['grace_period' => 10800, 'humanize_archives' => false, 'humanize_core' => false, 'humanize_dates' => false, 'humanize_limit' => 4838000, 'microformats' => false], function ($options) { return \Ubik\validate($options, ['integer' => ['humanize_limit'], 'integer_or_false' => ['grace_period']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // A standard statement featuring all kinds of post metadata // @filters: ubik_meta_statement function standard() { if (empty($meta = get_data())) { return; } // Initialize $output = []; // Setup basic metadata; the only information we have for sure is type, date, and author if ($meta['updated']) { $output[] = sprintf(wp_kses(__('%1$s %2$s was published %3$s<span class="last-updated"> and updated %4$s</span><span class="by-author"> by %5$s</span>', 'ubik'), ['span' => ['class' => []]]), sprintf('<a href="%s" rel="bookmark">%s</a>', get_permalink(), esc_html__('This', 'ubik')), strtolower($meta['type']), $meta['published'], $meta['updated'], $meta['author']); } else { $output[] = sprintf(wp_kses(__('%1$s %2$s was published %3$s<span class="by-author"> by %4$s</span>', 'ubik'), ['span' => ['class' => []]]), sprintf('<a href="%s" rel="bookmark">%s</a>', get_permalink(), esc_html__('This', 'ubik')), strtolower($meta['type']), $meta['published'], $meta['author']); } if ($meta['categories']) { $output[] = sprintf(esc_html__('Category: %s', 'ubik'), $meta['categories']); } if ($meta['tags']) {
public function validate($options) { return \Ubik\validate($options, ['array' => ['aliases'], 'string_or_false' => ['css_prefix', 'inline_action', 'inline_args', 'path']]); }
<?php namespace Ubik\Search; $options = \Ubik\init(__FILE__, ['form_activate' => true, 'form_class' => 'search-form', 'posts_per_page' => false, 'redirect' => true, 'redirect_random' => false, 'redirect_single' => true], function ($options) { return \Ubik\validate($options, ['integer_or_false' => ['posts_per_page'], 'string' => ['form_class']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($option) { return \Ubik\option(__FILE__, $option); } // == FORM == // // Custom search form; can be hooked to `get_search_forms` action or invoked with `\Ubik\Search\form()` // @filter: ubik_search_help_text // @filter: ubik_search_button // @filter: ubik_search_form function form() { // Define strings and elements; note the presence of two filters, one for help text and the other for the contents of the button $strings = ['id' => 's-' . uniqid(), 'help' => esc_attr(apply_filters('ubik_search_help_text', __('Search', 'ubik')))]; // Assemble complete form return apply_filters('ubik_search_form', sprintf('<form method="get" class="%s" action="%s" role="search">%s%s%s</form>', esc_attr(option('form_class')), trailingslashit(home_url()), sprintf('<label for="%1$s" class="screen-reader-text">%2$s</label>', $strings['id'], $strings['help']), sprintf('<input id="%1$s" name="s" type="search" class="search-field" placeholder="%2$s…" title="%2$s" %3$s/>', $strings['id'], $strings['help'], is_search() ? 'value="' . esc_attr(get_search_query()) . '"' : ''), sprintf('<button type="submit" class="search-submit">%s</button>', apply_filters('ubik_search_form_button', __('Search', 'ubik'))))); } if ($options['form_activate']) { add_filter('get_search_form', __NAMESPACE__ . '\\form'); } // == POSTS PER PAGE == // // Modify how many posts per page are displayed in different contexts; source: http://wordpress.stackexchange.com/questions/21/show-a-different-number-of-posts-per-page-depending-on-context-e-g-homepage function posts_per_page($query) {
<?php namespace Ubik\Series; $options = \Ubik\init(__FILE__, ['order' => 'ASC', 'post_types' => ['post']], function ($options) { return \Ubik\validate($options, ['array' => ['post_types'], 'string_value' => ['order', ['ASC', 'DESC']]]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // Everything you need to implement a quick and dirty post series custom taxonomy function init() { register_taxonomy('series', option('post_types'), ['hierarchical' => false, 'labels' => ['name' => _x('Series', 'taxonomy general name'), 'singular_name' => _x('Series', 'taxonomy singular name'), 'search_items' => esc_html__('Search Series', 'ubik'), 'all_items' => esc_html__('All Series', 'ubik'), 'parent_item' => esc_html__('Parent Series', 'ubik'), 'parent_item_colon' => esc_html__('Parent Series:', 'ubik'), 'edit_item' => esc_html__('Edit Series', 'ubik'), 'update_item' => esc_html__('Update Series', 'ubik'), 'add_new_item' => esc_html__('Add New Series', 'ubik'), 'new_item_name' => esc_html__('New Series Name', 'ubik'), 'menu_name' => esc_html__('Series', 'ubik')], 'rewrite' => ['slug' => 'series', 'with_front' => false, 'ep_mask' => EP_TAGS]]); } add_action('init', __NAMESPACE__ . '\\init'); // Returns an array of series, each containing an array of post IDs in that series function data() { // Attempt to retrieve the current post and exit early if we're not successful if (empty($id = get_the_ID())) { return; } // Retrieve the series terms for the current post $terms = array_map('intval', wp_get_object_terms($id, 'series', ['fields' => 'ids', 'orderby' => 'name', 'order' => 'ASC'])); // Nothing found, let's return if (empty($terms)) { return false; }
<?php namespace Ubik\PasswordForm; $options = \Ubik\init(__FILE__, ['button' => _x('Enter password', 'password form button', 'ubik'), 'button_style' => '', 'class' => 'form-post-password', 'input_style' => '', 'prompt' => _x('This entry is protected. Please enter the password:'******'password form prompt', 'ubik')], function ($options) { return \Ubik\validate($options, ['string' => ['button', 'button_style', 'class', 'prompt']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // Improved HTML5 password form based on WordPress core function function password_form($output = '') { if (empty($id = get_the_ID())) { return $output; } return sprintf('%1$s<form action="%2$s" class="%3$s" method="post"><label for="%4$s" class="screen-reader-text">%5$s</label><input name="post_password" id="%4$s" type="password" size="20" required=""%6$s/><button id="submit" type="submit" name="submit"%7$s>%8$s</button></form>', sprintf('<p>%s</p>', esc_html(option('prompt'))), esc_url(site_url('wp-login.php?action=postpass', 'login_post')), option('class'), esc_attr('password-input-' . intval($id)), esc_html__('Password', 'ubik'), option('input_style') ? ' style="' . esc_attr(option('input_style')) . '"' : '', option('button_style') ? ' style="' . esc_attr(option('button_style')) . '"' : '', option('button')); } add_filter('the_password_form', __NAMESPACE__ . '\\password_form');
<?php namespace Ubik\Markdown; $options = \Ubik\init(__FILE__, ['block_elements' => ['address', 'aside', 'blockquote'], 'footnotes_more' => true, 'footnotes_rel' => true, 'transform' => ['get_the_author_description', 'get_the_excerpt', 'term_description', 'widget_text'], 'transform_more' => []], function ($options) { return \Ubik\validate($options, ['array' => ['transform_more'], 'array_or_false' => ['block_elements', 'transform']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($option) { return \Ubik\option(__FILE__, $option); } // == BLOCK ELEMENTS == // if ($options['block_elements']) { add_filter('content_save_pre', __NAMESPACE__ . '\\block_elements'); } elseif ($options['block_elements'] === false) { add_filter('content_save_pre', __NAMESPACE__ . '\\block_elements_disable'); } // Enable additional Markdown Extra processing within specified block elements; this only occurs when content is saved function block_elements($content) { $elements = option('block_elements'); if (!empty($elements)) { $content = preg_replace('/<(' . implode('|', $elements) . ')>/', '<$1 markdown="1">', $content); } return $content; } // Disable additional Markdown Extra processing of block elements function block_elements_disable($content) { return str_replace(' markdown=\\"1\\"', '', $content);
<?php namespace Ubik\Colophon; $options = \Ubik\init(__FILE__, ['author' => false, 'format' => _x('%1$s%2$s %3$s. %4$s.', 'Colophon: glyph/date/credit/powered by', 'ubik'), 'from' => false, 'glyph' => '©', 'to' => date("Y")], function ($options) { return \Ubik\validate($options, ['string' => ['format', 'glyph']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // Generate a standard colophon from three parts: copyright statement, credits, and the "powered by" line // @filter: ubik_colophon // @filter: ubik_colophon_date // @filter: ubik_colophon_credit // @filter: ubik_colophon_tech function colophon($args = []) { $args = wp_parse_args($args, ['format' => option('format'), 'from' => option('from'), 'to' => option('to'), 'glyph' => option('glyph'), 'author' => option('author')]); return apply_filters('ubik_colophon', sprintf(esc_html($args['format']), $args['glyph'], apply_filters('ubik_colophon_date', colophon_date($args['from'], $args['to'])), apply_filters('ubik_colophon_credit', colophon_credit($args['author'])), apply_filters('ubik_colophon_tech', colophon_tech()))); } // Generate a colophon date range function colophon_date($from = '', $to = '') { if ($from && $to) { return $from . '–' . $to; } // en-dash return $from . $to; }
<?php namespace Ubik\Terms; $options = \Ubik\init(__FILE__, ['categorized' => null, 'description_shortcodes' => true, 'taxonomy_shortcodes' => ['post_tag' => ['name' => 'tag']]], function ($options) { return \Ubik\validate($options, ['array_or_false' => ['taxonomy_shortcodes']]); }); function option($option) { return \Ubik\option(__FILE__, $option); } // == CORE == // // Return an array of ancestors of a given term in a hierarchical taxonomy // @filter: ubik_terms_ancestors function ancestors($term = '', $taxonomy = '') { // Check query variables for term and taxonomy data and exit early if nothing works or the taxonomy isn't hierarchical if (empty($term)) { $term = get_query_var('term'); } if (empty($taxonomy)) { $taxonomy = get_query_var('taxonomy'); } if (!term_exists($term) || !taxonomy_exists($taxonomy) || !is_taxonomy_hierarchical($taxonomy)) { return; } // Get initial term data if (is_int($term)) { $term = get_term_by('id', $term, $taxonomy); } else { $term = get_term_by('slug', $term, $taxonomy);
<?php namespace Ubik\Views; $options = \Ubik\init(__FILE__, ['default_archives' => false, 'default_home' => false, 'taxonomies' => apply_filters('ubik_views_taxonomies', ['category', 'post_tag']), 'template_filter' => false, 'views' => ['gallery' => ['name' => esc_html__('Gallery', 'ubik'), 'template' => 'thumb'], 'list' => ['name' => esc_html__('List', 'ubik'), 'template' => 'list'], 'posts' => ['name' => esc_html__('Posts', 'ubik'), 'template' => '']]], function ($options) { return \Ubik\validate($options, ['array' => ['taxonomies', 'templates'], 'array_or_false' => ['default_archives'], 'string_or_false' => ['default_home']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // Setup rewrite tags and rules; be sure to flush permalinks to activate function setup_rewrite() { if (!($views = option('views'))) { return; } // Cycle through each template to add rewrite tags and rules foreach ($views as $view => $data) { add_rewrite_tag('%' . $view . '%', ''); // Regex is currently blank; if we want to capture: '([^/]+)' // Root rewrite rules; this allows us to swap views on the homepage and such add_rewrite_rule($view . '/page/?([0-9]{1,})/?$', 'index.php?&' . $view . '=&paged=$matches[1]', 'top'); add_rewrite_rule($view . '/?$', 'index.php?&' . $view . '=', 'top'); // Cycle through each taxonomy to apply additional rules if ($taxonomies = option('taxonomies')) { foreach ($taxonomies as $taxonomy) { // Clear existing variables from the last run through the loop unset($tax, $slug, $query_var); // Only proceed if we have a match
<?php namespace Ubik\Filter; $options = \Ubik\init(__FILE__, ['exclude_cats' => false, 'exclude_formats' => false, 'exclude_tags' => false, 'include_all' => false], function ($options) { return \Ubik\validate($options, ['array_or_false' => ['exclude_cats', 'exclude_formats', 'exclude_tags'], 'string_or_false' => ['include_all']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // == FILTERS == // // Exclude specific categories from the homepage function exclude_cats($query) { if (!is_admin() && $query->is_home() && $query->is_main_query() && $query->get('ubik_include_all') !== true) { // Returns a list of term IDs $terms = terms_transform(option('exclude_cats'), 'category'); // One final test and then we're good to go if (!empty($terms) && $terms === array_filter($terms, 'is_int')) { $query->set('category__not_in', $terms); } } } if ($options['exclude_cats']) { add_filter('pre_get_posts', __NAMESPACE__ . '\\exclude_cats'); } // Exclude specific post formats from the homepage function exclude_formats($query) {
<?php namespace Ubik\Optimize; $options = \Ubik\init(__FILE__, ['clean_allowed_tags' => true, 'clean_body_classes' => true, 'clean_feed_title' => true, 'clean_head_tag' => true, 'clean_language_attributes' => true, 'clean_post_title_private' => false, 'clean_post_title_protected' => false, 'clean_style_tag' => true, 'clean_self_closing_tags' => ['comment_id_fields', 'get_avatar', 'post_thumbnail_html'], 'disable_attachment_comments' => false, 'disable_comments_feed' => false, 'disable_embeds' => false, 'disable_emoji' => false, 'disable_generator' => true, 'disable_jquery' => false, 'disable_jquery_migrate' => false, 'disable_open_sans' => false, 'disable_pingbacks' => false, 'disable_recent_comments_css' => true, 'scripts_async' => false, 'scripts_async_exceptions' => ['jquery'], 'scripts_jquery_footer' => false], function ($options) { return \Ubik\validate($options, ['array' => ['scripts_async_exceptions'], 'array_or_false' => ['self_closing_tags']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // Modify what tags and attributes are allowed in comments; also changes the text output of allowed_tags(); doesn't affect administrators // @filter: ubik_comments_allowed_tags function clean_allowed_tags() { global $allowedtags; $allowedtags = apply_filters('ubik_comments_allowed_tags', ['a' => ['href' => true], 'b' => [], 'blockquote' => ['cite' => true], 'cite' => [], 'code' => [], 'em' => [], 'i' => [], 'q' => ['cite' => true], 'strong' => []]); } if ($options['clean_allowed_tags']) { add_action('init', __NAMESPACE__ . '\\clean_allowed_tags', 11); } // Clean page template classes, removing duplicates (e.g. 'page-template-page-templates') that come up when you store page templates in a subdirectory function clean_body_classes($classes) { foreach ($classes as $id => $class) { if (strpos($class, 'page-templates')) { unset($classes[$id]); } } return $classes;
<?php namespace Ubik\Google; $options = \Ubik\init(__FILE__, ['analytics' => false, 'analytics_async' => false, 'analytics_legacy' => false, 'analytics_require' => false, 'fonts' => false, 'fonts_admin' => false, 'fonts_handle' => sanitize_title(wp_get_theme()) . '-fonts', 'fonts_method' => false], function ($options) { return \Ubik\validate($options, ['string_or_false' => ['analytics', 'fonts', 'fonts_admin', 'fonts_method'], 'string' => ['fonts_handle']]); }); // Shorthand function to retrieve an option within namespaced functions in this module (optional) function option($option) { return \Ubik\option(__FILE__, $option); } // == ANALYTICS == // // Legacy Analytics tracking code (2014 and before) function analytics_legacy() { ?> <script> var _gaq = _gaq || []; _gaq.push(['_setAccount', '<?php echo option('analytics'); ?> ']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script><?php }
<?php namespace Ubik\Formats; $options = \Ubik\init(__FILE__, ['feed_exclude' => false, 'feed_exclude_formats' => ['post-format-aside', 'post-format-chat', 'post-format-link', 'post-format-quote', 'post-format-status'], 'rewrite_base' => false], function ($options) { return \Ubik\validate($options, ['array' => ['feed_exclude_formats'], 'string_or_false' => ['rewrite_base']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // Exclude certain post formats from the feed; via https://wordpress.stackexchange.com/questions/18412/how-to-exclude-posts-of-a-certain-format-from-the-feed function feed_exclude(&$wp_query) { if ($wp_query->is_feed()) { $post_format_tax_query = ['taxonomy' => 'post_format', 'field' => 'slug', 'terms' => option('feed_exclude_formats'), 'operator' => 'NOT IN']; $tax_query = $wp_query->get('tax_query'); if (is_array($tax_query)) { $tax_query = $tax_query + $post_format_tax_query; } else { $tax_query = [$post_format_tax_query]; } $wp_query->set('tax_query', $tax_query); } } if ($options['feed_exclude']) { add_action('pre_get_posts', __NAMESPACE__ . '\\feed_exclude'); } // Get link metadata and trims protocol and trailing slash for display; assumes WP-Post-Formats or equivalent is in use function link_meta()
<?php namespace Ubik\Main; $options = \Ubik\init(__FILE__, ['comments_link_protected' => false, 'comments_link_show_none' => false, 'excerpt_length' => 50, 'excerpt_more' => _x('...', 'excerpt ending', 'ubik'), 'more_link' => _x('Continue reading', 'more link', 'ubik'), 'more_link_arrow' => ' →', 'page_excerpts' => true], function ($options) { return \Ubik\validate($options, ['integer' => ['excerpt_length'], 'string' => ['excerpt_more', 'more_link'], 'string_or_false' => ['more_link']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // == COMMENTS == // // A cleaner implementation of `comments_popup_link()`; argument order mimics core functionality // Note: this could be re-implemented with `form` and `button` elements but there are concerns about the accessibility of such an approach for simple functions like this one // @filter: ubik_comments_link_text function comments_link($zero = false, $one = false, $more = false, $class = '', $none = false) { // Default values lifted from WordPress core if (false === $zero) { $zero = esc_html__('No Comments', 'ubik'); } if (false === $one) { $one = esc_html__('1 Comment', 'ubik'); } if (false === $more) { $more = esc_html__('% Comments', 'ubik'); } if (false === $none) { $none = esc_html__('Comments Off', 'ubik'); }
<?php namespace Ubik\Example; $options = \Ubik\init(__FILE__, ['option' => true, 'feature' => false], function ($options) { // Optionally pass an anonymous function as third parameter to validate options passed by the theme return \Ubik\validate($options, ['array' => ['dropdown_post_types', 'dropdown_taxonomies'], 'array_or_false' => ['link_archive', 'quick_edit']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // == FUNCTION == // // Describe your function // @filter: ubik_example_filter function example() { // The $options array is not available inside namespaced functions; use the option() function instead if (option('feature')) { $example = "Feature is on"; } else { $example = "Feature is off"; } echo apply_filters('ubik_example_filter', $example); } if ($options['option']) { add_action('init', __NAMESPACE__ . '\\example'); }
<?php namespace Ubik\Related; $options = \Ubik\init(__FILE__, ['filter' => true, 'max_results' => 20, 'post_type' => 'post', 'taxonomies' => ['post_tag' => 1], 'taxonomies_extended' => []], function ($options) { return \Ubik\validate($options, ['array' => ['taxonomies', 'taxonomies_extended'], 'integer' => ['max_results'], 'string' => ['post_type']]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($options) { return \Ubik\option(__FILE__, $options); } // == RELATED POSTS == // // Various ways to retrieve a list of related posts // The general approach: score posts based on how many taxonomy terms they have in common // Returns a list of post IDs; how you output this is up to the theme // Note: much of this is based on a post by kingkool68 on WordPress Stackexchange: // https://wordpress.stackexchange.com/questions/98024/related-posts-by-multiple-tags // Caveat: this was one of my earlier experiments with PHP and the entire approach, although it produces workable results, is computationally expensive // Master function for retrieving related posts; validates input and manages single or multiple taxonomies switch // @filter: ubik_related_taxonomies // @filter: ubik_related_max_results function posts($post_id = '') { if (empty($post = get_post($post_id))) { return; } // Check the post ID passed to this function if (!is_int($post_id)) { $post_id = $post->ID; }
<?php namespace Ubik\Admin; if (!is_admin()) { return; } $options = \Ubik\init(__FILE__, ['link_manager_disable' => false, 'post_list_thumbnail' => false, 'post_list_thumbnail_size' => 60, 'post_slug_alphanumeric' => false, 'user_contact_methods' => false, 'user_contact_methods_clean' => true, 'user_description_html' => false, 'view_all_settings' => false, 'visual_editor' => true], function ($options) { return \Ubik\validate($options, ['integer_range' => ['post_list_thumbnail_size', [10, 200]]]); }); // Shorthand function to retrieve an option within namespaced functions in this module function option($option) { return \Ubik\option(__FILE__, $option); } // == POST LIST THUMBNAILS == // // Featured image/post thumbnail column in post list; adapted from http://www.rektproductions.com/display-featured-images-in-admin-post-list/ // @filter: ubik_admin_post_list_thumbnail_style function post_list_thumbnail_columns($defaults) { $defaults['featured_image'] = __('Thumb', 'ubik'); return $defaults; } function post_list_thumbnail_custom_columns($column_name, $id) { if ($column_name === 'featured_image') { echo the_post_thumbnail([option('post_list_thumbnail_size'), option('post_list_thumbnail_size')]); } } function post_list_thumbnail_columns_style() {