This function adds a tab named "Special Page" into "My Account" tab list:
add_filter( 'woocommerce_account_menu_items' , 'jc_menu_panel_nav' );
function jc_menu_panel_nav() {
$items = array(
'dashboard' => __( 'Dashboard', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ),
'downloads' => __( 'Downloads', 'woocommerce' ),
'edit-address' => __( 'Addresses', 'woocommerce' ),
'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
'edit-account' => __( 'Account Details', 'woocommerce' ),
'special-page' => __( 'Special Page', 'woocommerce' ), // My custom tab here
'customer-logout' => __( 'Logout', 'woocommerce' ),
);
return $items;
}
That results in this:
But the link points to my-account/special-page/, and naturally gives a 404 error.
How I can assign this URL to a file named special-page.php?
Finally I could solve the problem using a snippet provided for the same people of WooCommerce (There are more tips in that page). For anyone interested, paste all the following code in functions.php:
function my_custom_endpoints() {
add_rewrite_endpoint( 'special-page', EP_ROOT | EP_PAGES );
}
add_action( 'init', 'my_custom_endpoints' );
function my_custom_query_vars( $vars ) {
$vars[] = 'special-page';
return $vars;
}
add_filter( 'query_vars', 'my_custom_query_vars', 0 );
function my_custom_flush_rewrite_rules() {
flush_rewrite_rules();
}
add_action( 'wp_loaded', 'my_custom_flush_rewrite_rules' );
I think this way allows more control to order/renaming the menu:
function my_custom_my_account_menu_items( $items ) {
$items = array(
'dashboard' => __( 'Dashboard', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ),
//'downloads' => __( 'Downloads', 'woocommerce' ),
//'edit-address' => __( 'Addresses', 'woocommerce' ),
//'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
'edit-account' => __( 'Edit Account', 'woocommerce' ),
'special-page' => 'Special Page',
'customer-logout' => __( 'Logout', 'woocommerce' ),
);
return $items;
}
add_filter( 'woocommerce_account_menu_items', 'my_custom_my_account_menu_items' );
In the following function I included the file to maintain some "order", but it also admits direct code.
Be sure to place the special-page.php file in the myaccount folder.
function my_custom_endpoint_content() {
include 'woocommerce/myaccount/special-page.php';
}
add_action( 'woocommerce_account_special-page_endpoint', 'my_custom_endpoint_content' );
Important: Once did this, go to Dashboard > Settings > Permalinks and click "Save Settings" in order to flush rewrite rules (thanks #optimiertes)
Source: Tabbed My Account page
First my-account/special-page/ should be myaccount/special-page/ in woocommerce 2.6+.
This solution is Incomplete and I am still working On…
You can use first this hook:
add_action( 'init', 'add_wc_endpoint' );
function add_wc_endpoint(){
add_rewrite_endpoint( 'special-page', EP_ROOT | EP_PAGES );
}
Then filtering wc_get_templateto call your files when the request match your endpoint:
add_filter( 'wc_get_template', 'custom_vc_endpoint', 10, 5 );
function custom_vc_endpoint($located, $template_name, $args, $template_path, $default_path){
if( $template_name == 'myaccount/special-page.php' ){
global $wp_query;
if(isset($wp_query->query['special-page'])){
$located = get_template_directory() . '/woocommerce/myaccount/special-page.php';
}
}
return $located;
}
If you use a child theme, replace get_template_directory() by get_stylesheet_directory()… Paste this code in function.php file of your active child theme or theme.
To avoid a 404 error "page not found", you will need to refresh rewrite rules adding to your code:
flush_rewrite_rules();
Update: Finally Dario (the OP) found a working solution. Look at his answer.
References:
Tabbed My Account page (Official Woocommerce 2.6+): Creating new endpoints
How to add a new endpoint in woocommerce (old and incomplete)
There is a better way to use a template in your custom page in woocommerce:
function my_custom_endpoint_content() {
wc_get_template( 'myaccount/special-page.php' );
}
add_action( 'woocommerce_account_special-page_endpoint', 'my_custom_endpoint_content' );
this should work without using the wc_get_template filter.
You can add this code to your theme's function.php:
class My_Custom_My_Account_Endpoint {
/**
* Custom endpoint name.
*
* #var string
*/
public static $endpoint = 'special-page';
/**
* Plugin actions.
*/
public function __construct() {
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'add_endpoints' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Change the My Accout page title.
add_filter( 'the_title', array( $this, 'endpoint_title' ) );
// Insering your new tab/page into the My Account page.
add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
add_action( 'woocommerce_account_' . self::$endpoint . '_endpoint', array( $this, 'endpoint_content' ) );
}
/**
* Register new endpoint to use inside My Account page.
*
* #see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
*/
public function add_endpoints() {
add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
* Add new query var.
*
* #param array $vars
* #return array
*/
public function add_query_vars( $vars ) {
$vars[] = self::$endpoint;
return $vars;
}
/**
* Set endpoint title.
*
* #param string $title
* #return string
*/
public function endpoint_title( $title ) {
global $wp_query;
$is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
// New page title.
$title = __( 'Special Page', 'woocommerce' );
remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
}
return $title;
}
/**
* Insert the new endpoint into the My Account menu.
*
* #param array $items
* #return array
*/
public function new_menu_items( $items ) {
// Remove the logout menu item.
$logout = $items['customer-logout'];
unset( $items['customer-logout'] );
// Insert your custom endpoint.
$items[ self::$endpoint ] = __( 'Special Page', 'woocommerce' );
// Insert back the logout item.
$items['customer-logout'] = $logout;
return $items;
}
/**
* Endpoint HTML content.
*/
public function endpoint_content() {
include('woocommerce/myaccount/special-page.php');
}
/**
* Plugin install action.
* Flush rewrite rules to make our custom endpoint available.
*/
public static function install() {
flush_rewrite_rules();
}
}
new My_Custom_My_Account_Endpoint();
// Flush rewrite rules on plugin activation.
register_activation_hook( __FILE__, array( 'My_Custom_My_Account_Endpoint', 'install' ) );
If you don't know where is your theme's function.php:
1.Log in to the WordPress Admin interface
2.In the left sidebar, hover over Appearances, then click Theme Editor
3.In the right sidebar, click functions.php
I have a wordpress site using the 2017 Theme that has sections where you can embed one of your other pages. The Header Image size for my Blog page is HUGE, but when I go to the Blog page it is truncated by the theme to a nice banner. So on the home page section, you have to scroll through the huge image.
I'd like to show the truncated size in the section on the home page. How do I (I assume) modify the theme to do this?
When I inspect the element, it is
<div class="panel-image" style="background-image: url(image_url);">
<div class="panel-image-prop" style="padding-top: 100%"></div>
</div>
FYI, the theme Functions.php is below.
<?php
/**
* Twenty Seventeen functions and definitions
*
* #link https://developer.wordpress.org/themes/basics/theme-functions/
*
* #package WordPress
* #subpackage Twenty_Seventeen
* #since 1.0
*/
/**
* Twenty Seventeen only works in WordPress 4.7 or later.
*/
if ( version_compare( $GLOBALS['wp_version'], '4.7-alpha', '<' ) ) {
require get_template_directory() . '/inc/back-compat.php';
return;
}
/**
* 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 twentyseventeen_setup() {
/*
* Make theme available for translation.
* Translations can be filed at WordPress.org. See: https://translate.wordpress.org/projects/wp-themes/twentyseventeen
* If you're building a theme based on Twenty Seventeen, use a find and replace
* to change 'twentyseventeen' to the name of your theme in all the template files.
*/
load_theme_textdomain( 'twentyseventeen' );
// 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' );
/*
* Enable support for Post Thumbnails on posts and pages.
*
* #link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
*/
add_theme_support( 'post-thumbnails' );
add_image_size( 'twentyseventeen-featured-image', 2000, 1200, true );
add_image_size( 'twentyseventeen-thumbnail-avatar', 100, 100, true );
// Set the default content width.
$GLOBALS['content_width'] = 525;
// This theme uses wp_nav_menu() in two locations.
register_nav_menus(
array(
'top' => __( 'Top Menu', 'twentyseventeen' ),
'social' => __( 'Social Links Menu', 'twentyseventeen' ),
)
);
/*
* Switch default core markup for search form, comment form, and comments
* to output valid HTML5.
*/
add_theme_support(
'html5',
array(
'comment-form',
'comment-list',
'gallery',
'caption',
)
);
/*
* Enable support for Post Formats.
*
* See: https://codex.wordpress.org/Post_Formats
*/
add_theme_support(
'post-formats',
array(
'aside',
'image',
'video',
'quote',
'link',
'gallery',
'audio',
)
);
// Add theme support for Custom Logo.
add_theme_support(
'custom-logo',
array(
'width' => 250,
'height' => 250,
'flex-width' => true,
)
);
// Add theme support for selective refresh for widgets.
add_theme_support( 'customize-selective-refresh-widgets' );
/*
* This theme styles the visual editor to resemble the theme style,
* specifically font, colors, and column width.
*/
add_editor_style( array( 'assets/css/editor-style.css', twentyseventeen_fonts_url() ) );
// Load regular editor styles into the new block-based editor.
add_theme_support( 'editor-styles' );
// Load default block styles.
add_theme_support( 'wp-block-styles' );
// Add support for responsive embeds.
add_theme_support( 'responsive-embeds' );
// Define and register starter content to showcase the theme on new sites.
$starter_content = array(
'widgets' => array(
// Place three core-defined widgets in the sidebar area.
'sidebar-1' => array(
'text_business_info',
'search',
'text_about',
),
// Add the core-defined business info widget to the footer 1 area.
'sidebar-2' => array(
'text_business_info',
),
// Put two core-defined widgets in the footer 2 area.
'sidebar-3' => array(
'text_about',
'search',
),
),
// Specify the core-defined pages to create and add custom thumbnails to some of them.
'posts' => array(
'home',
'about' => array(
'thumbnail' => '{{image-sandwich}}',
),
'contact' => array(
'thumbnail' => '{{image-espresso}}',
),
'blog' => array(
'thumbnail' => '{{image-coffee}}',
),
'homepage-section' => array(
'thumbnail' => '{{image-espresso}}',
),
),
// Create the custom image attachments used as post thumbnails for pages.
'attachments' => array(
'image-espresso' => array(
'post_title' => _x( 'Espresso', 'Theme starter content', 'twentyseventeen' ),
'file' => 'assets/images/espresso.jpg', // URL relative to the template directory.
),
'image-sandwich' => array(
'post_title' => _x( 'Sandwich', 'Theme starter content', 'twentyseventeen' ),
'file' => 'assets/images/sandwich.jpg',
),
'image-coffee' => array(
'post_title' => _x( 'Coffee', 'Theme starter content', 'twentyseventeen' ),
'file' => 'assets/images/coffee.jpg',
),
),
// Default to a static front page and assign the front and posts pages.
'options' => array(
'show_on_front' => 'page',
'page_on_front' => '{{home}}',
'page_for_posts' => '{{blog}}',
),
// Set the front page section theme mods to the IDs of the core-registered pages.
'theme_mods' => array(
'panel_1' => '{{homepage-section}}',
'panel_2' => '{{about}}',
'panel_3' => '{{blog}}',
'panel_4' => '{{contact}}',
),
// Set up nav menus for each of the two areas registered in the theme.
'nav_menus' => array(
// Assign a menu to the "top" location.
'top' => array(
'name' => __( 'Top Menu', 'twentyseventeen' ),
'items' => array(
'link_home', // Note that the core "home" page is actually a link in case a static front page is not used.
'page_about',
'page_blog',
'page_contact',
),
),
// Assign a menu to the "social" location.
'social' => array(
'name' => __( 'Social Links Menu', 'twentyseventeen' ),
'items' => array(
'link_yelp',
'link_facebook',
'link_twitter',
'link_instagram',
'link_email',
),
),
),
);
/**
* Filters Twenty Seventeen array of starter content.
*
* #since Twenty Seventeen 1.1
*
* #param array $starter_content Array of starter content.
*/
$starter_content = apply_filters( 'twentyseventeen_starter_content', $starter_content );
add_theme_support( 'starter-content', $starter_content );
}
add_action( 'after_setup_theme', 'twentyseventeen_setup' );
/**
* Set the content width in pixels, based on the theme's design and stylesheet.
*
* Priority 0 to make it available to lower priority callbacks.
*
* #global int $content_width
*/
function twentyseventeen_content_width() {
$content_width = $GLOBALS['content_width'];
// Get layout.
$page_layout = get_theme_mod( 'page_layout' );
// Check if layout is one column.
if ( 'one-column' === $page_layout ) {
if ( twentyseventeen_is_frontpage() ) {
$content_width = 644;
} elseif ( is_page() ) {
$content_width = 740;
}
}
// Check if is single post and there is no sidebar.
if ( is_single() && ! is_active_sidebar( 'sidebar-1' ) ) {
$content_width = 740;
}
/**
* Filter Twenty Seventeen content width of the theme.
*
* #since Twenty Seventeen 1.0
*
* #param int $content_width Content width in pixels.
*/
$GLOBALS['content_width'] = apply_filters( 'twentyseventeen_content_width', $content_width );
}
add_action( 'template_redirect', 'twentyseventeen_content_width', 0 );
/**
* Register custom fonts.
*/
function twentyseventeen_fonts_url() {
$fonts_url = '';
/*
* Translators: If there are characters in your language that are not
* supported by Libre Franklin, translate this to 'off'. Do not translate
* into your own language.
*/
$libre_franklin = _x( 'on', 'Libre Franklin font: on or off', 'twentyseventeen' );
if ( 'off' !== $libre_franklin ) {
$font_families = array();
$font_families[] = 'Libre Franklin:300,300i,400,400i,600,600i,800,800i';
$query_args = array(
'family' => urlencode( implode( '|', $font_families ) ),
'subset' => urlencode( 'latin,latin-ext' ),
);
$fonts_url = add_query_arg( $query_args, 'https://fonts.googleapis.com/css' );
}
return esc_url_raw( $fonts_url );
}
/**
* Add preconnect for Google Fonts.
*
* #since Twenty Seventeen 1.0
*
* #param array $urls URLs to print for resource hints.
* #param string $relation_type The relation type the URLs are printed.
* #return array $urls URLs to print for resource hints.
*/
function twentyseventeen_resource_hints( $urls, $relation_type ) {
if ( wp_style_is( 'twentyseventeen-fonts', 'queue' ) && 'preconnect' === $relation_type ) {
$urls[] = array(
'href' => 'https://fonts.gstatic.com',
'crossorigin',
);
}
return $urls;
}
add_filter( 'wp_resource_hints', 'twentyseventeen_resource_hints', 10, 2 );
/**
* Register widget area.
*
* #link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
*/
function twentyseventeen_widgets_init() {
register_sidebar(
array(
'name' => __( 'Blog Sidebar', 'twentyseventeen' ),
'id' => 'sidebar-1',
'description' => __( 'Add widgets here to appear in your sidebar on blog posts and archive pages.', 'twentyseventeen' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
)
);
register_sidebar(
array(
'name' => __( 'Footer 1', 'twentyseventeen' ),
'id' => 'sidebar-2',
'description' => __( 'Add widgets here to appear in your footer.', 'twentyseventeen' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
)
);
register_sidebar(
array(
'name' => __( 'Footer 2', 'twentyseventeen' ),
'id' => 'sidebar-3',
'description' => __( 'Add widgets here to appear in your footer.', 'twentyseventeen' ),
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
)
);
}
add_action( 'widgets_init', 'twentyseventeen_widgets_init' );
/**
* Replaces "[...]" (appended to automatically generated excerpts) with ... and
* a 'Continue reading' link.
*
* #since Twenty Seventeen 1.0
*
* #param string $link Link to single post/page.
* #return string 'Continue reading' link prepended with an ellipsis.
*/
function twentyseventeen_excerpt_more( $link ) {
if ( is_admin() ) {
return $link;
}
$link = sprintf(
'<p class="link-more">%2$s</p>',
esc_url( get_permalink( get_the_ID() ) ),
/* translators: %s: Name of current post */
sprintf( __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'twentyseventeen' ), get_the_title( get_the_ID() ) )
);
return ' … ' . $link;
}
add_filter( 'excerpt_more', 'twentyseventeen_excerpt_more' );
/**
* Handles JavaScript detection.
*
* Adds a `js` class to the root `<html>` element when JavaScript is detected.
*
* #since Twenty Seventeen 1.0
*/
function twentyseventeen_javascript_detection() {
echo "<script>(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);</script>\n";
}
add_action( 'wp_head', 'twentyseventeen_javascript_detection', 0 );
/**
* Add a pingback url auto-discovery header for singularly identifiable articles.
*/
function twentyseventeen_pingback_header() {
if ( is_singular() && pings_open() ) {
printf( '<link rel="pingback" href="%s">' . "\n", esc_url( get_bloginfo( 'pingback_url' ) ) );
}
}
add_action( 'wp_head', 'twentyseventeen_pingback_header' );
/**
* Display custom color CSS.
*/
function twentyseventeen_colors_css_wrap() {
if ( 'custom' !== get_theme_mod( 'colorscheme' ) && ! is_customize_preview() ) {
return;
}
require_once( get_parent_theme_file_path( '/inc/color-patterns.php' ) );
$hue = absint( get_theme_mod( 'colorscheme_hue', 250 ) );
$customize_preview_data_hue = '';
if ( is_customize_preview() ) {
$customize_preview_data_hue = 'data-hue="' . $hue . '"';
}
?>
<style type="text/css" id="custom-theme-colors" <?php echo $customize_preview_data_hue; ?>>
<?php echo twentyseventeen_custom_colors_css(); ?>
</style>
<?php
}
add_action( 'wp_head', 'twentyseventeen_colors_css_wrap' );
/**
* Enqueues scripts and styles.
*/
function twentyseventeen_scripts() {
// Add custom fonts, used in the main stylesheet.
wp_enqueue_style( 'twentyseventeen-fonts', twentyseventeen_fonts_url(), array(), null );
// Theme stylesheet.
wp_enqueue_style( 'twentyseventeen-style', get_stylesheet_uri() );
// Theme block stylesheet.
wp_enqueue_style( 'twentyseventeen-block-style', get_theme_file_uri( '/assets/css/blocks.css' ), array( 'twentyseventeen-style' ), '1.1' );
// Load the dark colorscheme.
if ( 'dark' === get_theme_mod( 'colorscheme', 'light' ) || is_customize_preview() ) {
wp_enqueue_style( 'twentyseventeen-colors-dark', get_theme_file_uri( '/assets/css/colors-dark.css' ), array( 'twentyseventeen-style' ), '1.0' );
}
// Load the Internet Explorer 9 specific stylesheet, to fix display issues in the Customizer.
if ( is_customize_preview() ) {
wp_enqueue_style( 'twentyseventeen-ie9', get_theme_file_uri( '/assets/css/ie9.css' ), array( 'twentyseventeen-style' ), '1.0' );
wp_style_add_data( 'twentyseventeen-ie9', 'conditional', 'IE 9' );
}
// Load the Internet Explorer 8 specific stylesheet.
wp_enqueue_style( 'twentyseventeen-ie8', get_theme_file_uri( '/assets/css/ie8.css' ), array( 'twentyseventeen-style' ), '1.0' );
wp_style_add_data( 'twentyseventeen-ie8', 'conditional', 'lt IE 9' );
// Load the html5 shiv.
wp_enqueue_script( 'html5', get_theme_file_uri( '/assets/js/html5.js' ), array(), '3.7.3' );
wp_script_add_data( 'html5', 'conditional', 'lt IE 9' );
wp_enqueue_script( 'twentyseventeen-skip-link-focus-fix', get_theme_file_uri( '/assets/js/skip-link-focus-fix.js' ), array(), '1.0', true );
$twentyseventeen_l10n = array(
'quote' => twentyseventeen_get_svg( array( 'icon' => 'quote-right' ) ),
);
if ( has_nav_menu( 'top' ) ) {
wp_enqueue_script( 'twentyseventeen-navigation', get_theme_file_uri( '/assets/js/navigation.js' ), array( 'jquery' ), '1.0', true );
$twentyseventeen_l10n['expand'] = __( 'Expand child menu', 'twentyseventeen' );
$twentyseventeen_l10n['collapse'] = __( 'Collapse child menu', 'twentyseventeen' );
$twentyseventeen_l10n['icon'] = twentyseventeen_get_svg(
array(
'icon' => 'angle-down',
'fallback' => true,
)
);
}
wp_enqueue_script( 'twentyseventeen-global', get_theme_file_uri( '/assets/js/global.js' ), array( 'jquery' ), '1.0', true );
wp_enqueue_script( 'jquery-scrollto', get_theme_file_uri( '/assets/js/jquery.scrollTo.js' ), array( 'jquery' ), '2.1.2', true );
wp_localize_script( 'twentyseventeen-skip-link-focus-fix', 'twentyseventeenScreenReaderText', $twentyseventeen_l10n );
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
}
add_action( 'wp_enqueue_scripts', 'twentyseventeen_scripts' );
/**
* Enqueues styles for the block-based editor.
*
* #since Twenty Seventeen 1.8
*/
function twentyseventeen_block_editor_styles() {
// Block styles.
wp_enqueue_style( 'twentyseventeen-block-editor-style', get_theme_file_uri( '/assets/css/editor-blocks.css' ), array(), '1.1' );
// Add custom fonts.
wp_enqueue_style( 'twentyseventeen-fonts', twentyseventeen_fonts_url(), array(), null );
}
add_action( 'enqueue_block_editor_assets', 'twentyseventeen_block_editor_styles' );
/**
* Add custom image sizes attribute to enhance responsive image functionality
* for content images.
*
* #since Twenty Seventeen 1.0
*
* #param string $sizes A source size value for use in a 'sizes' attribute.
* #param array $size Image size. Accepts an array of width and height
* values in pixels (in that order).
* #return string A source size value for use in a content image 'sizes' attribute.
*/
function twentyseventeen_content_image_sizes_attr( $sizes, $size ) {
$width = $size[0];
if ( 740 <= $width ) {
$sizes = '(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px';
}
if ( is_active_sidebar( 'sidebar-1' ) || is_archive() || is_search() || is_home() || is_page() ) {
if ( ! ( is_page() && 'one-column' === get_theme_mod( 'page_options' ) ) && 767 <= $width ) {
$sizes = '(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px';
}
}
return $sizes;
}
add_filter( 'wp_calculate_image_sizes', 'twentyseventeen_content_image_sizes_attr', 10, 2 );
/**
* Filter the `sizes` value in the header image markup.
*
* #since Twenty Seventeen 1.0
*
* #param string $html The HTML image tag markup being filtered.
* #param object $header The custom header object returned by 'get_custom_header()'.
* #param array $attr Array of the attributes for the image tag.
* #return string The filtered header image HTML.
*/
function twentyseventeen_header_image_tag( $html, $header, $attr ) {
if ( isset( $attr['sizes'] ) ) {
$html = str_replace( $attr['sizes'], '100vw', $html );
}
return $html;
}
add_filter( 'get_header_image_tag', 'twentyseventeen_header_image_tag', 10, 3 );
/**
* Add custom image sizes attribute to enhance responsive image functionality
* for post thumbnails.
*
* #since Twenty Seventeen 1.0
*
* #param array $attr Attributes for the image markup.
* #param int $attachment Image attachment ID.
* #param array $size Registered image size or flat array of height and width dimensions.
* #return array The filtered attributes for the image markup.
*/
function twentyseventeen_post_thumbnail_sizes_attr( $attr, $attachment, $size ) {
if ( is_archive() || is_search() || is_home() ) {
$attr['sizes'] = '(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px';
} else {
$attr['sizes'] = '100vw';
}
return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'twentyseventeen_post_thumbnail_sizes_attr', 10, 3 );
/**
* Use front-page.php when Front page displays is set to a static page.
*
* #since Twenty Seventeen 1.0
*
* #param string $template front-page.php.
*
* #return string The template to be used: blank if is_home() is true (defaults to index.php), else $template.
*/
function twentyseventeen_front_page_template( $template ) {
return is_home() ? '' : $template;
}
add_filter( 'frontpage_template', 'twentyseventeen_front_page_template' );
/**
* Modifies tag cloud widget arguments to display all tags in the same font size
* and use list format for better accessibility.
*
* #since Twenty Seventeen 1.4
*
* #param array $args Arguments for tag cloud widget.
* #return array The filtered arguments for tag cloud widget.
*/
function twentyseventeen_widget_tag_cloud_args( $args ) {
$args['largest'] = 1;
$args['smallest'] = 1;
$args['unit'] = 'em';
$args['format'] = 'list';
return $args;
}
add_filter( 'widget_tag_cloud_args', 'twentyseventeen_widget_tag_cloud_args' );
/**
* Get unique ID.
*
* This is a PHP implementation of Underscore's uniqueId method. A static variable
* contains an integer that is incremented with each call. This number is returned
* with the optional prefix. As such the returned value is not universally unique,
* but it is unique across the life of the PHP process.
*
* #since Twenty Seventeen 2.0
* #see wp_unique_id() Themes requiring WordPress 5.0.3 and greater should use this instead.
*
* #staticvar int $id_counter
*
* #param string $prefix Prefix for the returned ID.
* #return string Unique ID.
*/
function twentyseventeen_unique_id( $prefix = '' ) {
static $id_counter = 0;
if ( function_exists( 'wp_unique_id' ) ) {
return wp_unique_id( $prefix );
}
return $prefix . (string) ++$id_counter;
}
/**
* Implement the Custom Header feature.
*/
require get_parent_theme_file_path( '/inc/custom-header.php' );
/**
* Custom template tags for this theme.
*/
require get_parent_theme_file_path( '/inc/template-tags.php' );
/**
* Additional features to allow styling of the templates.
*/
require get_parent_theme_file_path( '/inc/template-functions.php' );
/**
* Customizer additions.
*/
require get_parent_theme_file_path( '/inc/customizer.php' );
/**
* SVG icons functions and filters.
*/
require get_parent_theme_file_path( '/inc/icon-functions.php' );
Maybe this is more useful, panel template php:
<?php
/**
* Template part for displaying pages on front page
*
* #package WordPress
* #subpackage Twenty_Seventeen
* #since 1.0
* #version 1.0
*/
global $twentyseventeencounter;
?>
<article id="panel<?php echo $twentyseventeencounter; ?>" <?php post_class( 'twentyseventeen-panel ' ); ?> >
<?php
if ( has_post_thumbnail() ) :
$thumbnail = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'twentyseventeen-featured-image' );
// Calculate aspect ratio: h / w * 100%.
$ratio = $thumbnail[2] / $thumbnail[1] * 100;
?>
<div class="panel-image" style="background-image: url(<?php echo esc_url( $thumbnail[0] ); ?>);">
<div class="panel-image-prop" style="padding-top: <?php echo esc_attr( $ratio ); ?>%"></div>
</div><!-- .panel-image -->
<?php endif; ?>
<div class="panel-content">
<div class="wrap">
<header class="entry-header">
<?php the_title( '<h2 class="entry-title">', '</h2>' ); ?>
<?php twentyseventeen_edit_link( get_the_ID() ); ?>
</header><!-- .entry-header -->
<div class="entry-content">
<?php
/* translators: %s: Name of current post */
the_content(
sprintf(
__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'twentyseventeen' ),
get_the_title()
)
);
?>
</div><!-- .entry-content -->
<?php
// Show recent blog posts if is blog posts page (Note that get_option returns a string, so we're casting the result as an int).
if ( get_the_ID() === (int) get_option( 'page_for_posts' ) ) :
?>
<?php
// Show three most recent posts.
$recent_posts = new WP_Query(
array(
'posts_per_page' => 3,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
)
);
?>
<?php if ( $recent_posts->have_posts() ) : ?>
<div class="recent-posts">
<?php
while ( $recent_posts->have_posts() ) :
$recent_posts->the_post();
get_template_part( 'template-parts/post/content', 'excerpt' );
endwhile;
wp_reset_postdata();
?>
</div><!-- .recent-posts -->
<?php endif; ?>
<?php endif; ?>
</div><!-- .wrap -->
</div><!-- .panel-content -->
</article><!-- #post-<?php the_ID(); ?> -->
Pretty simple fix in CSS. Just changed:
.panel-image {
height: 100vh;
max-height: 1200px;
}
to
.panel-image {
height: 165px;
max-height: 1200px;
}
I'm creating custom elements for WPBakery.
I have a folder called vc-elements which contains two files:
hero.php
text-image.php
On the WordPress admin side, I want both elements to be visible. To do this, in functions.php I'm running:
add_action( 'vc_before_init', 'vc_before_init_actions' );
function vc_before_init_actions() {
// Link to VC elements's folder
if( function_exists('vc_set_shortcodes_templates_dir') ){
vc_set_shortcodes_templates_dir( get_template_directory() . 'vc-elements' );
}
}
But in the admin side, neither of the two blocks show?
Previously I had:
function vc_before_init_actions() {
require_once( get_template_directory().'/vc-elements/hero.php' );
}
Which showed the hero block in the admin. But when I added:
function vc_before_init_actions() {
require_once( get_template_directory().'/vc-elements/hero.php' );
require_once( get_template_directory().'/vc-elements/text-image.php' );
}
In the admin side, the hero element is replaced by the text image element - only one shows at one time. Why's this?
Are you building this with a parent or child theme? I'm not sure about your markup.
Usually, when I add a custom module I need to check if the plugin exists..
<?php
/**
* Adds new shortcode "myprefix_say_hello" and registers it to
* the Visual Composer plugin
*
*/
if ( ! class_exists( 'EZ_VC_Product_Widget' ) ) {
class EZ_VC_Product_Widget {
/**
* Main constructor
*/
public function __construct() {
// Registers the shortcode in WordPress
add_shortcode( 'ez_product', array( 'EZ_VC_Product_Widget', 'output' ) );
// Map shortcode to Visual Composer
if ( function_exists( 'vc_lean_map' ) ) {
vc_lean_map( 'ez_product', array( 'EZ_VC_Product_Widget',
'map' ) );
}
}
/**
* Shortcode output
*/
public static function output( $atts, $content = null ) {
// Extract shortcode attributes (based on the vc_lean_map function - see next function)
extract( vc_map_get_attributes( 'ez_product', $atts ) );
// Define output
$product = wc_get_product($id);
if ( $id && $product) {
global $post;
$post = $product->get_post_data();
setup_postdata( $post );
ob_start();
get_template_part('template-parts/product-module');
wp_reset_postdata();
return ob_get_clean();
}
else
return '';
}
/**
* Map shortcode to VC
*
* This is an array of all your settings which become the shortcode attributes ($atts)
* for the output. See the link below for a description of all available parameters.
*
* #since 1.0.0
* #link https://kb.wpbakery.com/docs/inner-api/vc_map/
*/
public static function map() {
return array(
'name' => esc_html__( 'EZ Product', 'shopkeeper' ),
'description' => esc_html__( 'Shortcode outputs a single product.', 'shopkeeper' ),
'base' => 'ez_product',
"icon" => get_stylesheet_directory_uri() . "/vc_extend/ez_shortcode_icon.png",
'params' => array(
array(
'type' => 'autocomplete',
'heading' => esc_html__( 'Select identificator', 'js_composer' ),
'param_name' => 'id',
'description' => esc_html__( 'Input product ID or product SKU or product title to see suggestions', 'js_composer' ),
),
array(
'type' => 'hidden',
// This will not show on render, but will be used when defining value for autocomplete
'param_name' => 'sku',
),
),
);
}
}
}
add_action('vc_before_init', function(){
new EZ_VC_Product_Widget;
});
/**
* #action wp_ajax_vc_get_autocomplete_suggestion - since 4.4 used to
hook ajax requests for autocomplete suggestions
*/
add_action( 'wp_ajax_vc_get_autocomplete_suggestion',
'ez_vc_get_autocomplete_suggestion' );
/**
* #since 4.4
*/
function ez_vc_get_autocomplete_suggestion() {
vc_user_access()->checkAdminNonce()->validateDie()->wpAny(
'edit_posts', 'edit_pages' )->validateDie();
$query = vc_post_param( 'query' );
$shortcode = wp_strip_all_tags( vc_post_param( 'shortcode' ) );
if ( $shortcode == 'ez_product') {
$tag = 'product';//wp_strip_all_tags( vc_post_param( 'shortcode'
)
);
$param_name = vc_post_param( 'param' );
vc_render_suggestion( $query, $tag, $param_name );
exit;
}
}
This function adds a tab named "Special Page" into "My Account" tab list:
add_filter( 'woocommerce_account_menu_items' , 'jc_menu_panel_nav' );
function jc_menu_panel_nav() {
$items = array(
'dashboard' => __( 'Dashboard', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ),
'downloads' => __( 'Downloads', 'woocommerce' ),
'edit-address' => __( 'Addresses', 'woocommerce' ),
'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
'edit-account' => __( 'Account Details', 'woocommerce' ),
'special-page' => __( 'Special Page', 'woocommerce' ), // My custom tab here
'customer-logout' => __( 'Logout', 'woocommerce' ),
);
return $items;
}
That results in this:
But the link points to my-account/special-page/, and naturally gives a 404 error.
How I can assign this URL to a file named special-page.php?
Finally I could solve the problem using a snippet provided for the same people of WooCommerce (There are more tips in that page). For anyone interested, paste all the following code in functions.php:
function my_custom_endpoints() {
add_rewrite_endpoint( 'special-page', EP_ROOT | EP_PAGES );
}
add_action( 'init', 'my_custom_endpoints' );
function my_custom_query_vars( $vars ) {
$vars[] = 'special-page';
return $vars;
}
add_filter( 'query_vars', 'my_custom_query_vars', 0 );
function my_custom_flush_rewrite_rules() {
flush_rewrite_rules();
}
add_action( 'wp_loaded', 'my_custom_flush_rewrite_rules' );
I think this way allows more control to order/renaming the menu:
function my_custom_my_account_menu_items( $items ) {
$items = array(
'dashboard' => __( 'Dashboard', 'woocommerce' ),
'orders' => __( 'Orders', 'woocommerce' ),
//'downloads' => __( 'Downloads', 'woocommerce' ),
//'edit-address' => __( 'Addresses', 'woocommerce' ),
//'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
'edit-account' => __( 'Edit Account', 'woocommerce' ),
'special-page' => 'Special Page',
'customer-logout' => __( 'Logout', 'woocommerce' ),
);
return $items;
}
add_filter( 'woocommerce_account_menu_items', 'my_custom_my_account_menu_items' );
In the following function I included the file to maintain some "order", but it also admits direct code.
Be sure to place the special-page.php file in the myaccount folder.
function my_custom_endpoint_content() {
include 'woocommerce/myaccount/special-page.php';
}
add_action( 'woocommerce_account_special-page_endpoint', 'my_custom_endpoint_content' );
Important: Once did this, go to Dashboard > Settings > Permalinks and click "Save Settings" in order to flush rewrite rules (thanks #optimiertes)
Source: Tabbed My Account page
First my-account/special-page/ should be myaccount/special-page/ in woocommerce 2.6+.
This solution is Incomplete and I am still working On…
You can use first this hook:
add_action( 'init', 'add_wc_endpoint' );
function add_wc_endpoint(){
add_rewrite_endpoint( 'special-page', EP_ROOT | EP_PAGES );
}
Then filtering wc_get_templateto call your files when the request match your endpoint:
add_filter( 'wc_get_template', 'custom_vc_endpoint', 10, 5 );
function custom_vc_endpoint($located, $template_name, $args, $template_path, $default_path){
if( $template_name == 'myaccount/special-page.php' ){
global $wp_query;
if(isset($wp_query->query['special-page'])){
$located = get_template_directory() . '/woocommerce/myaccount/special-page.php';
}
}
return $located;
}
If you use a child theme, replace get_template_directory() by get_stylesheet_directory()… Paste this code in function.php file of your active child theme or theme.
To avoid a 404 error "page not found", you will need to refresh rewrite rules adding to your code:
flush_rewrite_rules();
Update: Finally Dario (the OP) found a working solution. Look at his answer.
References:
Tabbed My Account page (Official Woocommerce 2.6+): Creating new endpoints
How to add a new endpoint in woocommerce (old and incomplete)
There is a better way to use a template in your custom page in woocommerce:
function my_custom_endpoint_content() {
wc_get_template( 'myaccount/special-page.php' );
}
add_action( 'woocommerce_account_special-page_endpoint', 'my_custom_endpoint_content' );
this should work without using the wc_get_template filter.
You can add this code to your theme's function.php:
class My_Custom_My_Account_Endpoint {
/**
* Custom endpoint name.
*
* #var string
*/
public static $endpoint = 'special-page';
/**
* Plugin actions.
*/
public function __construct() {
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'add_endpoints' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Change the My Accout page title.
add_filter( 'the_title', array( $this, 'endpoint_title' ) );
// Insering your new tab/page into the My Account page.
add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
add_action( 'woocommerce_account_' . self::$endpoint . '_endpoint', array( $this, 'endpoint_content' ) );
}
/**
* Register new endpoint to use inside My Account page.
*
* #see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
*/
public function add_endpoints() {
add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
* Add new query var.
*
* #param array $vars
* #return array
*/
public function add_query_vars( $vars ) {
$vars[] = self::$endpoint;
return $vars;
}
/**
* Set endpoint title.
*
* #param string $title
* #return string
*/
public function endpoint_title( $title ) {
global $wp_query;
$is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
// New page title.
$title = __( 'Special Page', 'woocommerce' );
remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
}
return $title;
}
/**
* Insert the new endpoint into the My Account menu.
*
* #param array $items
* #return array
*/
public function new_menu_items( $items ) {
// Remove the logout menu item.
$logout = $items['customer-logout'];
unset( $items['customer-logout'] );
// Insert your custom endpoint.
$items[ self::$endpoint ] = __( 'Special Page', 'woocommerce' );
// Insert back the logout item.
$items['customer-logout'] = $logout;
return $items;
}
/**
* Endpoint HTML content.
*/
public function endpoint_content() {
include('woocommerce/myaccount/special-page.php');
}
/**
* Plugin install action.
* Flush rewrite rules to make our custom endpoint available.
*/
public static function install() {
flush_rewrite_rules();
}
}
new My_Custom_My_Account_Endpoint();
// Flush rewrite rules on plugin activation.
register_activation_hook( __FILE__, array( 'My_Custom_My_Account_Endpoint', 'install' ) );
If you don't know where is your theme's function.php:
1.Log in to the WordPress Admin interface
2.In the left sidebar, hover over Appearances, then click Theme Editor
3.In the right sidebar, click functions.php