I have a Plugin installed on my WordPress site.
I'd like to override a function within the Plugin. Do I override this in my theme's functions.php and if so, how do I do this?
Here's the original function in my plugin:
/**
* sensei_start_course_form function.
*
* #access public
* #param mixed $course_id
* #return void
*/
function sensei_start_course_form( $course_id ) {
$prerequisite_complete = sensei_check_prerequisite_course( $course_id );
if ( $prerequisite_complete ) {
?><form method="POST" action="<?php echo esc_url( get_permalink() ); ?>">
<input type="hidden" name="<?php echo esc_attr( 'woothemes_sensei_start_course_noonce' ); ?>" id="<?php echo esc_attr( 'woothemes_sensei_start_course_noonce' ); ?>" value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_start_course_noonce' ) ); ?>" />
<span><input name="course_start" type="submit" class="course-start" value="<?php echo apply_filters( 'sensei_start_course_text', __( 'Start taking this Course', 'woothemes-sensei' ) ); ?>"/></span>
</form><?php
} // End If Statement
} // End sensei_start_course_form()
You can't really "override" a function. If a function is defined, you can't redefine or change it. Your best option is to create a copy of the plugin and change the function directly. Of course you will have to repeat this everytime the plugin is updated.
Give the plugin a different name to distinguish them in the plugin listing. Disable the original, enable your copy.
You can do it by using add_filter() function.
See wordpress stackexchange: Override plugin with functions.php
Just add the below code in theme's functions.php file.
add_filter('sensei_start_course_form','MyCustomfilter',$priority = 10, $args = 1);
function MyCustomfilter($course_id) {
// Do your logics here
}
I know this is late but in the event that someone else finds this post. A simpler solution is to make a copy of the function if you can to your themes functions file and rename it so that it doesn't conflict with the original function. Then use your new function in place of the original. That way you can update the plugin files without affecting your changes.
A bit late on this (november 2021) but I still found this answer today, so I'll add a solution I didn't see around:
For some historical reasons, WP still has the ability to add "must use" plugins that runs before all other plugins. So this give us the opportunity to add the function you want to override, so it already exists when the original plugin run.
In your case
add a .php file in the folder wp-content/mu-plugins
let say
wp-content/mu-plugins/custom-override.php
add your function in custom-override.php :
if ( ! function_exists( 'sensei_start_course_form' ) ) {
function sensei_start_course_form( $course_id ) {
//your magic here
//...
}
}
be sure that the original plugin also has this conditional "if function doesn't already exists..."
if ( ! function_exists( 'sensei_start_course_form' ) ) { ...
This did the trick for me ;-)
PD: I'm not an expert, please give me some feedback if this is wrong somehow. Thanks
REF: https://wordpress.org/support/article/must-use-plugins/
I also needed to change some code in a WordPress plugin. So I created a function that can be placed in functions.php in your child-theme. Please test before use! It is probably poor written since I'm no PHP expert. But the concept works for me. I tested it first outside WordPress so some variables like $root should/could be modified.
Situation was that I had to change some values in two different files in the plugin Email posts to subscribers.
I needed to change $home_url = home_url('/'); to $home_url = 'custom-redirect-url'; and 'content="10; to 'content="1; in the files optin.php and unsubscribe.php.
Every time the plugin gets updated it runs a function after the update. This is the code I use:
// Function that replaces the code
function replace_text_plugin_email_posts_to_subscribers($pluginTargetFile, $replaceURL) {
$root = $_SERVER['DOCUMENT_ROOT'];
$replaceThis = array("\$home_url = home_url('/');", "content=\"10;");
$withThis = array($replaceURL, "content=\"1;");
$fname = $root . $pluginTargetFile;
$fhandle = fopen($fname,"r");
$content = fread($fhandle,filesize($fname));
$content = str_replace($replaceThis, $withThis, $content);
$fhandle = fopen($fname,"w");
fwrite($fhandle,$content);
fclose($fhandle);
}
//Function that runs every time that email-posts-to-subscribers is updated
function my_upgrade_function( $upgrader_object, $options ) {
$current_plugin_path_name = 'email-posts-to-subscribers/email-posts-to-subscribers.php';
if ($options['action'] == 'update' && $options['type'] == 'plugin' ) {
foreach($options['plugins'] as $each_plugin) {
if ($each_plugin==$current_plugin_path_name) {
replace_text_plugin_email_posts_to_subscribers("/wp-content/plugins/email-posts-to-subscribers/job/optin.php","\$home_url = 'https://example.com/redirect-optin';");
replace_text_plugin_email_posts_to_subscribers("/wp-content/plugins/email-posts-to-subscribers/job/unsubscribe.php","\$home_url = 'https://example.com/redirect-unsubscribe';");
}
}
}
}
add_action( 'upgrader_process_complete', 'my_upgrade_function',10, 2);
I guess this wil only be of use when you have to adjust some minor things. Rewriting complete code is maybe not working with this code, but I didn't test this.
Related
I created a WordPress Plugin, with a hook to create links below the overview of posts in the backend(for a custom post type).
The link should redirect to a custom PHP-File. Which is currently solved like this (for Terminierungsverwaltung):
class CustomPlugin
{
function __construct(){
#... more code
/**
* Terminverwaltung
*/
add_filter( 'post_row_actions', array( $this,'termin_add_user_action_button'), 10, 2 );
#... more code
}
#... more code
function termin_add_user_action_button($actions, $post){
global $wpdb;
$post_id = $post->ID; //post ID
$poll_id; //poll ID
$wordpress_polls = $wpdb->get_results("SELECT wordpress_id, poll_id FROM " . self::WORDPRESS_TABLE_NAME . " WHERE wordpress_id = " . $post_id);
$wordpress_polls_rows = $wpdb->num_rows;
foreach($wordpress_polls as $wordpress_poll){
$poll_id = $wordpress_poll->poll_id;
}
if($wordpress_polls_rows === NULL || $wordpress_polls_rows === 0){
return $actions;
} else{
if(get_post_type() === 'workshop'){
$url = add_query_arg(
array(
'post_id' => $post->ID,
'poll_id' => $poll_id,
),
plugins_url( '/attendees.php', __FILE__ )
);
$actions['termin_add_user'] = 'Teilnehmerverwaltung';
}
return $actions;
}
}
#... more code
}
So currently I am pointing directly to the source file attendees.php (which is located inside the plugin directory) and it is not protected.
My aim is to protect the attendees.php with:
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
Obviously, I will need to hook the file somehow to the plugin or WordPress, so ABSPATH is defined. But I am not sure how to do it. Does anyone know how to get this done?
I am new to PHP and WordPress, so sorry if this is a newbie question.
Thanks in advance!
THE-E
In case the attendees.php is of importance, it has currently this structure, and should be displayed independently:
<?php
// if ( ! defined( 'ABSPATH' ) ) {
// exit; // Exit if accessed directly.
// }
require '../../../wp-load.php';
require 'src/attendees_function.php';
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel = "stylesheet"
type = "text/css"
href = "style/attendeesStyle.css" />
<title>Teilnehmerverwaltung: <?php echo get_the_title($_REQUEST['post_id']);?></title>
</head>
<body>
<?php add_user_form(); ?>
<?php delete_attendee(); ?>
<?php upload(); ?>
<H1>Teilnehmerverwaltung</H1>
<H2><?php echo get_the_title($_REQUEST['post_id']);?></H2>
<section>
<div id="add-users-upload">
<form method="POST" enctype="multipart/form-data" id="csv-form">
<input type="file" name="teilnehmer-csv" accept=".csv"><br>
<button type="submit" name="csv-upload" id="top-buttons">Teilnehmer CSV hochladen</button>
</form>
<form method="post">
<label for="kuerzel">Kürzel:</label>
<input type="hidden" name="poll-id" value="<?php $poll_id = $_REQUEST['poll_id']; echo $poll_id; ?>"/>
<input type="hidden" name="table" value="<?php $table = "oc_polls_share"; echo $table; ?>"/>
<input type="text" class="form-control" id="input-kuerzel" name="kuerzel"><br>
<button type="submit" name="add-user-form" id="top-buttons">Teilnehmer anlegen</button>
</form>
</div>
</section>
<div id="table-div">
<table>
</thead>
<tr>
<td id="index">#</td>
<td id="index">Status</td>
<td id="header">Kürzel</td>
<td id="header">E-Mail</td>
<td id="header">Vorname</td>
<td id="header">Nachname</td>
<td id="header">Geburtstag</td>
<td id="header">Token</td>
<td id="header">Löschen</td>
<td id="header">Umfrage-Link</td>
<td id="header">Webseiten-Link</td>
<td id="header">Senden</td>
</tr>
</thead>
<tbody>
<?php
$nextcloud_base_url = "https://example.com";
$nextcloud_attendees_base_url = $nextcloud_base_url . "/apps/polls/s/";
if(isset($_REQUEST['post_id']) && isset($_REQUEST['poll_id'])){
$post_id = $_REQUEST['post_id']; //post ID
$poll_id = $_REQUEST['poll_id']; //poll ID
}
$wordpress_polls_table_name = 'wordpress_polls'; //storage of primary keys of post id and poll id
$polls_share_table_name = 'oc_polls_share'; //attendees table
$wordpress_polls = get_wordpress_polls($wordpress_polls_table_name, $post_id);
$wordpress_polls_rows = get_wordpress_polls($wordpress_polls_table_name, $post_id);
$poll_id = get_poll_id($wordpress_polls);
if($wordpress_polls_rows === NULL || $wordpress_polls_rows === 0){
return;
} else {
$attendees = get_attendees($polls_share_table_name, $poll_id);
$attendees_rows = get_attendees_rows($polls_share_table_name, $poll_id);
create_attendee_rows($attendees, $nextcloud_attendees_base_url);
}
?>
</tbody>
</table>
</div>
<div id="legende">
<p>
Status-Legende:<br>
❌ = Abstimmung nicht erfolgt<br>
✅ = Abstimmung erfolgt
</p>
</div>
</body>
</html>
EDIT:
I am looking into the Custom Endpoints Documentation, but couldn't get it to work for now.
Meanwhile a picture of the content I want to integrate (attendees.php)
There's a bunch of ways to solve this which I'll try to outline. These are not in order of recommendation, just stream on consciousness. I would recommend #2, if it is viable, however.
1 - Manually boot WordPress
This question shows shows how to do this and this answer gives pros and cons for each, but the general idea is to require_once either the wp-load.php or the wp-blog-header.php files from root, and you'd probably want the former. Doing this, however, is usually discouraged and I would only recommend it for cases where you need access to basic WordPress functions. If you do this, WordPress doesn't know what your security requirements are, so it will be up to you to perform access control using things like current_user_can.
Although I posted this first, I would strongly recommended avoiding this, and if you are distributing your plugin, especially in the WordPress.org repo, absolutely don't do this because I'm pretty certain it would be rejected.
2 - Create a true WordPress admin page
If you are willing so sacrifice some pixel space (for the admin toolbars), this is the recommended way. Just register a menu using add_menu_page and you can either echo or include/require your code:
add_action(
'admin_menu',
static function () {
add_menu_page(
'My Plugin',
'My Plugin',
'manage_options',
'my-plugin',
static function () {
// Either echo here or use an include/require
echo '<h1>Hello world</h1>';
}
);
}
);
The URL to this page is based on the fourth parameter to that function, which using the above would be /wp-admin/admin.php?page=my-plugin. Access control is handled automatically with the third parameter which makes certain that the user has the manage_options permission. You can customize that as needed, and optionally create your own permissions, too.
3 - Inject via templates
The template_include function is used to determine which front-end WordPress template to use. Personally, I don't like using this for admin stuff because I like to keep things separate from each other, but that's just me. In this code sample below I'm setting a template in the theme's folder, but it could just as easily be in the plugin's folder.
add_filter(
'template_include',
static function ($template) {
// Pick whatever logic you want here, it could be `_GET` or `_POST` or pretty much anything
if ('my-plugin' === ($_GET['action'] ?? null)) {
$template = get_template_directory() . '/searchform.php';
}
return $template;
}
);
The if logic is where you do whatever you want. I'm just showing a simple _GET check where the URL would be /?action=my-plugin. Security, once again, is up to you, but you have full access to WordPress core functions like current_user_can to do whatever is necessary.
4 - Rewrite endpoints
This is actually a version of #3 because you are just making the URL prettier. I personally think it is over-complicated because it is a multi-step process with a lot of moving parts, but if the URL is important to you it might work. Make sure to flush your permalinks! The key to this is rewrite_rules_array where you register a custom regex for the URL and you can provide whatever logic you need, including querystrings and whatever.
// Register a global variable for the URL so that WordPress is aware that you care about it
add_filter(
'query_vars',
static function ($vars) {
$vars[] = 'my-plugin';
return $vars;
}
);
// Add special regex-like syntax for URLs. You can go wild here, too
add_action(
'rewrite_rules_array',
static function ($rules) {
$newrules = array();
// The true isn't important, it could be anything. The my-plugin is what
// matters. Make sure to flush your permalinks!
$newrules['my-plugin/?$'] = 'index.php?my-plugin=true';
return $newrules + $rules;
}
);
add_action(
'template_include',
static function ($template) {
if (get_query_var('my-plugin')) {
$template = get_template_directory() . '/searchform.php';
}
return $template;
}
);
I am working on a way to disable a specific plugin on a certain product page. I've cobbled this together from things I found online and the plugins code itself but its not working. Curious to have some fresh eyes have a look and let me know what might be failing. The post id of the product is 2679320. The actions I have set to remove are the ones referenced in the plugin wp_enqueue_scripts. Here is the code I'm trying by loading to snippets:
function remove__construct() {
global $post;
$ids = array(2679320);
if(in_array($post->ID,$ids)):
remove_action(‘wp_enqueue_scripts’,array($this,’enqueue_scripts’));
remove_action(‘plugins_loaded’,array($this,’load_txt_domain’),99);
remove_action(‘wp_footer’,array($this,’get_popup_markup’));
remove_filter( ‘pre_option_woocommerce_cart_redirect_after_add’, array($this,’prevent_cart_redirect’),10,1);
endif;
}
add_action(‘wp_head’, ‘remove__construct’, 1);
Any ideas why this isn't working? What did I miss? Anyone have better way to do this?
You can use Plugin Organizer. It allows you to selectively disable a plugin on a page or a complete post type.
There are 2 ways to disable plugin.
The first way is to create a custom plugin that removes the action that used to initialize your target plugin. The second way is to remove actions and filters which add scripts, styles and makes changes on a page.
Either way you choose, you have to remove actions after they've been added and before they actually worked. That means that for the first way in most cases you have to use plugins_loaded hook which can't be used in your functions.php (the first hook which can be used in functions.php is load_textdomain hook). in case you want to disable the plugin on certain pages you have to somehow get the current post ID, which isn't so easy because global $post variable is not available yet (The earliest hook with $post is wp).
Parameters for your remove_action depend on plugin add_action. The main point here is that all parameters of your remove_action must be the same as add_action parameters. Here are some examples :
add_action('plugins_loaded', 'init_function_name');
remove_action('plugins_loaded', 'init_function_name');
add_action('plugins_loaded', 'init_function_name', 100);
remove_action('plugins_loaded', 'init_function_name', 100);
class Plugin_Classname {
public static function init() {
add_action( 'plugins_loaded', array( __CLASS__, 'on_init' ) );
}
}
remove_action( 'plugins_loaded', array( 'Plugin_Classname', 'on_init' ) );
class Plugin_Classname {
public function __construct(){
add_action('plugins_loaded', array($this, 'init'), 99);
}
public static function get_instance(){
if(self::$instance === null){
self::$instance = new self();
}
return self::$instance;
}
}
remove_action('plugins_loaded', array( Plugin_Classname::get_instance() , 'init'), 99);
Let's begin with the easiest way. Assume that removing scripts and styles is enough. Then you have to find wp_enqueue_scripts hooks in the plugin source. Eq.:
class Xoo_CP_Public{
protected static $instance = null;
public function __construct(){
add_action('plugins_loaded',array($this,'load_txt_domain'),99);
add_action('wp_enqueue_scripts',array($this,'enqueue_scripts'));
add_action('wp_footer',array($this,'get_popup_markup'));
add_filter( 'pre_option_woocommerce_cart_redirect_after_add', array($this,'prevent_cart_redirect'),10,1);
}
public static function get_instance(){
if(self::$instance === null){
self::$instance = new self();
}
return self::$instance;
}
}
As we need global $post variable we gonna use wp hook. Place the code below in functions.php:
function disable_plugin() {
global $post;
$ids = array( 2679320 ); // Disable plugin at page with ID = 2679320
if( in_array( $post->ID ,$ids ) ) {
remove_action('wp_enqueue_scripts',array( Xoo_CP_Public::get_instance(),'enqueue_scripts'));
remove_action('plugins_loaded',array(Xoo_CP_Public::get_instance(),'load_txt_domain'),99);
remove_action('wp_footer',array(Xoo_CP_Public::get_instance(),'get_popup_markup'));
remove_filter( 'pre_option_woocommerce_cart_redirect_after_add', array(Xoo_CP_Public::get_instance(),'prevent_cart_redirect'),10,1);
}
}
add_action( 'wp', 'disable_plugin' );
What if we want to remove an action is used to initialize this plugin? Let's take a look at add_action:
add_action('plugins_loaded','xoo_cp_rock_the_world');
In this case we can't use plugins_loaded hook because add_action is being called without priority parameter. If it's being called with priority parameter we could just create disable-plugin.php file in /wp-content/plugins folder and place this code there:
function disable_plugin() {
remove_action('plugins_loaded', 'xoo_cp_rock_the_world', 100);
}
add_action('plugins_loaded','disable_plugin');
But it's useless in this case without priority parameter. Yet we can cheat! We don't have to use any hooks and call remove_action directly. We should call it after target plugin add_action was called. Plugins are loaded in alphabetical order so if we named our plugin 'zzz-disable-plugin.php` with this lines of code:
/* Plugin Name: zzz-disable-plugin */
remove_action('plugins_loaded', 'xoo_cp_rock_the_world');
The target plugin will be disabled. At all pages though. I haven't find a way to get ID of current page on such an early hook. But we can use URI :
/* Plugin Name: zzz-disable-plugin */
if( 'product/polo' == trim( $_SERVER[ 'REQUEST_URI' ], '/' ) ) {
remove_action('plugins_loaded', 'xoo_cp_rock_the_world');
}
I have a page speed issue, the theme I bought is really crappy but i cannot change it now. I use WP_rocket, server have HTTP2 but still it is to many resources to load. So i try to reduce numbers of styles by wp_deregister_style and load it only when need. For example contact-form-7 front-end style I need only in .../contact page. It good idea ? Or it could be harmful?
function rs_deregister_css () {
global $wp;
$url = home_url( $wp->request);
$contakt = strpos($url,'contakt');
if (!$contakt) {
wp_deregister_style('contact-form-7');
}
}
add_action( 'wp_print_styles', 'rs_deregister_css', 99);
Yes, its a very good idea since you only use the contact form in the contact page, don't forget to deregister the javascript file, too
if (!$contakt) {
wp_deregister_style('contact-form-7');
wp_deregister_script('contact-form-7');
}
Yes, it would be a good idea for your load time. But I suggest you to load style on specific instead of checking the URL and unload it every time.
Try to read Conditional Tags
function my_enqueue_stuff() {
if ( is_front_page() ) {
/** Call landing-page-template-one enqueue */
wp_enqueue_style( 'your-style-handle', get_stylesheet_directory_uri() . '/yourfile.css' );
} else {
/** Call regular enqueue */
}
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_stuff' );
EDIT
Since you only want to the style or javascript load for specific pages, then add this code to your functions.php:
function remove_wpcf7_extras() {
remove_action('wp_print_scripts', 'wpcf7_enqueue_scripts');
remove_action('wp_print_styles', 'wpcf7_enqueue_styles');
}
if( !is_page('contact') ) {
add_action('wp_head', 'remove_wpcf7_extras');
}
I am trying to prevent all of the different scripts from my shop ( jigoshop ) from loading on every page load. I have been using the wp_deregister_script function but it wont work. My question is, if there is a way that the wp_deregister_script function could be blocked by the plugin itself or any other function?
This is the script i am currently using:
function js_css_control()
{
$link = $_SERVER['REQUEST_URI'];
$teile = explode("/", $link);
if($link!="/")
{
$seite = $teile[1];
}
else
{
$seite = "start";
}
if($seite=="start")
{
wp_deregister_script( 'jigoshop_global' );
wp_deregister_script( 'prettyPhoto' );
wp_deregister_style ( 'jigoshop_styles' );
wp_deregister_style ( 'jigoshop-jquery-ui' );
wp_deregister_style ( 'jigoshop-select2' );
}
}
add_action('wp_enqueue_scripts', 'js_css_control');
The function that may suit your purpose better is wp_dequeue_script. You can do everything just about the same except change deregister to dequeue.
Also, if that doesn't work and for future reference, try changing the hook that you use in add_action, for instance template_redirect may be a choice in case wp_enqueue_scripts doesn't pan out.
Anyone know of a way to remove the main editor from the page edit screen? And not just with css. I've added a few other meta boxes with the tinymce and they collide with the main one.
I have a class that removes other meta boxes from the edit screen, but I cant get rid of the main editor this way. I've tried to add 'divpostrich' and 'divpost' to the array in the class (but with no luck):
class removeMetas{
public function __construct(){
add_action('do_meta_boxes', array($this, 'removeMetaBoxes'), 10, 3);
}
public function removeMetaBoxes($type, $context, $post){
/**
* usages
* remove_meta_box($id, $page, $context)
* add_meta_box($id, $title, $callback, $page, $context = 'advanced', $priority = 'default')
*/
$boxes = array( 'slugdiv', 'postexcerpt', 'passworddiv', 'categorydiv',
'tagsdiv', 'trackbacksdiv', 'commentstatusdiv', 'commentsdiv',
'authordiv', 'postcustom');
foreach ($boxes as $box){
foreach (array('link', 'post', 'page') as $page){
foreach (array('normal', 'advanced', 'side') as $context){
remove_meta_box($box, $type, $context);
}
}
}
}
}
$removeMetas = new removeMetas();
I have also tried removing the 'divpostrich' with jquery. But cant figure out where to put the js for it to work. When I remove the 'postdivrich' in the browser with firebug - my remaining tinymce fields work perfect.
Any ideas?
There is built in WP support for this so you don't have to fiddle directly with the globals and ensure forwards compatibility if they ever change how features are handled. The WP Core code does pretty much the exact same logic as #user622018 answer however
function remove_editor() {
remove_post_type_support('page', 'editor');
}
add_action('admin_init', 'remove_editor');
What you are looking for is the global $_wp_post_type_features array.
Below is a quick example of how it can be used
function reset_editor()
{
global $_wp_post_type_features;
$post_type="page";
$feature = "editor";
if ( !isset($_wp_post_type_features[$post_type]) )
{
}
elseif ( isset($_wp_post_type_features[$post_type][$feature]) )
unset($_wp_post_type_features[$post_type][$feature]);
}
add_action("init","reset_editor");
Add the following code to your functions.
function remove_editor_init() {
if ( is_admin() ) {
$post_id = 0;
if(isset($_GET['post'])) $post_id = $_GET['post'];
$template_file = get_post_meta($post_id, '_wp_page_template', TRUE);
if ($template_file == 'page-home.php') {
remove_post_type_support('page', 'editor');
}
}
}
add_action( 'init', 'remove_editor_init' );
Couldn't you just disable the TinyMCE editor, leaving the HTML editor, as your meta boxes are colliding with it? :)
To disable the editor you will need to edit your wp-config.php file and add this line to the top:
define('DISALLOW_FILE_EDIT', true);