¿Cómo hacer que un complemento requiera otro?

30

Estoy creando un complemento que agrega funcionalidad adicional a un complemento principal. Idealmente, en la pantalla de administración de complementos, el enlace "activar" debería deshabilitarse y debería agregarse una nota en línea que le diga al usuario que instale y active el complemento principal primero antes de que pueda usar el complemento actual.

kosinix
fuente
1
¿Qué pasa con el uso: is_plugin_active ()? Por ejemplo: if (is_plugin_active('path/to/plugin.php')) { // Do something }
TomC

Respuestas:

35

Gracias por la respuesta chicos. Aunque ambas respuestas me pusieron en el camino correcto, ninguna salió de la caja. Así que estoy compartiendo mis soluciones a continuación.

Método 1 - Usando register_activation_hook:

Cree el complemento principal en plugins / parent-plugin / parent-plugin.php:

<?php
/*
Plugin Name: Parent Plugin
Description: Demo plugin with a dependent child plugin.
Version: 1.0.0
*/

Cree el complemento infantil en plugins / child-plugin / child-plugin.php:

<?php
/*
Plugin Name: Child Plugin
Description: Parent Plugin should be installed and active to use this plugin.
Version: 1.0.0
*/
register_activation_hook( __FILE__, 'child_plugin_activate' );
function child_plugin_activate(){

    // Require parent plugin
    if ( ! is_plugin_active( 'parent-plugin/parent-plugin.php' ) and current_user_can( 'activate_plugins' ) ) {
        // Stop activation redirect and show error
        wp_die('Sorry, but this plugin requires the Parent Plugin to be installed and active. <br><a href="' . admin_url( 'plugins.php' ) . '">&laquo; Return to Plugins</a>');
    }
}

Tenga en cuenta que no estoy usando deactivate_plugins( $plugin );ya que por alguna razón no funciona. Entonces utilicé wp_die para cancelar la redirección de activación e informar al usuario.

Ventaja:

  • Solución simple y no incurre en db hits adicionales en comparación con el método 2

Desventajas

  • la pantalla de wp_die es fea
  • La pantalla wp_die TODAVÍA aparecerá si activó el complemento principal y el complemento secundario al mismo tiempo usando las casillas de verificación en la pantalla de administración de complementos.

Método 2: uso de admin_init y admin_notices

Cree el complemento principal en plugins / parent-plugin / parent-plugin.php:

<?php
/*
Plugin Name: Parent Plugin
Description: Demo plugin with a dependent child plugin.
Version: 1.0.0
*/

Cree el complemento infantil en plugins / child-plugin / child-plugin.php:

<?php
/*
Plugin Name: Child Plugin
Description: Parent Plugin should be installed and active to use this plugin.
Version: 1.0.0
*/
add_action( 'admin_init', 'child_plugin_has_parent_plugin' );
function child_plugin_has_parent_plugin() {
    if ( is_admin() && current_user_can( 'activate_plugins' ) &&  !is_plugin_active( 'parent-plugin/parent-plugin.php' ) ) {
        add_action( 'admin_notices', 'child_plugin_notice' );

        deactivate_plugins( plugin_basename( __FILE__ ) ); 

        if ( isset( $_GET['activate'] ) ) {
            unset( $_GET['activate'] );
        }
    }
}

function child_plugin_notice(){
    ?><div class="error"><p>Sorry, but Child Plugin requires the Parent plugin to be installed and active.</p></div><?php
}

Ventaja:

  • Funciona cuando activa el complemento principal y secundario al mismo tiempo mediante casillas de verificación

Desventaja:

  • Incurra db hits adicionales ya que el complemento se activa realmente al principio y se desactiva una vez que se ejecuta admin_init.

En cuanto a mi pregunta sobre la desactivación del enlace de activación, podría usar:

add_filter( 'plugin_action_links', 'disable_child_link', 10, 2 );
function disable_child_link( $links, $file ) {

    if ( 'child-plugin/child-plugin.php' == $file and isset($links['activate']) )
        $links['activate'] = '<span>Activate</span>';

    return $links;
}

Sin embargo, resultó ser muy poco práctico ya que NO hay lugar para poner este código. No pude ponerlo en el complemento principal ya que el complemento principal debe estar activo para que se ejecute este código. Ciertamente no pertenece al plugin secundario o functions.php. Así que estoy desechando esta idea.

kosinix
fuente
1
¡El método 2 funcionó muy bien! Lo usé para extender el complemento de otra persona.
Collin Price
2

Pruebe esto, está comentado, por lo que debería ayudarlo a comprenderlo.

<?php
register_activation_hook( __FILE__, 'myplugin_activate' ); // Register myplugin_activate on
function myplugin_activate() {
    $plugin = plugin_basename( __FILE__ ); // 'myplugin'
    if ( is_plugin_active( 'plugin-directory/first-plugin.php' ) ) {
        // Plugin was active, do hook for 'myplugin'
    } else {
        // Plugin was not-active, uh oh, do not allow this plugin to activate
        deactivate_plugins( $plugin ); // Deactivate 'myplugin'
    }
}
?> 

Si esto arroja un error, también puede verificar la 'opción' de 'myplugin' y configurarlo como falso o no activado.

MrJustin
fuente
2

Ambas soluciones sugeridas tienen fallas.

Método 1: Como se mencionó, la pantalla wp_die () TODAVÍA aparecerá cuando el complemento principal y el complemento secundario se activen al mismo tiempo usando las casillas de verificación en la pantalla de administración de complementos.

Método 2: en algunos casos de uso no es bueno ya que 'admin_init' se ejecuta mucho después de 'plugins_loaded' ( https://codex.wordpress.org/Plugin_API/Action_Reference ), y después del enlace de desinstalación ( https: // codex. wordpress.org/Function_Reference/register_uninstall_hook ). Entonces, por ejemplo, si queremos que el complemento ejecute algún código en la desinstalación, ya sea que el complemento principal esté activo o no, este enfoque NO funcionará.

Solución:

En primer lugar, debemos agregar el siguiente código al final del archivo PHP principal del complemento principal:

do_action( 'my_plugin_loaded' );

Esto enviará un evento / señal a todos los suscriptores, indicando que se cargó el complemento principal.

Entonces, la clase del complemento debería tener el siguiente aspecto:

class My_Addon
{
    static function init ()
    {
        register_activation_hook( __FILE__, array( __CLASS__, '_install' ) );

        if ( ! self::_is_parent_active_and_loaded() ) {
            return;
        }
    }

    #region Parent Plugin Check

    /**
     * Check if parent plugin is activated (not necessarly loaded).
     *
     * @author Vova Feldman (@svovaf)
     *
     * @return bool
     */
    static function _is_parent_activated()
    {
        $active_plugins_basenames = get_option( 'active_plugins' );
        foreach ( $active_plugins_basenames as $plugin_basename ) {
            if ( false !== strpos( $plugin_basename, '/my-plugin-main-file.php' ) ) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if parent plugin is active and loaded.
     *
     * @author Vova Feldman (@svovaf)
     *
     * @return bool
     */
    static function _is_parent_active_and_loaded()
    {
        return class_exists( 'My_Plugin' );
    }

    /**
     *
     * @author Vova Feldman (@svovaf)
     */
    static function _install()
    {
        if ( ! self::_is_parent_active_and_loaded() ) {
            deactivate_plugins( basename( __FILE__ ) );

            // Message error + allow back link.
            wp_die( __( 'My Add-on requires My Plugin to be installed and activated.' ), __( 'Error' ), array( 'back_link' => true ) );
        }
    }

    #endregion Parent Plugin Check
}

if (My_Addon::_is_parent_active_and_loaded())
{
    // If parent plugin already included, init add-on.
    My_Addon::init();
}
else if (My_Addon::_is_parent_activated())
{
    // Init add-on only after the parent plugins is loaded.
    add_action( 'my_plugin_loaded', array( __CLASS__, 'init' ) );
}
else
{
    // Even though the parent plugin is not activated, execute add-on for activation / uninstall hooks.
    My_Addon::init();
}

Espero eso ayude :)

Vovafeldman
fuente
44
Esta respuesta también tiene un defecto. :-) Se supone que tiene control total sobre el complemento principal donde puede agregar do_action ('my_plugin_loaded'); en su código La respuesta seleccionada funcionará con o sin control del complemento principal (por ejemplo, el complemento principal no es suyo)
kosinix
Gracias, esto es exactamente lo que estaba buscando. En mi caso, hacer un control total sobre el plug-in de los padres, y lo necesario para crear este tipo de dependencia.
cr0ybot
0

Creo que necesitas la activación del complemento TGM .

TGM Plugin Activation es una biblioteca PHP que le permite requerir o recomendar fácilmente complementos para sus temas de WordPress (y complementos). Permite a sus usuarios instalar, actualizar e incluso activar automáticamente complementos en forma singular o masiva utilizando clases, funciones e interfaces nativas de WordPress. Puede hacer referencia a complementos incluidos, complementos desde el repositorio de complementos de WordPress o incluso complementos alojados en otros lugares de Internet.

Amir Hossein Hossein Zadeh
fuente
Link incorrecto. Enlace correcto aquí
Xedin Desconocido el