diff options
Diffstat (limited to 'inc')
| -rw-r--r-- | inc/class-wp-bootstrap-navwalker.php | 559 | ||||
| -rw-r--r-- | inc/custom-comments.php | 71 | ||||
| -rw-r--r-- | inc/custom-header.php | 49 | ||||
| -rw-r--r-- | inc/customizer.php | 135 | ||||
| -rw-r--r-- | inc/editor.php | 78 | ||||
| -rw-r--r-- | inc/enqueue.php | 34 | ||||
| -rw-r--r-- | inc/extras.php | 114 | ||||
| -rw-r--r-- | inc/hooks.php | 49 | ||||
| -rw-r--r-- | inc/jetpack.php | 67 | ||||
| -rw-r--r-- | inc/pagination.php | 56 | ||||
| -rw-r--r-- | inc/setup.php | 132 | ||||
| -rw-r--r-- | inc/style-wpcom.css | 7 | ||||
| -rw-r--r-- | inc/template-tags.php | 137 | ||||
| -rwxr-xr-x | inc/theme-settings.php | 36 | ||||
| -rw-r--r-- | inc/widgets.php | 119 | ||||
| -rw-r--r-- | inc/woocommerce.php | 140 | ||||
| -rw-r--r-- | inc/wpcom.php | 51 |
17 files changed, 1834 insertions, 0 deletions
diff --git a/inc/class-wp-bootstrap-navwalker.php b/inc/class-wp-bootstrap-navwalker.php new file mode 100644 index 0000000..a343fcc --- /dev/null +++ b/inc/class-wp-bootstrap-navwalker.php @@ -0,0 +1,559 @@ +<?php +/** + * WP Bootstrap Navwalker + * + * @package WP-Bootstrap-Navwalker + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/* + * Class Name: WP_Bootstrap_Navwalker + * Plugin Name: WP Bootstrap Navwalker + * Plugin URI: https://github.com/wp-bootstrap/wp-bootstrap-navwalker + * Description: A custom WordPress nav walker class to implement the Bootstrap 4 navigation style in a custom theme using the WordPress built in menu manager. + * Author: Edward McIntyre - @twittem, WP Bootstrap, William Patton - @pattonwebz + * Version: 4.1.0 + * Author URI: https://github.com/wp-bootstrap + * GitHub Plugin URI: https://github.com/wp-bootstrap/wp-bootstrap-navwalker + * GitHub Branch: master + * License: GPL-3.0+ + * License URI: http://www.gnu.org/licenses/gpl-3.0.txt +*/ + +/* Check if Class Exists. */ +if ( ! class_exists( 'Understrap_WP_Bootstrap_Navwalker' ) ) { + /** + * WP_Bootstrap_Navwalker class. + * + * @extends Walker_Nav_Menu + */ + class Understrap_WP_Bootstrap_Navwalker extends Walker_Nav_Menu { + + /** + * Starts the list before the elements are added. + * + * @since WP 3.0.0 + * + * @see Walker_Nav_Menu::start_lvl() + * + * @param string $output Used to append additional content (passed by reference). + * @param int $depth Depth of menu item. Used for padding. + * @param stdClass $args An object of wp_nav_menu() arguments. + */ + public function start_lvl( &$output, $depth = 0, $args = array() ) { + if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) { + $t = ''; + $n = ''; + } else { + $t = "\t"; + $n = "\n"; + } + $indent = str_repeat( $t, $depth ); + // Default class to add to the file. + $classes = array( 'dropdown-menu' ); + /** + * Filters the CSS class(es) applied to a menu list element. + * + * @since WP 4.8.0 + * + * @param array $classes The CSS classes that are applied to the menu `<ul>` element. + * @param stdClass $args An object of `wp_nav_menu()` arguments. + * @param int $depth Depth of menu item. Used for padding. + */ + $class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) ); + $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : ''; + /** + * The `.dropdown-menu` container needs to have a labelledby + * attribute which points to it's trigger link. + * + * Form a string for the labelledby attribute from the the latest + * link with an id that was added to the $output. + */ + $labelledby = ''; + // find all links with an id in the output. + preg_match_all( '/(<a.*?id=\"|\')(.*?)\"|\'.*?>/im', $output, $matches ); + // with pointer at end of array check if we got an ID match. + if ( end( $matches[2] ) ) { + // build a string to use as aria-labelledby. + $labelledby = 'aria-labelledby="' . end( $matches[2] ) . '"'; + } + $output .= "{$n}{$indent}<ul$class_names $labelledby role=\"menu\">{$n}"; + } + + /** + * Starts the element output. + * + * @since WP 3.0.0 + * @since WP 4.4.0 The {@see 'nav_menu_item_args'} filter was added. + * + * @see Walker_Nav_Menu::start_el() + * + * @param string $output Used to append additional content (passed by reference). + * @param WP_Post $item Menu item data object. + * @param int $depth Depth of menu item. Used for padding. + * @param stdClass $args An object of wp_nav_menu() arguments. + * @param int $id Current item ID. + */ + public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) { + if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) { + $t = ''; + $n = ''; + } else { + $t = "\t"; + $n = "\n"; + } + $indent = ( $depth ) ? str_repeat( $t, $depth ) : ''; + + $classes = empty( $item->classes ) ? array() : (array) $item->classes; + + // Initialize some holder variables to store specially handled item + // wrappers and icons. + $linkmod_classes = array(); + $icon_classes = array(); + + /** + * Get an updated $classes array without linkmod or icon classes. + * + * NOTE: linkmod and icon class arrays are passed by reference and + * are maybe modified before being used later in this function. + */ + $classes = self::seporate_linkmods_and_icons_from_classes( $classes, $linkmod_classes, $icon_classes, $depth ); + + // Join any icon classes plucked from $classes into a string. + $icon_class_string = join( ' ', $icon_classes ); + + /** + * Filters the arguments for a single nav menu item. + * + * WP 4.4.0 + * + * @param stdClass $args An object of wp_nav_menu() arguments. + * @param WP_Post $item Menu item data object. + * @param int $depth Depth of menu item. Used for padding. + */ + $args = apply_filters( 'nav_menu_item_args', $args, $item, $depth ); + + // Add .dropdown or .active classes where they are needed. + if ( isset( $args->has_children ) && $args->has_children ) { + $classes[] = 'dropdown'; + } + if ( in_array( 'current-menu-item', $classes, true ) || in_array( 'current-menu-parent', $classes, true ) ) { + $classes[] = 'active'; + } + + // Add some additional default classes to the item. + $classes[] = 'menu-item-' . $item->ID; + $classes[] = 'nav-item'; + + // Allow filtering the classes. + $classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ); + + // Form a string of classes in format: class="class_names". + $class_names = join( ' ', $classes ); + $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : ''; + + /** + * Filters the ID applied to a menu item's list item element. + * + * @since WP 3.0.1 + * @since WP 4.1.0 The `$depth` parameter was added. + * + * @param string $menu_id The ID that is applied to the menu item's `<li>` element. + * @param WP_Post $item The current menu item. + * @param stdClass $args An object of wp_nav_menu() arguments. + * @param int $depth Depth of menu item. Used for padding. + */ + $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth ); + $id = $id ? ' id="' . esc_attr( $id ) . '"' : ''; + + $output .= $indent . '<li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement"' . $id . $class_names . '>'; + + // initialize array for holding the $atts for the link item. + $atts = array(); + + // Set title from item to the $atts array - if title is empty then + // default to item title. + if ( empty( $item->attr_title ) ) { + $atts['title'] = ! empty( $item->title ) ? strip_tags( $item->title ) : ''; + } else { + $atts['title'] = $item->attr_title; + } + + $atts['target'] = ! empty( $item->target ) ? $item->target : ''; + $atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : ''; + // If item has_children add atts to <a>. + if ( isset( $args->has_children ) && $args->has_children && 0 === $depth && $args->depth > 1 ) { + $atts['href'] = '#'; + $atts['data-toggle'] = 'dropdown'; + $atts['aria-haspopup'] = 'true'; + $atts['aria-expanded'] = 'false'; + $atts['class'] = 'dropdown-toggle nav-link'; + $atts['id'] = 'menu-item-dropdown-' . $item->ID; + } else { + $atts['href'] = ! empty( $item->url ) ? $item->url : '#'; + // Items in dropdowns use .dropdown-item instead of .nav-link. + if ( $depth > 0 ) { + $atts['class'] = 'dropdown-item'; + } else { + $atts['class'] = 'nav-link'; + } + } + + // update atts of this item based on any custom linkmod classes. + $atts = self::update_atts_for_linkmod_type( $atts, $linkmod_classes ); + // Allow filtering of the $atts array before using it. + $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth ); + + // Build a string of html containing all the atts for the item. + $attributes = ''; + foreach ( $atts as $attr => $value ) { + if ( ! empty( $value ) ) { + $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value ); + $attributes .= ' ' . $attr . '="' . $value . '"'; + } + } + + /** + * Set a typeflag to easily test if this is a linkmod or not. + */ + $linkmod_type = self::get_linkmod_type( $linkmod_classes ); + + /** + * START appending the internal item contents to the output. + */ + $item_output = isset( $args->before ) ? $args->before : ''; + /** + * This is the start of the internal nav item. Depending on what + * kind of linkmod we have we may need different wrapper elements. + */ + if ( '' !== $linkmod_type ) { + // is linkmod, output the required element opener. + $item_output .= self::linkmod_element_open( $linkmod_type, $attributes ); + } else { + // With no link mod type set this must be a standard <a> tag. + $item_output .= '<a' . $attributes . '>'; + } + + /** + * Initiate empty icon var, then if we have a string containing any + * icon classes form the icon markup with an <i> element. This is + * output inside of the item before the $title (the link text). + */ + $icon_html = ''; + if ( ! empty( $icon_class_string ) ) { + // append an <i> with the icon classes to what is output before links. + $icon_html = '<i class="' . esc_attr( $icon_class_string ) . '" aria-hidden="true"></i> '; + } + + /** This filter is documented in wp-includes/post-template.php */ + $title = apply_filters( 'the_title', $item->title, $item->ID ); + + /** + * Filters a menu item's title. + * + * @since WP 4.4.0 + * + * @param string $title The menu item's title. + * @param WP_Post $item The current menu item. + * @param stdClass $args An object of wp_nav_menu() arguments. + * @param int $depth Depth of menu item. Used for padding. + */ + $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth ); + + /** + * If the .sr-only class was set apply to the nav items text only. + */ + if ( in_array( 'sr-only', $linkmod_classes, true ) ) { + $title = self::wrap_for_screen_reader( $title ); + $keys_to_unset = array_keys( $linkmod_classes, 'sr-only' ); + foreach ( $keys_to_unset as $k ) { + unset( $linkmod_classes[ $k ] ); + } + } + + // Put the item contents into $output. + $item_output .= isset( $args->link_before ) ? $args->link_before . $icon_html . $title . $args->link_after : ''; + /** + * This is the end of the internal nav item. We need to close the + * correct element depending on the type of link or link mod. + */ + if ( '' !== $linkmod_type ) { + // is linkmod, output the required element opener. + $item_output .= self::linkmod_element_close( $linkmod_type, $attributes ); + } else { + // With no link mod type set this must be a standard <a> tag. + $item_output .= '</a>'; + } + + $item_output .= isset( $args->after ) ? $args->after : ''; + + /** + * END appending the internal item contents to the output. + */ + $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); + + } + + /** + * Traverse elements to create list from elements. + * + * Display one element if the element doesn't have any children otherwise, + * display the element and its children. Will only traverse up to the max + * depth and no ignore elements under that depth. It is possible to set the + * max depth to include all depths, see walk() method. + * + * This method should not be called directly, use the walk() method instead. + * + * @since WP 2.5.0 + * + * @see Walker::start_lvl() + * + * @param object $element Data object. + * @param array $children_elements List of elements to continue traversing (passed by reference). + * @param int $max_depth Max depth to traverse. + * @param int $depth Depth of current element. + * @param array $args An array of arguments. + * @param string $output Used to append additional content (passed by reference). + */ + public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) { + if ( ! $element ) { + return; } + $id_field = $this->db_fields['id']; + // Display this element. + if ( is_object( $args[0] ) ) { + $args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] ); } + parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output ); + } + + /** + * Menu Fallback + * ============= + * If this function is assigned to the wp_nav_menu's fallback_cb variable + * and a menu has not been assigned to the theme location in the WordPress + * menu manager the function with display nothing to a non-logged in user, + * and will add a link to the WordPress menu manager if logged in as an admin. + * + * @param array $args passed from the wp_nav_menu function. + */ + public static function fallback( $args ) { + if ( current_user_can( 'edit_theme_options' ) ) { + + /* Get Arguments. */ + $container = $args['container']; + $container_id = $args['container_id']; + $container_class = $args['container_class']; + $menu_class = $args['menu_class']; + $menu_id = $args['menu_id']; + + // initialize var to store fallback html. + $fallback_output = ''; + + if ( $container ) { + $fallback_output .= '<' . esc_attr( $container ); + if ( $container_id ) { + $fallback_output .= ' id="' . esc_attr( $container_id ) . '"'; + } + if ( $container_class ) { + $fallback_output .= ' class="' . esc_attr( $container_class ) . '"'; + } + $fallback_output .= '>'; + } + $fallback_output .= '<ul'; + if ( $menu_id ) { + $fallback_output .= ' id="' . esc_attr( $menu_id ) . '"'; } + if ( $menu_class ) { + $fallback_output .= ' class="' . esc_attr( $menu_class ) . '"'; } + $fallback_output .= '>'; + $fallback_output .= '<li><a href="' . esc_url( admin_url( 'nav-menus.php' ) ) . '" title="' . esc_attr__( 'Add a menu', 'understrap' ) . '">' . esc_html__( 'Add a menu', 'understrap' ) . '</a></li>'; + $fallback_output .= '</ul>'; + if ( $container ) { + $fallback_output .= '</' . esc_attr( $container ) . '>'; + } + + // if $args has 'echo' key and it's true echo, otherwise return. + if ( array_key_exists( 'echo', $args ) && $args['echo'] ) { + echo $fallback_output; // WPCS: XSS OK. + } else { + return $fallback_output; + } + } + } + + /** + * Find any custom linkmod or icon classes and store in their holder + * arrays then remove them from the main classes array. + * + * Supported linkmods: .disabled, .dropdown-header, .dropdown-divider, .sr-only + * Supported iconsets: Font Awesome 4/5, Glypicons + * + * NOTE: This accepts the linkmod and icon arrays by reference. + * + * @since 4.0.0 + * + * @param array $classes an array of classes currently assigned to the item. + * @param array $linkmod_classes an array to hold linkmod classes. + * @param array $icon_classes an array to hold icon classes. + * @param integer $depth an integer holding current depth level. + * + * @return array $classes a maybe modified array of classnames. + */ + private function seporate_linkmods_and_icons_from_classes( $classes, &$linkmod_classes, &$icon_classes, $depth ) { + // Loop through $classes array to find linkmod or icon classes. + foreach ( $classes as $key => $class ) { + // If any special classes are found, store the class in it's + // holder array and and unset the item from $classes. + if ( preg_match( '/^disabled|^sr-only/i', $class ) ) { + // Test for .disabled or .sr-only classes. + $linkmod_classes[] = $class; + unset( $classes[ $key ] ); + } elseif ( preg_match( '/^dropdown-header|^dropdown-divider|^dropdown-item-text/i', $class ) && $depth > 0 ) { + // Test for .dropdown-header or .dropdown-divider and a + // depth greater than 0 - IE inside a dropdown. + $linkmod_classes[] = $class; + unset( $classes[ $key ] ); + } elseif ( preg_match( '/^fa-(\S*)?|^fa(s|r|l|b)?(\s?)?$/i', $class ) ) { + // Font Awesome. + $icon_classes[] = $class; + unset( $classes[ $key ] ); + } elseif ( preg_match( '/^glyphicon-(\S*)?|^glyphicon(\s?)$/i', $class ) ) { + // Glyphicons. + $icon_classes[] = $class; + unset( $classes[ $key ] ); + } + } + + return $classes; + } + + /** + * Return a string containing a linkmod type and update $atts array + * accordingly depending on the decided. + * + * @since 4.0.0 + * + * @param array $linkmod_classes array of any link modifier classes. + * + * @return string empty for default, a linkmod type string otherwise. + */ + private function get_linkmod_type( $linkmod_classes = array() ) { + $linkmod_type = ''; + // Loop through array of linkmod classes to handle their $atts. + if ( ! empty( $linkmod_classes ) ) { + foreach ( $linkmod_classes as $link_class ) { + if ( ! empty( $link_class ) ) { + + // check for special class types and set a flag for them. + if ( 'dropdown-header' === $link_class ) { + $linkmod_type = 'dropdown-header'; + } elseif ( 'dropdown-divider' === $link_class ) { + $linkmod_type = 'dropdown-divider'; + } elseif ( 'dropdown-item-text' === $link_class ) { + $linkmod_type = 'dropdown-item-text'; + } + } + } + } + return $linkmod_type; + } + + /** + * Update the attributes of a nav item depending on the limkmod classes. + * + * @since 4.0.0 + * + * @param array $atts array of atts for the current link in nav item. + * @param array $linkmod_classes an array of classes that modify link or nav item behaviors or displays. + * + * @return array maybe updated array of attributes for item. + */ + private function update_atts_for_linkmod_type( $atts = array(), $linkmod_classes = array() ) { + if ( ! empty( $linkmod_classes ) ) { + foreach ( $linkmod_classes as $link_class ) { + if ( ! empty( $link_class ) ) { + // update $atts with a space and the extra classname... + // so long as it's not a sr-only class. + if ( 'sr-only' !== $link_class ) { + $atts['class'] .= ' ' . esc_attr( $link_class ); + } + // check for special class types we need additional handling for. + if ( 'disabled' === $link_class ) { + // Convert link to '#' and unset open targets. + $atts['href'] = '#'; + unset( $atts['target'] ); + } elseif ( 'dropdown-header' === $link_class || 'dropdown-divider' === $link_class || 'dropdown-item-text' === $link_class ) { + // Store a type flag and unset href and target. + unset( $atts['href'] ); + unset( $atts['target'] ); + } + } + } + } + return $atts; + } + + /** + * Wraps the passed text in a screen reader only class. + * + * @since 4.0.0 + * + * @param string $text the string of text to be wrapped in a screen reader class. + * @return string the string wrapped in a span with the class. + */ + private function wrap_for_screen_reader( $text = '' ) { + if ( $text ) { + $text = '<span class="sr-only">' . $text . '</span>'; + } + return $text; + } + + /** + * Returns the correct opening element and attributes for a linkmod. + * + * @since 4.0.0 + * + * @param string $linkmod_type a sting containing a linkmod type flag. + * @param string $attributes a string of attributes to add to the element. + * + * @return string a string with the openign tag for the element with attribibutes added. + */ + private function linkmod_element_open( $linkmod_type, $attributes = '' ) { + $output = ''; + if ( 'dropdown-item-text' === $linkmod_type ) { + $output .= '<span class="dropdown-item-text"' . $attributes . '>'; + } elseif ( 'dropdown-header' === $linkmod_type ) { + // For a header use a span with the .h6 class instead of a real + // header tag so that it doesn't confuse screen readers. + $output .= '<span class="dropdown-header h6"' . $attributes . '>'; + } elseif ( 'dropdown-divider' === $linkmod_type ) { + // this is a divider. + $output .= '<div class="dropdown-divider"' . $attributes . '>'; + } + return $output; + } + + /** + * Return the correct closing tag for the linkmod element. + * + * @since 4.0.0 + * + * @param string $linkmod_type a string containing a special linkmod type. + * + * @return string a string with the closing tag for this linkmod type. + */ + private function linkmod_element_close( $linkmod_type ) { + $output = ''; + if ( 'dropdown-header' === $linkmod_type || 'dropdown-item-text' === $linkmod_type ) { + // For a header use a span with the .h6 class instead of a real + // header tag so that it doesn't confuse screen readers. + $output .= '</span>'; + } elseif ( 'dropdown-divider' === $linkmod_type ) { + // this is a divider. + $output .= '</div>'; + } + return $output; + } + } +} diff --git a/inc/custom-comments.php b/inc/custom-comments.php new file mode 100644 index 0000000..c4aa7c7 --- /dev/null +++ b/inc/custom-comments.php @@ -0,0 +1,71 @@ +<?php +/** + * Comment layout. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +// Comments form. +add_filter( 'comment_form_default_fields', 'understrap_bootstrap_comment_form_fields' ); + +/** + * Creates the comments form. + * + * @param string $fields Form fields. + * + * @return array + */ + +if ( ! function_exists( 'understrap_bootstrap_comment_form_fields' ) ) { + + function understrap_bootstrap_comment_form_fields( $fields ) { + $commenter = wp_get_current_commenter(); + $req = get_option( 'require_name_email' ); + $aria_req = ( $req ? " aria-required='true'" : '' ); + $html5 = current_theme_supports( 'html5', 'comment-form' ) ? 1 : 0; + $consent = empty( $commenter['comment_author_email'] ) ? '' : ' checked="checked"'; + $fields = array( + 'author' => '<div class="form-group comment-form-author textfield-box"><label for="author">' . __( 'Name', + 'understrap' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' . + '<input class="form-control" id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . '></div>', + 'email' => '<div class="form-group comment-form-email textfield-box"><label for="email">' . __( 'E-Mail', + 'understrap' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' . + '<input class="form-control" id="email" name="email" ' . ( $html5 ? 'type="email"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . '></div>', + 'url' => '<div class="form-group comment-form-url textfield-box"><label for="url">' . __( 'Webseite', + 'understrap' ) . '</label> ' . + '<input class="form-control" id="url" name="url" ' . ( $html5 ? 'type="url"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30"></div>', + 'cookies' => '<div class="form-group form-check comment-form-cookies-consent"><input class="form-check-input" id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"' . $consent . ' /> ' . + '<label class="form-check-label" for="wp-comment-cookies-consent">' . __( 'Save my name, email, and website in this browser for the next time I comment', 'understrap' ) . '</label></div>', + ); + + return $fields; + } +} // endif function_exists( 'understrap_bootstrap_comment_form_fields' ) + +add_filter( 'comment_form_defaults', 'understrap_bootstrap_comment_form' ); + +/** + * Builds the form. + * + * @param string $args Arguments for form's fields. + * + * @return mixed + */ + +if ( ! function_exists( 'understrap_bootstrap_comment_form' ) ) { + + function understrap_bootstrap_comment_form( $args ) { + $args['comment_field'] = '<div class="form-group comment-form-comment"> + <div class="textfield-box"> + <label for="comment">' . _x( 'Kommentar', 'noun', 'understrap' ) . ( ' <span class="required">*</span>' ) . '</label> + <textarea class="form-control" id="comment" name="comment" aria-required="true" cols="45" rows="8"></textarea> + </div> + </div>'; + $args['class_submit'] = 'btn btn-secondary'; // since WP 4.1. + return $args; + } +} // endif function_exists( 'understrap_bootstrap_comment_form' ) diff --git a/inc/custom-header.php b/inc/custom-header.php new file mode 100644 index 0000000..b66a416 --- /dev/null +++ b/inc/custom-header.php @@ -0,0 +1,49 @@ +<?php +/** + * Custom header setup. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +add_action( 'after_setup_theme', 'understrap_custom_header_setup' ); + +if ( ! function_exists ( 'understrap_custom_header_setup' ) ) { + function understrap_custom_header_setup() { + + /** + * Filter UnderStrap custom-header support arguments. + * + * @since UnderStrap 0.5.2 + * + * @param array $args { + * An array of custom-header support arguments. + * + * @type string $default-image Default image of the header. + * @type string $default_text_color Default color of the header text. + * @type int $width Width in pixels of the custom header image. Default 954. + * @type int $height Height in pixels of the custom header image. Default 1300. + * @type string $wp-head-callback Callback function used to styles the header image and text + * displayed on the blog. + * @type string $flex-height Flex support for height of header. + * } + */ + add_theme_support( 'custom-header', apply_filters( 'understrap_custom_header_args', array( + 'default-image' => get_parent_theme_file_uri( '/img/header.jpg' ), + 'width' => 2000, + 'height' => 1200, + 'flex-height' => true, + ) ) ); + + register_default_headers( array( + 'default-image' => array( + 'url' => '%s/img/header.jpg', + 'thumbnail_url' => '%s/img/header.jpg', + 'description' => __( 'Default Header Image', 'understrap' ), + ), + ) ); + } +}
\ No newline at end of file diff --git a/inc/customizer.php b/inc/customizer.php new file mode 100644 index 0000000..6729d77 --- /dev/null +++ b/inc/customizer.php @@ -0,0 +1,135 @@ +<?php +/** + * Understrap Theme Customizer + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/** + * Add postMessage support for site title and description for the Theme Customizer. + * + * @param WP_Customize_Manager $wp_customize Theme Customizer object. + */ +if ( ! function_exists( 'understrap_customize_register' ) ) { + /** + * Register basic customizer support. + * + * @param object $wp_customize Customizer reference. + */ + function understrap_customize_register( $wp_customize ) { + $wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; + $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; + $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage'; + } +} +add_action( 'customize_register', 'understrap_customize_register' ); + +if ( ! function_exists( 'understrap_theme_customize_register' ) ) { + /** + * Register individual settings through customizer's API. + * + * @param WP_Customize_Manager $wp_customize Customizer reference. + */ + function understrap_theme_customize_register( $wp_customize ) { + + // Theme layout settings. + $wp_customize->add_section( 'understrap_theme_layout_options', array( + 'title' => __( 'Theme Layout Settings', 'understrap' ), + 'capability' => 'edit_theme_options', + 'description' => __( 'Container width and sidebar defaults', 'understrap' ), + 'priority' => 160, + ) ); + + /** + * Select sanitization function + * + * @param string $input Slug to sanitize. + * @param WP_Customize_Setting $setting Setting instance. + * @return string Sanitized slug if it is a valid choice; otherwise, the setting default. + */ + function understrap_theme_slug_sanitize_select( $input, $setting ){ + + // Ensure input is a slug (lowercase alphanumeric characters, dashes and underscores are allowed only). + $input = sanitize_key( $input ); + + // Get the list of possible select options. + $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 ); + + } + + $wp_customize->add_setting( 'understrap_container_type', array( + 'default' => 'container', + 'type' => 'theme_mod', + 'sanitize_callback' => 'understrap_theme_slug_sanitize_select', + 'capability' => 'edit_theme_options', + ) ); + + $wp_customize->add_control( + new WP_Customize_Control( + $wp_customize, + 'understrap_container_type', array( + 'label' => __( 'Container Width', 'understrap' ), + 'description' => __( 'Choose between Bootstrap\'s container and container-fluid', 'understrap' ), + 'section' => 'understrap_theme_layout_options', + 'settings' => 'understrap_container_type', + 'type' => 'select', + 'choices' => array( + 'container' => __( 'Fixed width container', 'understrap' ), + 'container-fluid' => __( 'Full width container', 'understrap' ), + ), + 'priority' => '10', + ) + ) ); + + $wp_customize->add_setting( 'understrap_sidebar_position', array( + 'default' => 'right', + 'type' => 'theme_mod', + 'sanitize_callback' => 'sanitize_text_field', + 'capability' => 'edit_theme_options', + ) ); + + $wp_customize->add_control( + new WP_Customize_Control( + $wp_customize, + 'understrap_sidebar_position', array( + 'label' => __( 'Sidebar Positioning', 'understrap' ), + 'description' => __( 'Set sidebar\'s default position. Can either be: right, left, both or none. Note: this can be overridden on individual pages.', + 'understrap' ), + 'section' => 'understrap_theme_layout_options', + 'settings' => 'understrap_sidebar_position', + 'type' => 'select', + 'sanitize_callback' => 'understrap_theme_slug_sanitize_select', + 'choices' => array( + 'right' => __( 'Right sidebar', 'understrap' ), + 'left' => __( 'Left sidebar', 'understrap' ), + 'both' => __( 'Left & Right sidebars', 'understrap' ), + 'none' => __( 'No sidebar', 'understrap' ), + ), + 'priority' => '20', + ) + ) ); + } +} // endif function_exists( 'understrap_theme_customize_register' ). +add_action( 'customize_register', 'understrap_theme_customize_register' ); + +/** + * Binds JS handlers to make Theme Customizer preview reload changes asynchronously. + */ +if ( ! function_exists( 'understrap_customize_preview_js' ) ) { + /** + * Setup JS integration for live previewing. + */ + function understrap_customize_preview_js() { + wp_enqueue_script( 'understrap_customizer', get_template_directory_uri() . '/js/customizer.js', + array( 'customize-preview' ), '20130508', true + ); + } +} +add_action( 'customize_preview_init', 'understrap_customize_preview_js' ); diff --git a/inc/editor.php b/inc/editor.php new file mode 100644 index 0000000..4b71ee9 --- /dev/null +++ b/inc/editor.php @@ -0,0 +1,78 @@ +<?php +/** + * Understrap modify editor + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/** + * Registers an editor stylesheet for the theme. + */ + +add_action( 'admin_init', 'understrap_wpdocs_theme_add_editor_styles' ); + +if ( ! function_exists ( 'understrap_wpdocs_theme_add_editor_styles' ) ) { + function understrap_wpdocs_theme_add_editor_styles() { + add_editor_style( 'css/custom-editor-style.min.css' ); + } +} + +// Add TinyMCE style formats. +add_filter( 'mce_buttons_2', 'understrap_tiny_mce_style_formats' ); + +if ( ! function_exists ( 'understrap_tiny_mce_style_formats' ) ) { + function understrap_tiny_mce_style_formats( $styles ) { + + array_unshift( $styles, 'styleselect' ); + return $styles; + } +} + + +add_filter( 'tiny_mce_before_init', 'understrap_tiny_mce_before_init' ); + +if ( ! function_exists ( 'understrap_tiny_mce_before_init' ) ) { + function understrap_tiny_mce_before_init( $settings ) { + + $style_formats = array( + array( + 'title' => 'Lead Paragraph', + 'selector' => 'p', + 'classes' => 'lead', + 'wrapper' => true + ), + array( + 'title' => 'Small', + 'inline' => 'small' + ), + array( + 'title' => 'Blockquote', + 'block' => 'blockquote', + 'classes' => 'blockquote', + 'wrapper' => true + ), + array( + 'title' => 'Blockquote Footer', + 'block' => 'footer', + 'classes' => 'blockquote-footer', + 'wrapper' => true + ), + array( + 'title' => 'Cite', + 'inline' => 'cite' + ) + ); + + if ( isset( $settings['style_formats'] ) ) { + $orig_style_formats = json_decode($settings['style_formats'],true); + $style_formats = array_merge($orig_style_formats,$style_formats); + } + + $settings['style_formats'] = json_encode( $style_formats ); + return $settings; + } +} diff --git a/inc/enqueue.php b/inc/enqueue.php new file mode 100644 index 0000000..a51937f --- /dev/null +++ b/inc/enqueue.php @@ -0,0 +1,34 @@ +<?php +/** + * Understrap enqueue scripts + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +if ( ! function_exists( 'understrap_scripts' ) ) { + /** + * Load theme's JavaScript and CSS sources. + */ + function understrap_scripts() { + // Get the theme data. + $the_theme = wp_get_theme(); + $theme_version = $the_theme->get( 'Version' ); + + $css_version = $theme_version . '.' . filemtime(get_template_directory() . '/css/theme.css'); + wp_enqueue_style( 'theme-styles', get_stylesheet_directory_uri() . '/css/theme.css', array(), $css_version ); + + wp_enqueue_script( 'jquery'); + + $js_version = $theme_version . '.' . filemtime(get_template_directory() . '/js/theme.min.js'); + wp_enqueue_script( 'theme-scripts', get_template_directory_uri() . '/js/theme.min.js', array(), $js_version, true ); + if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { + wp_enqueue_script( 'comment-reply' ); + } + } +} // endif function_exists( 'understrap_scripts' ). + +add_action( 'wp_enqueue_scripts', 'understrap_scripts' ); diff --git a/inc/extras.php b/inc/extras.php new file mode 100644 index 0000000..94f7485 --- /dev/null +++ b/inc/extras.php @@ -0,0 +1,114 @@ +<?php +/** + * Custom functions that act independently of the theme templates. + * + * Eventually, some of the functionality here could be replaced by core features. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +add_filter( 'body_class', 'understrap_body_classes' ); + +if ( ! function_exists( 'understrap_body_classes' ) ) { + /** + * Adds custom classes to the array of body classes. + * + * @param array $classes Classes for the body element. + * + * @return array + */ + function understrap_body_classes( $classes ) { + // Adds a class of group-blog to blogs with more than 1 published author. + if ( is_multi_author() ) { + $classes[] = 'group-blog'; + } + // Adds a class of hfeed to non-singular pages. + if ( ! is_singular() ) { + $classes[] = 'hfeed'; + } + + return $classes; + } +} + +// Removes tag class from the body_class array to avoid Bootstrap markup styling issues. +add_filter( 'body_class', 'understrap_adjust_body_class' ); + +if ( ! function_exists( 'understrap_adjust_body_class' ) ) { + /** + * Setup body classes. + * + * @param string $classes CSS classes. + * + * @return mixed + */ + function understrap_adjust_body_class( $classes ) { + + foreach ( $classes as $key => $value ) { + if ( 'tag' == $value ) { + unset( $classes[ $key ] ); + } + } + + return $classes; + + } +} + +// Filter custom logo with correct classes. +add_filter( 'get_custom_logo', 'understrap_change_logo_class' ); + +if ( ! function_exists( 'understrap_change_logo_class' ) ) { + /** + * Replaces logo CSS class. + * + * @param string $html Markup. + * + * @return mixed + */ + function understrap_change_logo_class( $html ) { + + $html = str_replace( 'class="custom-logo"', 'class="img-fluid"', $html ); + $html = str_replace( 'class="custom-logo-link"', 'class="navbar-brand custom-logo-link"', $html ); + $html = str_replace( 'alt=""', 'title="Home" alt="logo"' , $html ); + + return $html; + } +} + +/** + * Display navigation to next/previous post when applicable. + */ + +if ( ! function_exists ( 'understrap_post_nav' ) ) { + function understrap_post_nav() { + // Don't print empty markup if there's nowhere to navigate. + $previous = ( is_attachment() ) ? get_post( get_post()->post_parent ) : get_adjacent_post( false, '', true ); + $next = get_adjacent_post( false, '', false ); + + if ( ! $next && ! $previous ) { + return; + } + ?> + <nav class="container navigation post-navigation"> + <h2 class="sr-only"><?php _e( 'Post navigation', 'understrap' ); ?></h2> + <div class="row nav-links justify-content-between"> + <?php + + if ( get_previous_post_link() ) { + previous_post_link( '<span class="col nav-previous text-left">%link</span>', _x( '<i class="fa fa-angle-left"></i> %title', 'Previous post link', 'understrap' ) ); + } + if ( get_next_post_link() ) { + next_post_link( '<span class="col nav-next text-right">%link</span>', _x( '%title <i class="fa fa-angle-right"></i>', 'Next post link', 'understrap' ) ); + } + ?> + </div><!-- .nav-links --> + </nav><!-- .navigation --> + + <?php + } +} diff --git a/inc/hooks.php b/inc/hooks.php new file mode 100644 index 0000000..8cd0b8d --- /dev/null +++ b/inc/hooks.php @@ -0,0 +1,49 @@ +<?php +/** + * Custom hooks. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +if ( ! function_exists( 'understrap_site_info' ) ) { + /** + * Add site info hook to WP hook library. + */ + function understrap_site_info() { + #do_action( 'understrap_site_info' ); + } +} + +if ( ! function_exists( 'understrap_add_site_info' ) ) { + add_action( 'understrap_site_info', 'understrap_add_site_info' ); + + /** + * Add site info content. + */ + function understrap_add_site_info() { + $the_theme = wp_get_theme(); + + $site_info = sprintf( + '<a href="%1$s">%2$s</a><span class="sep"> | </span>%3$s(%4$s)', + esc_url( __( 'http://wordpress.org/', 'understrap' ) ), + sprintf( + /* translators:*/ + esc_html__( 'Proudly powered by %s', 'understrap' ), 'WordPress' + ), + sprintf( // WPCS: XSS ok. + /* translators:*/ + esc_html__( 'Theme: %1$s by %2$s.', 'understrap' ), $the_theme->get( 'Name' ), '<a href="' . esc_url( __( 'http://understrap.com', 'understrap' ) ) . '">understrap.com</a>' + ), + sprintf( // WPCS: XSS ok. + /* translators:*/ + esc_html__( 'Version: %1$s', 'understrap' ), $the_theme->get( 'Version' ) + ) + ); + + echo apply_filters( 'understrap_site_info_content', $site_info ); // WPCS: XSS ok. + } +} diff --git a/inc/jetpack.php b/inc/jetpack.php new file mode 100644 index 0000000..1c2579c --- /dev/null +++ b/inc/jetpack.php @@ -0,0 +1,67 @@ +<?php +/** + * Jetpack Compatibility File + * + * @link https://jetpack.me/ + * + * @package UnderStrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/** + * Jetpack setup function. + * + * See: https://jetpack.me/support/infinite-scroll/ + * See: https://jetpack.me/support/responsive-videos/ + */ + +add_action( 'after_setup_theme', 'understrap_components_jetpack_setup' ); + +if ( ! function_exists ( 'understrap_components_jetpack_setup' ) ) { + function understrap_components_jetpack_setup() { + // Add theme support for Infinite Scroll. + add_theme_support( 'infinite-scroll', array( + 'container' => 'main', + 'render' => 'understrap_components_infinite_scroll_render', + 'footer' => 'page', + ) ); + + // Add theme support for Responsive Videos. + add_theme_support( 'jetpack-responsive-videos' ); + + // Add theme support for Social Menus + add_theme_support( 'jetpack-social-menu' ); + + } +} + + +/** + * Custom render function for Infinite Scroll. + */ + +if ( ! function_exists ( 'understrap_components_infinite_scroll_render' ) ) { + function understrap_components_infinite_scroll_render() { + while ( have_posts() ) { + the_post(); + if ( is_search() ) : + get_template_part( 'loop-templates/content', 'search' ); + else : + get_template_part( 'loop-templates/content', get_post_format() ); + endif; + } + } +} + +if ( ! function_exists ( 'understrap_components_social_menu' ) ) { + function understrap_components_social_menu() { + if ( ! function_exists( 'jetpack_social_menu' ) ) { + return; + } else { + jetpack_social_menu(); + } + } +}
\ No newline at end of file diff --git a/inc/pagination.php b/inc/pagination.php new file mode 100644 index 0000000..9a6ff79 --- /dev/null +++ b/inc/pagination.php @@ -0,0 +1,56 @@ +<?php +/** + * Pagination layout. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +if ( ! function_exists ( 'understrap_pagination' ) ) { + + function understrap_pagination( $args = array(), $class = 'pagination' ) { + + if ($GLOBALS['wp_query']->max_num_pages <= 1) return; + + $args = wp_parse_args( $args, array( + 'mid_size' => 2, + 'prev_next' => true, + 'prev_text' => __('«', 'understrap'), + 'next_text' => __('»', 'understrap'), + 'screen_reader_text' => __('Posts navigation', 'understrap'), + 'type' => 'array', + 'current' => max( 1, get_query_var('paged') ), + ) ); + + $links = paginate_links($args); + + ?> + + <nav aria-label="<?php echo $args['screen_reader_text']; ?>"> + + <ul class="pagination"> + + <?php + + foreach ( $links as $key => $link ) { ?> + + <li class="page-item <?php echo strpos( $link, 'current' ) ? 'active' : '' ?>"> + + <?php echo str_replace( 'page-numbers', 'page-link', $link ); ?> + + </li> + + <?php } ?> + + </ul> + + </nav> + + <?php + } +} + +?> diff --git a/inc/setup.php b/inc/setup.php new file mode 100644 index 0000000..5118851 --- /dev/null +++ b/inc/setup.php @@ -0,0 +1,132 @@ +<?php +/** + * Theme basic setup. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +// Set the content width based on the theme's design and stylesheet. +if ( ! isset( $content_width ) ) { + $content_width = 640; /* pixels */ +} + +add_action( 'after_setup_theme', 'understrap_setup' ); + +if ( ! function_exists ( 'understrap_setup' ) ) { + /** + * Sets up theme defaults and registers support for various WordPress features. + * + * Note that this function is hooked into the after_setup_theme hook, which + * runs before the init hook. The init hook is too late for some features, such + * as indicating support for post thumbnails. + */ + function understrap_setup() { + /* + * Make theme available for translation. + * Translations can be filed in the /languages/ directory. + * If you're building a theme based on understrap, use a find and replace + * to change 'understrap' to the name of your theme in all the template files + */ + load_theme_textdomain( 'understrap', get_template_directory() . '/languages' ); + + // Add default posts and comments RSS feed links to head. + add_theme_support( 'automatic-feed-links' ); + + /* + * Let WordPress manage the document title. + * By adding theme support, we declare that this theme does not use a + * hard-coded <title> tag in the document head, and expect WordPress to + * provide it for us. + */ + add_theme_support( 'title-tag' ); + + // This theme uses wp_nav_menu() in one location. + register_nav_menus( array( + 'primary' => __( 'Primary Menu', 'understrap' ), + ) ); + + /* + * Switch default core markup for search form, comment form, and comments + * to output valid HTML5. + */ + add_theme_support( 'html5', array( + 'search-form', + 'comment-form', + 'comment-list', + 'gallery', + 'caption', + ) ); + + /* + * Adding Thumbnail basic support + */ + add_theme_support( 'post-thumbnails' ); + + /* + * Adding support for Widget edit icons in customizer + */ + add_theme_support( 'customize-selective-refresh-widgets' ); + + /* + * Enable support for Post Formats. + * See http://codex.wordpress.org/Post_Formats + */ + add_theme_support( 'post-formats', array( + 'aside', + 'image', + 'video', + 'quote', + 'link', + ) ); + + // Set up the WordPress core custom background feature. + add_theme_support( 'custom-background', apply_filters( 'understrap_custom_background_args', array( + 'default-color' => 'ffffff', + 'default-image' => '', + ) ) ); + + // Set up the WordPress Theme logo feature. + add_theme_support( 'custom-logo' ); + + // Check and setup theme default settings. + understrap_setup_theme_default_settings(); + + } +} + + +add_filter( 'excerpt_more', 'understrap_custom_excerpt_more' ); + +if ( ! function_exists( 'understrap_custom_excerpt_more' ) ) { + /** + * Removes the ... from the excerpt read more link + * + * @param string $more The excerpt. + * + * @return string + */ + function understrap_custom_excerpt_more( $more ) { + return ''; + } +} + +add_filter( 'wp_trim_excerpt', 'understrap_all_excerpts_get_more_link' ); + +if ( ! function_exists( 'understrap_all_excerpts_get_more_link' ) ) { + /** + * Adds a custom read more link to all excerpts, manually or automatically generated + * + * @param string $post_excerpt Posts's excerpt. + * + * @return string + */ + function understrap_all_excerpts_get_more_link( $post_excerpt ) { + + return $post_excerpt . ' <p><a class="btn btn-secondary understrap-read-more-link" href="' . esc_url( get_permalink( get_the_ID() )) . '#verkostung">' . __( 'Mehr lesen...', + 'understrap' ) . '</a></p>'; + } +} diff --git a/inc/style-wpcom.css b/inc/style-wpcom.css new file mode 100644 index 0000000..0b6da17 --- /dev/null +++ b/inc/style-wpcom.css @@ -0,0 +1,7 @@ +/* + * Theme Name: Components + * + * Add any WordPress.com-specific CSS here + * + * This file is enqueued in /inc/wpcom.php + */
\ No newline at end of file diff --git a/inc/template-tags.php b/inc/template-tags.php new file mode 100644 index 0000000..8ef2eb6 --- /dev/null +++ b/inc/template-tags.php @@ -0,0 +1,137 @@ +<?php +/** + * Custom template tags for this theme. + * + * Eventually, some of the functionality here could be replaced by core features. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/** + * Prints HTML with meta information for the current post-date/time and author. + */ +if ( ! function_exists ( 'understrap_posted_on' ) ) { + function understrap_posted_on() { + $time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>'; + $time_string = sprintf( $time_string, + esc_attr( get_the_date( 'c' ) ), + esc_html( get_the_date() ) + ); + /* + $time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>'; + if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) { + $time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s"> (%4$s) </time>'; + } + $time_string = sprintf( $time_string, + esc_attr( get_the_date( 'c' ) ), + esc_html( get_the_date() ), + esc_attr( get_the_modified_date( 'c' ) ), + esc_html( get_the_modified_date() ) + ); + */ + /* + $posted_on = sprintf( + //esc_html_x( 'Posted on %s', 'post date', 'understrap' ), + esc_html_x( 'Autor:', 'post date', 'understrap' ), + '<a class="text-muted" href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>' + ); + */ + $posted_on = '<a class="text-muted" href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'; + $byline = sprintf( + esc_html_x( 'Autor: %s', 'post author', 'understrap' ), + '<span class="author vcard"><a class="text-muted url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>' + ); + echo '<span class="text-muted"><span class="byline"> ' . $byline . '</span> | <span class="posted-on">' . $posted_on . '</span> | <a class="text-muted" href="' . esc_url( get_permalink() ) . '#comments">'; comments_number("0 Kommentare", "1 Kommentar", "% Kommentare"); echo '</a></span>'; // WPCS: XSS OK. + } +} + + +/** + * Prints HTML with meta information for the categories, tags and comments. + */ +if ( ! function_exists ( 'understrap_entry_footer' ) ) { + function understrap_entry_footer() { + // Hide category and tag text for pages. + if ( 'post' === get_post_type() ) { + /* translators: used between list items, there is a space after the comma */ + $categories_list = get_the_category_list( esc_html__( ', ', 'understrap' ) ); + if ( $categories_list && understrap_categorized_blog() ) { + printf( '<span class="cat-links text-muted col-sm col-xl-6"><i class="material-icons text-muted tag-category-icon">folder</i> ' . esc_html__( '%1$s', 'understrap' ) . '</span>', $categories_list ); // WPCS: XSS OK. + } + /* translators: used between list items, there is a space after the comma */ + $tags_list = get_the_tag_list( '', esc_html__( ', ', 'understrap' ) ); + if ( $tags_list ) { + printf( '<span class="tags-links text-right-xs col-sm col-xl-6"><i class="material-icons text-muted tag-category-icon">label</i>' . esc_html__( '%1$s', 'understrap' ) . '</span>', $tags_list ); // WPCS: XSS OK. + } + } + /* + if ( ! is_single() && ! post_password_required() && ( comments_open() || get_comments_number() ) ) { + echo '<span class="comments-link">'; + comments_popup_link( esc_html__( 'Leave a comment', 'understrap' ), esc_html__( '1 Comment', 'understrap' ), esc_html__( '% Comments', 'understrap' ) ); + echo '</span>'; + } + */ + # /* translators: %s: Name of current post */ + /* + edit_post_link( + sprintf( + esc_html__( 'Edit %s', 'understrap' ), + the_title( '<span class="screen-reader-text">"', '"</span>', false ) + ), + '<span class="edit-link">', + '</span>' + ); + */ + } +} + + +/** + * Returns true if a blog has more than 1 category. + * + * @return bool + */ +if ( ! function_exists ( 'understrap_categorized_blog' ) ) { + function understrap_categorized_blog() { + if ( false === ( $all_the_cool_cats = get_transient( 'understrap_categories' ) ) ) { + // Create an array of all the categories that are attached to posts. + $all_the_cool_cats = get_categories( array( + 'fields' => 'ids', + 'hide_empty' => 1, + // We only need to know if there is more than one category. + 'number' => 2, + ) ); + // Count the number of categories that are attached to the posts. + $all_the_cool_cats = count( $all_the_cool_cats ); + set_transient( 'understrap_categories', $all_the_cool_cats ); + } + if ( $all_the_cool_cats > 1 ) { + // This blog has more than 1 category so components_categorized_blog should return true. + return true; + } else { + // This blog has only 1 category so components_categorized_blog should return false. + return false; + } + } +} + + +/** + * Flush out the transients used in understrap_categorized_blog. + */ +add_action( 'edit_category', 'understrap_category_transient_flusher' ); +add_action( 'save_post', 'understrap_category_transient_flusher' ); + +if ( ! function_exists ( 'understrap_category_transient_flusher' ) ) { + function understrap_category_transient_flusher() { + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { + return; + } + // Like, beat it. Dig? + delete_transient( 'understrap_categories' ); + } +} diff --git a/inc/theme-settings.php b/inc/theme-settings.php new file mode 100755 index 0000000..9bee616 --- /dev/null +++ b/inc/theme-settings.php @@ -0,0 +1,36 @@ +<?php +/** + * Check and setup theme's default settings + * + * @package understrap + * + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +if ( ! function_exists ( 'understrap_setup_theme_default_settings' ) ) { + function understrap_setup_theme_default_settings() { + + // check if settings are set, if not set defaults. + // Caution: DO NOT check existence using === always check with == . + // Latest blog posts style. + $understrap_posts_index_style = get_theme_mod( 'understrap_posts_index_style' ); + if ( '' == $understrap_posts_index_style ) { + set_theme_mod( 'understrap_posts_index_style', 'default' ); + } + + // Sidebar position. + $understrap_sidebar_position = get_theme_mod( 'understrap_sidebar_position' ); + if ( '' == $understrap_sidebar_position ) { + set_theme_mod( 'understrap_sidebar_position', 'right' ); + } + + // Container width. + $understrap_container_type = get_theme_mod( 'understrap_container_type' ); + if ( '' == $understrap_container_type ) { + set_theme_mod( 'understrap_container_type', 'container' ); + } + } +}
\ No newline at end of file diff --git a/inc/widgets.php b/inc/widgets.php new file mode 100644 index 0000000..fdd6611 --- /dev/null +++ b/inc/widgets.php @@ -0,0 +1,119 @@ +<?php +/** + * Declaring widgets + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/** + * Count number of widgets in a sidebar + * Used to add classes to widget areas so widgets can be displayed one, two, three or four per row + */ +if ( ! function_exists( 'understrap_slbd_count_widgets' ) ) { + function understrap_slbd_count_widgets( $sidebar_id ) { + // If loading from front page, consult $_wp_sidebars_widgets rather than options + // to see if wp_convert_widget_settings() has made manipulations in memory. + global $_wp_sidebars_widgets; + if ( empty( $_wp_sidebars_widgets ) ) : + $_wp_sidebars_widgets = get_option( 'sidebars_widgets', array() ); + endif; + + $sidebars_widgets_count = $_wp_sidebars_widgets; + + if ( isset( $sidebars_widgets_count[ $sidebar_id ] ) ) : + $widget_count = count( $sidebars_widgets_count[ $sidebar_id ] ); + $widget_classes = 'widget-count-' . count( $sidebars_widgets_count[ $sidebar_id ] ); + if ( $widget_count % 4 == 0 || $widget_count > 6 ) : + // Four widgets per row if there are exactly four or more than six + $widget_classes .= ' col-md-3'; + elseif ( 6 == $widget_count ) : + // If two widgets are published + $widget_classes .= ' col-md-2'; + elseif ( $widget_count >= 3 ) : + // Three widgets per row if there's three or more widgets + $widget_classes .= ' col-md-4'; + elseif ( 2 == $widget_count ) : + // If two widgets are published + $widget_classes .= ' col-md-6'; + elseif ( 1 == $widget_count ) : + // If just on widget is active + $widget_classes .= ' col-md-12'; + endif; + return $widget_classes; + endif; + } +} + +add_action( 'widgets_init', 'understrap_widgets_init' ); + +if ( ! function_exists( 'understrap_widgets_init' ) ) { + /** + * Initializes themes widgets. + */ + function understrap_widgets_init() { + register_sidebar( array( + 'name' => __( 'Right Sidebar', 'understrap' ), + 'id' => 'right-sidebar', + 'description' => __( 'Right sidebar widget area', 'understrap' ), + 'before_widget' => '<aside id="%1$s" class="widget %2$s">', + 'after_widget' => '</aside>', + 'before_title' => '<h3 class="widget-title">', + 'after_title' => '</h3>', + ) ); + + register_sidebar( array( + 'name' => __( 'Left Sidebar', 'understrap' ), + 'id' => 'left-sidebar', + 'description' => __( 'Left sidebar widget area', 'understrap' ), + 'before_widget' => '<aside id="%1$s" class="widget %2$s">', + 'after_widget' => '</aside>', + 'before_title' => '<h3 class="widget-title">', + 'after_title' => '</h3>', + ) ); + + register_sidebar( array( + 'name' => __( 'Hero Slider', 'understrap' ), + 'id' => 'hero', + 'description' => __( 'Hero slider area. Place two or more widgets here and they will slide!', 'understrap' ), + 'before_widget' => '<div class="carousel-item">', + 'after_widget' => '</div>', + 'before_title' => '', + 'after_title' => '', + ) ); + + register_sidebar( array( + 'name' => __( 'Hero Canvas', 'understrap' ), + 'id' => 'herocanvas', + 'description' => __( 'Full size canvas hero area for Bootstrap and other custom HTML markup', 'understrap' ), + 'before_widget' => '', + 'after_widget' => '', + 'before_title' => '', + 'after_title' => '', + ) ); + + register_sidebar( array( + 'name' => __( 'Top Full', 'understrap' ), + 'id' => 'statichero', + 'description' => __( 'Full top widget with dynamic grid', 'understrap' ), + 'before_widget' => '<div id="%1$s" class="static-hero-widget %2$s '. understrap_slbd_count_widgets( 'statichero' ) .'">', + 'after_widget' => '</div><!-- .static-hero-widget -->', + 'before_title' => '<h3 class="widget-title">', + 'after_title' => '</h3>', + ) ); + + register_sidebar( array( + 'name' => __( 'Footer Full', 'understrap' ), + 'id' => 'footerfull', + 'description' => __( 'Full sized footer widget with dynamic grid', 'understrap' ), + 'before_widget' => '<div id="%1$s" class="footer-widget %2$s '. understrap_slbd_count_widgets( 'footerfull' ) .'">', + 'after_widget' => '</div><!-- .footer-widget -->', + 'before_title' => '<h3 class="widget-title">', + 'after_title' => '</h3>', + ) ); + + } +} // endif function_exists( 'understrap_widgets_init' ). diff --git a/inc/woocommerce.php b/inc/woocommerce.php new file mode 100644 index 0000000..3cd8e9b --- /dev/null +++ b/inc/woocommerce.php @@ -0,0 +1,140 @@ +<?php +/** + * Add WooCommerce support + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +add_action( 'after_setup_theme', 'understrap_woocommerce_support' ); +if ( ! function_exists( 'understrap_woocommerce_support' ) ) { + /** + * Declares WooCommerce theme support. + */ + function understrap_woocommerce_support() { + add_theme_support( 'woocommerce' ); + + // Add New Woocommerce 3.0.0 Product Gallery support + add_theme_support( 'wc-product-gallery-lightbox' ); + add_theme_support( 'wc-product-gallery-zoom' ); + add_theme_support( 'wc-product-gallery-slider' ); + + // hook in and customizer form fields. + add_filter( 'woocommerce_form_field_args', 'understrap_wc_form_field_args', 10, 3 ); + } +} + +/** +* First unhook the WooCommerce wrappers +*/ +remove_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10); +remove_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10); + +/** +* Then hook in your own functions to display the wrappers your theme requires +*/ +add_action('woocommerce_before_main_content', 'understrap_woocommerce_wrapper_start', 10); +add_action('woocommerce_after_main_content', 'understrap_woocommerce_wrapper_end', 10); +if ( ! function_exists( 'understrap_woocommerce_wrapper_start' ) ) { + function understrap_woocommerce_wrapper_start() { + $container = get_theme_mod( 'understrap_container_type' ); + echo '<div class="wrapper" id="woocommerce-wrapper">'; + echo '<div class="' . esc_attr( $container ) . '" id="content" tabindex="-1">'; + echo '<div class="row">'; + get_template_part( 'global-templates/left-sidebar-check' ); + echo '<main class="site-main" id="main">'; + } +} +if ( ! function_exists( 'understrap_woocommerce_wrapper_end' ) ) { +function understrap_woocommerce_wrapper_end() { + echo '</main><!-- #main -->'; + get_template_part( 'global-templates/right-sidebar-check' ); + echo '</div><!-- .row -->'; + echo '</div><!-- Container end -->'; + echo '</div><!-- Wrapper end -->'; + } +} + + +/** + * Filter hook function monkey patching form classes + * Author: Adriano Monecchi http://stackoverflow.com/a/36724593/307826 + * + * @param string $args Form attributes. + * @param string $key Not in use. + * @param null $value Not in use. + * + * @return mixed + */ +if ( ! function_exists ( 'understrap_wc_form_field_args' ) ) { + function understrap_wc_form_field_args( $args, $key, $value = null ) { + // Start field type switch case. + switch ( $args['type'] ) { + /* Targets all select input type elements, except the country and state select input types */ + case 'select' : + // Add a class to the field's html element wrapper - woocommerce + // input types (fields) are often wrapped within a <p></p> tag. + $args['class'][] = 'form-group'; + // Add a class to the form input itself. + $args['input_class'] = array( 'form-control', 'input-lg' ); + $args['label_class'] = array( 'control-label' ); + $args['custom_attributes'] = array( + 'data-plugin' => 'select2', + 'data-allow-clear' => 'true', + 'aria-hidden' => 'true', + // Add custom data attributes to the form input itself. + ); + break; + // By default WooCommerce will populate a select with the country names - $args + // defined for this specific input type targets only the country select element. + case 'country' : + $args['class'][] = 'form-group single-country'; + $args['label_class'] = array( 'control-label' ); + break; + // By default WooCommerce will populate a select with state names - $args defined + // for this specific input type targets only the country select element. + case 'state' : + // Add class to the field's html element wrapper. + $args['class'][] = 'form-group'; + // add class to the form input itself. + $args['input_class'] = array( '', 'input-lg' ); + $args['label_class'] = array( 'control-label' ); + $args['custom_attributes'] = array( + 'data-plugin' => 'select2', + 'data-allow-clear' => 'true', + 'aria-hidden' => 'true', + ); + break; + case 'password' : + case 'text' : + case 'email' : + case 'tel' : + case 'number' : + $args['class'][] = 'form-group'; + $args['input_class'] = array( 'form-control', 'input-lg' ); + $args['label_class'] = array( 'control-label' ); + break; + case 'textarea' : + $args['input_class'] = array( 'form-control', 'input-lg' ); + $args['label_class'] = array( 'control-label' ); + break; + case 'checkbox' : + $args['label_class'] = array( 'custom-control custom-checkbox' ); + $args['input_class'] = array( 'custom-control-input', 'input-lg' ); + break; + case 'radio' : + $args['label_class'] = array( 'custom-control custom-radio' ); + $args['input_class'] = array( 'custom-control-input', 'input-lg' ); + break; + default : + $args['class'][] = 'form-group'; + $args['input_class'] = array( 'form-control', 'input-lg' ); + $args['label_class'] = array( 'control-label' ); + break; + } // end switch ($args). + return $args; + } +}
\ No newline at end of file diff --git a/inc/wpcom.php b/inc/wpcom.php new file mode 100644 index 0000000..ca42c38 --- /dev/null +++ b/inc/wpcom.php @@ -0,0 +1,51 @@ +<?php +/** + * WordPress.com-specific functions and definitions + * + * This file is centrally included from `wp-content/mu-plugins/wpcom-theme-compat.php`. + * + * @package understrap + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly. +} + +/** + * Adds support for wp.com-specific theme functions. + * + * @global array $themecolors + */ +add_action( 'after_setup_theme', 'understrap_wpcom_setup' ); + +if ( ! function_exists ( 'understrap_wpcom_setup' ) ) { + function understrap_wpcom_setup() { + global $themecolors; + + // Set theme colors for third party services. + if ( ! isset( $themecolors ) ) { + $themecolors = array( + 'bg' => '', + 'border' => '', + 'text' => '', + 'link' => '', + 'url' => '', + ); + } + + /* Add WP.com print styles */ + add_theme_support( 'print-styles' ); + } +} + + +/* + * WordPress.com-specific styles + */ +add_action( 'wp_enqueue_scripts', 'understrap_wpcom_styles' ); + +if ( ! function_exists ( 'understrap_wpcom_styles' ) ) { + function understrap_wpcom_styles() { + wp_enqueue_style( 'understrap-wpcom', get_template_directory_uri() . '/inc/style-wpcom.css', '20160411' ); + } +}
\ No newline at end of file |
