如何在wp-admin内部影响Widget上显示的信息

时间:2017-03-22 作者:Sagive

首先,我想澄清-this is not a CSS question.

我想在wp admin、侧栏或页面生成器中更改小部件处于关闭/打开模式时显示的数据。这里有一幅图片可以更好地解释。

enter image description here

我希望能够动态地从小部件的标题中添加/删除一些内容,并使用widget$instance这样做

The desired result:
添加一个小信息标签,说明移动/桌面/两者-这是在特定小部件中选择的选项

有什么想法吗?

更新Since i see some intrest in a solution to this question:
@cjbj解决方案运行良好,但仅在侧栏中,而且仅部分:

add_filter (\'dynamic_sidebar_params\',\'wpse261042_change_widget_title\');
function wpse261042_change_widget_title ($params) {

    $widget_id          = $params[0][\'widget_id\'];
    $widget_instance    = strrchr ($widget_id, \'-\');
    $wlen               = strlen ($widget_id);
    $ilen               = strlen ($widget_instance);
    $widget_name        = substr ($widget_id,0,$wlen-$ilen);
    $widget_instance    = substr ($widget_instance,1);

    // get the data
    $widget_instances   = get_option(\'widget_\' . $widget_name);
    $data               = $widget_instances[$widget_instance];
    $use_mobile         = $data[\'use_mobile\'];  // option inside my widget

    if($use_mobile == \'yes\') {$string = \'desktop / mobile\';} else {$string = \'desktop only\';}

    $params[0][\'widget_name\'] .= $string;
    return $params;
}
但是。。您不能在该字符串中插入任何html(或者至少我不能)

如果我找到有效的解决方案,将进行更新。

3 个回复
最合适的回答,由SO网友:Fayaz 整理而成

背景:

使用dynamic_sidebar_params 不适用于HTML 是因为WordPress条带HTML 来自小部件标题wp_widget_control() 功能如下:

$widget_title = esc_html( strip_tags( $sidebar_args[\'widget_name\'] ) );
WordPress还剥离HTML 在默认JavaScript中wp-admin/js/widgets.js

因此,如果没有定制的解决方案,PHP或JavaScript都没有默认的过滤器或选项来实现您想要的。

自定义PHP解决方案:

自定义PHP解决方案可能只在wp-admin -> Appearance -> Widgets, 但不在Customizer -> Widgets.

WordPress添加wp_widget_control() function (生成控件UI)的dynamic_sidebar_params 钩子,因此可以使用此过滤器钩子覆盖它。然而,在customizer中,WordPress调用wp_widget_control() function 直接,因此此解决方案不适用于自定义程序。

解决方案如下所示(在自定义插件中添加此代码):

add_filter( \'dynamic_sidebar_params\', \'wpse261042_list_widget_controls_dynamic_sidebar\', 20 );
function wpse261042_list_widget_controls_dynamic_sidebar( $params ) {
    global $wp_registered_widgets;
    // we only want this in wp-admin (may need different check to enable page builder)
    if( is_admin() ) {
        if ( is_array( $params ) && is_array( $params[0] ) && $params[0][\'id\'] !== \'wp_inactive_widgets\' ) {
            $widget_id = $params[0][\'widget_id\'];
            if ( $wp_registered_widgets[$widget_id][\'callback\'] ===  \'wp_widget_control\' ) {
                // here we are replacing wp_widget_control() function 
                // with our custom wpse261042_widget_control() function
                $wp_registered_widgets[$widget_id][\'callback\'] = \'wpse261042_widget_control\';
            }
        }
    }
    return $params;
}

function wpse261042_widget_control( $sidebar_args ) {
    // here copy everything from the core wp_widget_control() function
    // and change only the part related to heading as you need 
} 
正如我之前所说的,此解决方案不适用于定制程序,并且更可能需要将来的更新,因为我们正在覆盖核心功能。

自定义JavaScript解决方案(推荐):

幸运的是,可以使用JavaScript自定义此行为。WordPress仍然使用JavaScript更新小部件控件标题。为此,WordPress保留了一个占位符in-widget-title CSS类并使用小部件更新它title JavaScript代码中的字段值。我们可以利用这一点来实现我们的目标。

相关的核心JS文件:

首先,您需要知道WordPress加载wp-admin/js/customize-widgets.js 文件(带有customize-widgets 手柄)inwp-admin -> Customize -> Widgets (自定义程序)和wp-admin/js/widgets.js 文件(带有admin-widgets 手柄)inwp-admin -> Appearance -> Widgets 操作控件UI。这两个文件对小部件UI标记和小部件标题UI操作执行类似的操作,但也有许多不同的操作。因此,对于基于JavaScript的解决方案,我们需要考虑这一点。

定制器的注意事项:

定制器不会在页面加载后立即加载小部件UI标记,而是在相应的Widgets -> Sidebar 面板打开。因此,我们需要在WordPress加载小部件UI后对其进行操作。例如,由于customizer代码是基于事件的,因此我使用以下代码行在正确的时刻设置事件处理程序:

section.expanded.bind( onExpanded );
此外,customizer使用AJAX立即加载更改,这就是为什么我使用下面的行来访问数据更改:

control.setting.bind( updateTitle );
还有,我需要widget-added 具有以下代码行的事件:

$( document ).on( \'widget-added\', add_widget );
自定义程序通用(&h3);wp-admin -> Appearance -> Widgets:上述两个JavaScript文件都会触发widget-updated 更新小部件时发生的事件。虽然customizer可以使用AJAX立即完成,但传统的Widget 管理员在您单击保存按钮后执行此操作。为此,我使用了以下代码行:

$( document ).on( \'widget-updated\', modify_widget );
注意事项wp-admin -> Appearance -> Widgets:与定制者相反,传统Widgets admin使用PHP加载小部件控件UI,因此我遍历了UI HTML以进行如下初始更改:

$( \'#widgets-right div.widgets-sortables div.widget\' ).each( function() { // code } ); 
自定义插件代码:以下是一个完整的插件,包含基于JavaScript的解决方案,可在wp-admin -> Appearance -> WidgetsCustomizer -> Widgets:

wpse-widget-control.php 插件PHP文件:

<?php
/**
 *  Plugin Name: Widget Control
 *  Plugin URI: https://wordpress.stackexchange.com/questions/261042/how-to-influence-the-information-displayed-on-widget-inside-wp-admin
 *  Description: Display additional info on Widget Heading in wp-admin & customizer using JS
 *  Author: Fayaz
 *  Version: 1.0
 *  Author URI: http://fmy.me/
 */

    if( is_admin() ) {
        add_action( \'current_screen\', \'wpse261042_widget_screen\' );
    }

    function wpse261042_widget_screen() {
        $currentScreen = get_current_screen();
        if( $currentScreen->id === \'customize\' ) {
            add_action( \'customize_controls_enqueue_scripts\', \'wpse261042_customizer_widgets\', 99 );
        }
        else if( $currentScreen->id === \'widgets\' ) {
            add_action( \'admin_enqueue_scripts\', \'wpse261042_admin_widgets\', 99 );
        }
    }

    function wpse261042_customizer_widgets() {
        wp_enqueue_script( \'custom-widget-heading\', plugin_dir_url( __FILE__ ) . \'custom-widget-heading.js\', array( \'jquery\', \'customize-widgets\' ) );
    }

    function wpse261042_admin_widgets() {
        wp_enqueue_script( \'custom-widget-heading\', plugin_dir_url( __FILE__ ) . \'custom-widget-heading.js\', array( \'jquery\', \'admin-widgets\' ) );
    }
custom-widget-heading.js JavaScript文件:

(function( wp, $ ) {
    var compare = {
        // field to compare
        field: \'title\',
        // value to be compared with
        value: \'yes\',
        // heading if compare.value matches with compare.field value
        heading: \' <i>(mobile/desktop)</i> \',
        // alternate heading
        alt_heading: \' <i>(desktop only)</i> \',
        // WP adds <span class="in-widget-title"></span> in each widget heading by default
        heading_selector: \'.in-widget-title\'
    };

    var widgetIdSelector = \'> .widget-inside > form > .widget-id\';
    // heading is added as prefix of already existing heading, modify this as needed
    function modify_heading( $elm, isMain ) {
        var html = $elm.html();
        if ( html.indexOf( compare.heading ) == -1 && html.indexOf( compare.alt_heading ) == -1 ) {
            if( isMain ) {
                $elm.html( compare.heading + html );
            }
            else {
                $elm.html( compare.alt_heading + html );
            }
        }
    };
    function parseFieldSelector( widgetId ) {
        return \'input[name="\' + widgetIdToFieldPrefix( widgetId ) + \'[\' + compare.field + \']"]\';
    };

    // @note: change this function if you don\'t want custom Heading change to appear for all the widgets.
    // If field variable is empty, then that means that field doesn\'t exist for that widget.
    // So use this logic if you don\'t want the custom heading manipulation if the field doesn\'t exist for a widget
    function modify_widget( evt, $widget, content ) {
        var field = null;
        var field_value = \'\';
        if( content ) {
            field = $( content ).find( parseFieldSelector( $widget.find( widgetIdSelector ).val() ) );
        }
        else {
            field = $widget.find( parseFieldSelector( $widget.find( widgetIdSelector ).val() ) );
        }
        if( field ) {
            field_value = ( ( field.attr( \'type\' ) != \'radio\' && field.attr( \'type\' ) != \'checkbox\' )
                          || field.is( \':checked\' ) ) ? field.val() : \'\';
        }
        modify_heading( $widget.find( compare.heading_selector ), field_value == compare.value );
    }

    function parseWidgetId( widgetId ) {
        var matches, parsed = {
            number: null,
            id_base: null
        };
        matches = widgetId.match( /^(.+)-(\\d+)$/ );
        if ( matches ) {
            parsed.id_base = matches[1];
            parsed.number = parseInt( matches[2], 10 );
        } else {
            parsed.id_base = widgetId;
        }
        return parsed;
    }
    function widgetIdToSettingId( widgetId ) {
        var parsed = parseWidgetId( widgetId ), settingId;
        settingId = \'widget_\' + parsed.id_base;
        if ( parsed.number ) {
            settingId += \'[\' + parsed.number + \']\';
        }
        return settingId;
    }
    function widgetIdToFieldPrefix( widgetId ) {
        var parsed = parseWidgetId( widgetId ), settingId;
        settingId = \'widget-\' + parsed.id_base;
        if ( parsed.number ) {
            settingId += \'[\' + parsed.number + \']\';
        }
        return settingId;
    }
    var api = wp.customize;
    if( api ) {
        // We ate in the customizer
        widgetIdSelector = \'> .widget-inside > .form > .widget-id\';
        api.bind( \'ready\', function() {
            function add_widget( evt, $widget ) {
                var control;
                control = api.control( widgetIdToSettingId( $widget.find( widgetIdSelector ).val() ) );

                function updateTitle( evt ) {
                    modify_widget( null, $widget );
                };
                if ( control ) {
                    control.setting.bind( updateTitle );
                }
                updateTitle();
            };
            api.control.each( function ( control ) {
                if( control.id &&  0 === control.id.indexOf( \'widget_\' ) ) {
                    api.section( control.section.get(), function( section ) {
                        function onExpanded( isExpanded ) {
                            if ( isExpanded ) {
                                section.expanded.unbind( onExpanded );
                                modify_widget( null, control.container.find( \'.widget\' ), control.params.widget_content );
                            }
                        };
                        if ( section.expanded() ) {
                            onExpanded( true );
                        } else {
                            section.expanded.bind( onExpanded );
                        }
                    } );
                }
            } );
            $( document ).on( \'widget-added\', add_widget );
        } );
    }
    else {
        // We are in wp-admin -> Appearance -> Widgets
        // Use proper condition and CODE if you want to target any page builder
        // that doesn\'t use WP Core Widget Markup or Core JavaScript
        $( window ).on( \'load\', function() {
            $( \'#widgets-right div.widgets-sortables div.widget\' ).each( function() {
                modify_widget( \'non-customizer\', $( this ) );
            } );
            $( document ).on( \'widget-added\', modify_widget );
        } );
    }
    $( document ).on( \'widget-updated\', modify_widget );
})( window.wp, jQuery );
插件用法:Note: 如果您将title 小部件的yes, 然后,它将在小部件控件UI标题中显示(移动/桌面)
,所有其他小部件的标题中将显示(仅桌面)。在customizer中,更改将立即进行wp-admin -> widgets 更改将在您之后显示save 这些变化。当然,您可以通过修改代码(在JavaScript中)来改变这种行为,从而为不同的field_name 或者只向一些小部件显示特定的标题,而不是向所有小部件显示。

例如,假设您有一个名为use_mobile, 当标题设置为时,您要将其设置为(移动/桌面)yes. 然后设置compare 变量如下:

var compare = {
    field: \'use_mobile\',
    value: \'yes\',
    heading: \' <i>(mobile/desktop)</i> \',
    alt_heading: \' <i>(desktop only)</i> \',
    heading_selector: \'.in-widget-title\'
};
此外,如果要更改整个标题(而不是.in-widget-title), 然后您可以更改heading_selector 设置以及的正确标记heading &;alt_heading 这样做。这种可能性是无穷无尽的,但如果您想对生成的标记有太多创造性,请确保WordPress核心代码不会产生任何错误。

页面生成器集成:

这些解决方案是否适用于页面生成器将取决于该页面生成器实现。如果它使用WordPress提供的方法加载小部件控件UI,那么它应该在没有任何修改的情况下工作,否则页面生成器也可能会有类似(但经过修改)的含义。

SO网友:cjbj

首先让我们看看是否可以更改admin中小部件标题中显示的信息。此列表由生成wp_list_widget_controls, 这需要dynamic_sidebar, 其中包含过滤器dynamic_sidebar_params 更改控件中的参数,包括标题。让我们尝试一下:

add_filter (\'dynamic_sidebar_params\',\'wpse261042_change_widget_title\');
function wpse261042_change_widget_title ($params) {
  $string = \' Added info\';
  $params[0][\'widget_name\'] .= $string;
  return $params;
  }
The$string 不完全在你指的地方,但我认为这已经足够好了。

现在,我们需要更换$string 使用当前小部件内部的一些信息。幸运的是,我们知道我们使用的是哪个小部件,因为$params 还包含widget_id. 我会的refer to this answer 有关如何使用widget_id 检索小部件数据。我们开始吧:

 // we need to separate the widget name and instance from the id
 $widget_id = $params[0][\'widget_id\'];
 $widget_instance = strrchr ($widget_id, \'-\');
 $wlen = strlen ($widget_id);
 $ilen = strlen ($widget_instance);
 $widget_name = substr ($widget_id,0,$wlen-$ilen);
 $widget_instance = substr ($widget_instance,1);
 // get the data
 $widget_instances = get_option(\'widget_\' . $widget_name);
 $data = $widget_instances[$widget_instance];
现在阵列$data 包含小部件的实例,您可以选择要传递给哪个实例$string 在函数中。

SO网友:J.D.

WordPress已经在widgets UI中内置了类似的功能。例如,请参见如何将用户输入的“标题”值附加到此搜索小部件的标题:

Search widget with title appended

执行此操作的代码位于wp-admin/js/widgets.js:

appendTitle : function(widget) {
    var title = $(\'input[id*="-title"]\', widget).val() || \'\';

    if ( title ) {
        title = \': \' + title.replace(/<[^<>]+>/g, \'\').replace(/</g, \'&lt;\').replace(/>/g, \'&gt;\');
    }

    $(widget).children(\'.widget-top\').children(\'.widget-title\').children()
            .children(\'.in-widget-title\').html(title);

},
它找到input 具有id 以结尾的属性-title, 并将在该输入中输入的值附加到小部件标题栏中的文本。

因此,如果您考虑的设置是基于input 字段(无论typetextradio, 等等),你只需要给它一个id 结束于-title, 剩下的由WordPress负责。

这样,当用户修改设置时,标题栏中的字符串将自动更新。