I have some setup code in my functions.php file that sets permalinks and adds categories that are used by the theme. I only want this code to run when the theme is first activated. There is no need for the code to run again. However, by placing it in the functions.php file, it runs each and every time a page on the website is loaded.
Is there an alternative method to use so that this code only runs when the custom theme is first activated?
In wp-includes/theme.php you’ll find the function switch_theme(). It offers an action hook:
/**
* Switches current theme to new template and stylesheet names.
*
* #since unknown
* #uses do_action() Calls 'switch_theme' action on updated theme display name.
*
* #param string $template Template name
* #param string $stylesheet Stylesheet name.
*/
function switch_theme($template, $stylesheet) {
update_option('template', $template);
update_option('stylesheet', $stylesheet);
delete_option('current_theme');
$theme = get_current_theme();
do_action('switch_theme', $theme);
}
So you may use this in your functions.php:
function my_activation_settings($theme)
{
if ( 'Your Theme Name' == $theme )
{
// do something
}
return;
}
add_action('switch_theme', 'my_activation_settings');
Just an idea; I haven’t tested it.
Another one to look at would be after_switch_theme it is also in wp-includes/theme.php
It seems to be a hook run in check_theme_switched
/**
* Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load
*
* #since 3.3.0
*/
function check_theme_switched() {
if ( $stylesheet = get_option( 'theme_switched' ) ) {
$old_theme = wp_get_theme( $stylesheet );
// Prevent retrieve_widgets() from running since Customizer already called it up front
if ( get_option( 'theme_switched_via_customizer' ) ) {
remove_action( 'after_switch_theme', '_wp_sidebars_changed' );
update_option( 'theme_switched_via_customizer', false );
}
if ( $old_theme->exists() ) {
/**
* Fires on the first WP load after a theme switch if the old theme still exists.
*
* This action fires multiple times and the parameters differs
* according to the context, if the old theme exists or not.
* If the old theme is missing, the parameter will be the slug
* of the old theme.
*
* #since 3.3.0
*
* #param string $old_name Old theme name.
* #param WP_Theme $old_theme WP_Theme instance of the old theme.
*/
do_action( 'after_switch_theme', $old_theme->get( 'Name' ), $old_theme );
} else {
/** This action is documented in wp-includes/theme.php */
do_action( 'after_switch_theme', $stylesheet );
}
flush_rewrite_rules();
update_option( 'theme_switched', false );
}
}`
add_action('after_switch_theme', 'my_activation_settings');
I think both ways work just something else to look into :)
Related
How can i get languages into my custom plugin of wordpress?
When i call pll_the_languages() it's output me error.
Maybe i should call some global method?
My plugin code:
/**
* woocommerce-admin-ajax
*
* #package woocommerce-admin-ajax
* #author Sergey Samokhvalov
* #wordpress-plugin
*
* Plugin Name: WooCommerce Admin Ajax
* Plugin URI: https://redirex.studio
* Description: Additional functionality for ajax update of product in admin page without reload page.
* Version: 1.0
* Requires PHP: 5.6.20
* Author: Sergey Samokhvalov
* Author URI: https://github.com/RedirexStudio/woocommerce-admin-ajax
* Text Domain: Woocommerce Admin Ajax
*/
/* Registrate admin js and styles */
add_action( 'admin_enqueue_scripts', 'reg_amin_js' );
function reg_amin_js( $page ) {
// change to the $page where you want to enqueue the script
if( $page == 'post-new.php' || $page == 'post.php' || $page == 'edit.php' ) {
// Enqueue WordPress media scripts
wp_enqueue_media();
// Enqueue custom script that will interact with wp.media
wp_enqueue_script( 'woocommerce_admin-scripts', plugins_url('/admin/js/admin.js',__FILE__ ), array('jquery') );
// Enqueue custom styles for admin panel
wp_enqueue_style('woocommerce_admin-styles', plugins_url('/admin/css/style.css', __FILE__ ));
}
}
/* //END//Registrate admin js and styles */
/* Polylang capability */
pll_the_languages();
/* //END//Polylang capability */
My issue is solved.
You should use admin_init action:
function plugin_pll_register_string() {
if ( function_exists( 'pll_register_string' ) ) {
pll_register_string('woocommerce-admin-ajax-strings', 'Update');
pll_register_string('woocommerce-admin-ajax-strings', 'Published');
pll_register_string('woocommerce-admin-ajax-strings', 'Product is updated!');
}
}
add_action( 'admin_init', 'plugin_pll_register_string' );
I am trying to overwrite the <title> tag of a page using a Wordpress plugin.
I don't want to change the theme's code. I just wanna force the theme to change some page titles via the plugin.
The theme uses add_theme_support( 'title-tag' ). Note that the use of wp_title is now deprecated.
Your problem is that you can not use wp_title() in the theme if the theme already supports title-tag. The <head> of your theme should look like this:
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<?php wp_head(); ?>
</head>
The filter and title-tag support:
add_action( 'after_setup_theme', 'my_theme_functions' );
function my_theme_functions() {
add_theme_support( 'title-tag' );
}
add_filter( 'wp_title', 'custom_titles', 10, 2 );
function custom_titles( $title, $sep ) {
//set custom title here
$title = "Some other title" . $title;;
return $title;
}
If you do this, it will work perfectly.
I posted this answer for another question but since it is relevant and more up-to-date, I though it might be useful for some people.
How document title is generated has changed since Wordpress v4.4.0. Now wp_get_document_title dictates how title is generated:
/**
* Displays title tag with content.
*
* #ignore
* #since 4.1.0
* #since 4.4.0 Improved title output replaced `wp_title()`.
* #access private
*/
function _wp_render_title_tag() {
if ( ! current_theme_supports( 'title-tag' ) ) {
return;
}
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}
Here is the code from v5.4.2. Here are the filters you can use to manipulate title tag:
function wp_get_document_title() {
/**
* Filters the document title before it is generated.
*
* Passing a non-empty value will short-circuit wp_get_document_title(),
* returning that value instead.
*
* #since 4.4.0
*
* #param string $title The document title. Default empty string.
*/
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
return $title;
}
// --- snipped ---
/**
* Filters the separator for the document title.
*
* #since 4.4.0
*
* #param string $sep Document title separator. Default '-'.
*/
$sep = apply_filters( 'document_title_separator', '-' );
/**
* Filters the parts of the document title.
*
* #since 4.4.0
*
* #param array $title {
* The document title parts.
*
* #type string $title Title of the viewed page.
* #type string $page Optional. Page number if paginated.
* #type string $tagline Optional. Site description when on home page.
* #type string $site Optional. Site title when not on home page.
* }
*/
$title = apply_filters( 'document_title_parts', $title );
// --- snipped ---
return $title;
}
So here are two ways you can do it.
First one uses pre_get_document_title filter which short-circuits the title generation and hence more performant if you are not going make changes on current title:
function custom_document_title( $title ) {
return 'Here is the new title';
}
add_filter( 'pre_get_document_title', 'custom_document_title', 10 );
Second way uses document_title_separator and document_title_parts hooks for the title and the title seperator that are executed later in the function, after title is generated using functions like single_term_title or post_type_archive_title depending on the page and about to be outputted:
// Custom function should return a string
function custom_seperator( $sep ) {
return '>';
}
add_filter( 'document_title_separator', 'custom_seperator', 10 );
// Custom function should return an array
function custom_html_title( $title ) {
return array(
'title' => 'Custom Title',
'site' => 'Custom Site'
);
}
add_filter( 'document_title_parts', 'custom_html_title', 10 );
Context: WordPress 5.4.5, Yoast 3.7.1
I'm a plugin developer who has access to the client's site. The site has Yoast 3.7.1 installed and I'm wondering if that is significant because no matter what I do I can't change the 404 page's title.
Now on other pages on StackOverflow where similar questions have been posed (here, here and here for example), those answering have asked if the header.php is correctly embedding a call to wp_title(). Here's what's in the current theme's header.php at that point:
<title><?php wp_title( '|', true, 'right' ); ?></title>
Interestingly, in my 404.php page, wp_get_document_title() tells me that the document title is Page not found - XXXX even though the wp_title call above specifies the separator as |. Yoast's rewriting of titles has been disabled so I'm not at all sure where that dash is coming from.
My plugin does a REST call and pulls in content from off-site for inclusion in the page. Part of that content is the text to be used in the title.
On previous client sites, I've been able to do the following:
add_filter('wp_title', 'change_404_title');
function change_404_title($title) {
if (is_404())
{
global $plugin_title;
if (!empty($plugin_title))
{
$title = $plugin_title;
}
}
return $title;
}
However, on this site, that's not working.
I have tried, based on the version of WordPress being used, hooking the pre_get_document_title filter, viz
add_filter('pre_get_document_title', 'change_404_title');
but again to no avail. I am currently reading up on Yoast ...
wp_title deprecated since version 4.4. So we should use the new filter pre_get_document_title. Your code looks fine but I am confused about global $plugin_title. I would rather ask you to Try this first
add_filter('pre_get_document_title', 'change_404_title');
function change_404_title($title) {
if (is_404()) {
return 'My Custom Title';
}
return $title;
}
If it doesn't work then try changing the priority to execute your function lately.
add_filter('pre_get_document_title', 'change_404_title', 50);
How document title is generated has changed since Wordpress v4.4.0. Now wp_get_document_title dictates how title is generated:
/**
* Displays title tag with content.
*
* #ignore
* #since 4.1.0
* #since 4.4.0 Improved title output replaced `wp_title()`.
* #access private
*/
function _wp_render_title_tag() {
if ( ! current_theme_supports( 'title-tag' ) ) {
return;
}
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}
Here is the code from v5.4.2. These are the filters you can use to manipulate title tag:
function wp_get_document_title() {
/**
* Filters the document title before it is generated.
*
* Passing a non-empty value will short-circuit wp_get_document_title(),
* returning that value instead.
*
* #since 4.4.0
*
* #param string $title The document title. Default empty string.
*/
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
return $title;
}
// --- snipped ---
/**
* Filters the separator for the document title.
*
* #since 4.4.0
*
* #param string $sep Document title separator. Default '-'.
*/
$sep = apply_filters( 'document_title_separator', '-' );
/**
* Filters the parts of the document title.
*
* #since 4.4.0
*
* #param array $title {
* The document title parts.
*
* #type string $title Title of the viewed page.
* #type string $page Optional. Page number if paginated.
* #type string $tagline Optional. Site description when on home page.
* #type string $site Optional. Site title when not on home page.
* }
*/
$title = apply_filters( 'document_title_parts', $title );
// --- snipped ---
return $title;
}
So here are two ways you can do it.
First one uses pre_get_document_title filter which short-circuits the title generation and hence more performant if you are not going make changes on current title:
function custom_document_title( $title ) {
return 'Here is the new title';
}
add_filter( 'pre_get_document_title', 'custom_document_title', 10 );
Second way uses document_title_separator and document_title_parts hooks for the title and the title seperator that are executed later in the function, after title is generated using functions like single_term_title or post_type_archive_title depending on the page, and just before the title tags is about to be outputted:
// Custom function should return a string
function custom_seperator( $sep ) {
return '>';
}
add_filter( 'document_title_separator', 'custom_seperator', 10 );
// Custom function should return an array
function custom_html_title( $title ) {
return array(
'title' => 'Custom Title',
'site' => 'Custom Site'
);
}
add_filter( 'document_title_parts', 'custom_html_title', 10 );
Add this to your functions.php
function custom_wp_title($title) {
if ( is_404() ) {
$title = 'Custom 404 Title';
}
return $title;
}
add_filter( 'wp_title', 'custom_wp_title', 10, 2 );
10 - is priority change to overwrite other plugins like SEO
I've created a custom product type in woocommerce called Booking.
Here is the code that I have:
class WC_Product_Booking extends WC_Product{
/**
* __construct function.
*
* #access public
* #param mixed $product
*/
public function __construct( $product ) {
$this->product_type = 'booking';
$this->supports[] = 'ajax_add_to_cart';
parent::__construct( $product );
add_action('woocommerce_booking_add_to_cart', array($this, 'add_to_cart'),30);
}
private function show_pricing_fields(){
?><script type='text/javascript'>
jQuery( document ).ready( function() {
jQuery( '.options_group.pricing' ).addClass( 'show_if_booking' ).show();
});
</script><?php
}
/**
* Display the add to cart button (same as for simple product)
*/
public function add_to_cart() {
wc_get_template( 'single-product/add-to-cart/simple.php' );
}
}
Right now the only problem is that the add to cart section on the product page is displayed 6 times andI cant figure out why.
How can I solve this issue?
Thanks
#Update … Solution (as LoicTheAztec put me on the right track):
I've found a solution to this problem, using this code
if (! function_exists( 'woocommerce_booking_add_to_cart' ) ) {
/**
* Output the simple product add to cart area.
*
* #subpackage Product
*/
function booking_add_to_cart() {
wc_get_template( 'single-product/add-to-cart/simple.php' );
}
add_action('woocommerce_booking_add_to_cart', 'booking_add_to_cart');
}
The crucial part is this action add_action('woocommerce_booking_add_to_cart', 'booking_add_to_cart');
Which puts the add to cart button once in the right place - to use it in your own custom product make an action called woocommerce_YOURPRODUCTTYPE_add_to_cart
Tried to test your code on a test server, but your booking product was not showing on backend.
Your issue could come from here: I think you are using with public function add_to_cart() an existing name function, and you have to rename-it differently.
Then I have revisited your code, based on this thread.
It's may be better to extend WC_Product_Simple class rather than WC_Product class, since your product uses simple product add-to-cart button template: single-product/add-to-cart/simple.php.
With this custom code I don't face like you Multiple add to cart sections.
— #Update1 —
But you can still keep WC_Product extended instead of WC_Product_Simple. This way, as you requested in comment, your product type will be "simple_booking" as specified in 1st and 2nd functions. That does not mean that your product is simple (it's just a slug that you can change, changing at the same time in both places).
So I have modified the code again and tested: It works…
This is the code I use (and I have tested):
/**
* Register the custom product type after init
*/
function register_simple_booking_product_type() {
/**
* This should be in its own separate file.
*/
class WC_Product_Booking extends WC_Product{ // <= changed back to WC_product class
public function __construct( $product ) {
$this->product_type = 'simple_booking';
$this->supports[] = 'ajax_add_to_cart';
parent::__construct( $product );
// As we extend simple product class, you may not need this anymore.
add_action('woocommerce_booking_add_to_cart', array($this, 'simple_booking_add_to_cart'),30);
}
}
}
add_action( 'init', 'register_simple_booking_product_type' );
// Registering the slug name (YOU can CHANGE IT)
function add_simple_booking_product( $types ){
// Key should be exactly the same as in the class product_type parameter
$types[ 'simple_booking' ] = __( 'Simple booking' );
return $types;
}
add_filter( 'product_type_selector', 'add_simple_booking_product' );
/**
* Show pricing fields for simple_booking product.
*/
function simple_booking_custom_js() {
if ( 'product' != get_post_type() ) :
return;
endif;
?><script type='text/javascript'>
jQuery( document ).ready( function() {
jQuery( '.options_group.pricing' ).addClass( 'show_if_simple_booking' ).show();
});
</script><?php
}
add_action( 'admin_footer', 'simple_booking_custom_js' );
// Not sure you will need that (because of the change of the extended class)
function simple_booking_add_to_cart() {
wc_get_template( 'single-product/add-to-cart/simple.php' );
}
Tested this code on function.php file located in active child theme (or theme).
Reference: Adding a custom WooCommerce product type
— #Update2 — The solution (find by the author of this question):
To puts the add-to-cart button once in the right place (to use it in your own custom product make an action called woocommerce_YOURPRODUCTTYPE_add_to_cart), with this code:
if (! function_exists( 'woocommerce_booking_add_to_cart' ) ) {
/**
* Output the simple product add to cart area.
*
* #subpackage Product
*/
function booking_add_to_cart() {
wc_get_template( 'single-product/add-to-cart/simple.php' );
}
add_action('woocommerce_booking_add_to_cart', 'booking_add_to_cart');
}
What is the difference between filter and hooks in wordpress.
How can i use the following filter in child theme ?
<?php
foreach ( $results as $result ) {
// external plugins can modify or disable field
$result = apply_filters( 'cp_package_field', $result, 'ad' );
if ( ! $result )
continue;
?>
how can i use the following hook in child theme ?
/**
* called in cp_add_new_listing() to hook into inserting new ad process
*
* #since 3.2.1
* #param int $post_id
*
*/
function cp_action_add_new_listing( $post_id ) {
do_action( 'cp_action_add_new_listing', $post_id );
}
For the first part of your question, here is a link to an explanation I found a while back that was pretty comprehensive and it helped me to understand the difference.
https://wordpress.stackexchange.com/questions/1007/difference-between-filter-and-action-hooks
To use the hook in your child theme, you'd probably need to have the following piece of code in your child theme's functions.php file:
/**
* Our callback function to the hook
* #param int $post_id id of the post
* #return void
*/
function my_child_theme_new_listing_cb( $post_id ) {
if($post_id == 10) { //Or whatever you want
echo 'Hello World';
}
//We do not have the responsibility to return something as it is a hook
}
add_action( 'cp_action_add_new_listing', 'my_child_theme_new_listing_cb', 10, 1 );
Hope it helps.