介绍SitePoint随机Hello Bar WordPress插件

tech2022-10-29  92

If you’re a regular SitePoint reader, you may have noticed a small feature we refer to as the Random Hello Bar. If you scroll far enough down this page you should see it slide in from the top of the screen. It should look something like this:

如果您是普通的SitePoint阅读器,则可能已经注意到我们将其称为“ 随机Hello条”的一个小功能。 如果您将此页面向下滚动足够远,您应该会看到它从屏幕顶部滑入。 它看起来应该像这样:

We feel it’s an unobtrusive way of adding advertising, product announcements or other messages to a page, so we thought it was time to share it with you. In this article I’m going take you through how we put it together and then show some examples of how you can truly make it your own. If you prefer to just skip to the code, it’s available on GitHub, npm or the WordPress Plugin Directory.

我们认为这是在页面上添加广告,产品公告或其他消息的一种简便的方法,因此我们认为是时候与您分享了。 在本文中,我将带您了解我们如何将其组合在一起,然后显示一些示例来说明如何真正实现自己的个性化。 如果您只想跳到代码,可以在GitHub , npm或WordPress插件目录上找到 。

WordPress管理员界面 (WordPress Admin Interface)

The entry point to our plugin is sp-random-hello-bar.php and the plugin’s main class at src/SitePoint/RandomHelloBar.php.

我们插件的入口是sp-random-hello-bar.php ,插件的主类是src/SitePoint/RandomHelloBar.php 。

//sp-random-hello-bar.php require_once(plugin_dir_path( __FILE__ ).'src/SitePoint/RandomHelloBar.php'); \SitePoint\RandomHelloBar::public_actions(); if (is_admin()) { \Sitepoint\RandomHelloBar::admin_actions(); } //src/SitePoint/RandomHelloBar.php namespace SitePoint; class RandomHelloBar { const PLUGIN_NAME = 'sp-random-hello-bar'; private static function get_option($option) { return get_option(self::PLUGIN_NAME.'-'.$option); } private static function update_option($option, $value) { return update_option(self::PLUGIN_NAME.'-'.$option, $value); } private static function delete_option($option) { return delete_option(self::PLUGIN_NAME.'-'.$option); } }

To create our admin UI we’re going take advantage of the WordPress Settings API as it allows admin pages containing settings forms to be managed semi-automatically. We add a SP Random Hello Bar sub-menu under the Settings menu via the add_options_page function. Then we register sp-random-hello-bar-enabled and sp-random-hello-bar-ads settings and the sections they belong to.

要创建我们的管理界面,我们将利用WordPress设置API,因为它允许半自动管理包含设置表单的管理页面。 我们通过add_options_page函数在“ 设置”菜单下添加SP随机Hello Bar子菜单。 然后,我们注册sp-random-hello-bar-enabled sp-random-hello-bar-ads和sp-random-hello-bar-ads设置以及它们所属的部分。

public static function admin_actions() { add_action('admin_init', '\Sitepoint\RandomHelloBar::admin_init'); add_action('admin_menu', function() { add_options_page('SP Random Hello Bar', 'SP Random Hello Bar', 'manage_options', self::PLUGIN_NAME, '\SitePoint\RandomHelloBar::options_page'); }); } public static function admin_init() { register_setting(self::PLUGIN_NAME.'-settings-group', self::PLUGIN_NAME.'-enabled'); register_setting(self::PLUGIN_NAME.'-settings-group', self::PLUGIN_NAME.'-ads', '\SitePoint\RandomHelloBar::sanitize_ads'); add_settings_section(self::PLUGIN_NAME.'-section-one', 'Settings', '\SitePoint\RandomHelloBar::section_one_help', self::PLUGIN_NAME); add_settings_field(self::PLUGIN_NAME.'-enabled', 'Enabled', function() { $setting = esc_attr(self::get_option('enabled')); include dirname( __FILE__ ).'/../views/admin/enabled-fields.php'; }, self::PLUGIN_NAME, self::PLUGIN_NAME.'-section-one'); add_settings_section(self::PLUGIN_NAME.'-section-two', 'Hello Bar Ads', '\SitePoint\RandomHelloBar::section_two_help', self::PLUGIN_NAME); add_settings_section(self::PLUGIN_NAME.'-field-two', null, '\SitePoint\RandomHelloBar::ad_fields', self::PLUGIN_NAME); } public static function options_page() { include dirname( __FILE__ ).'/../views/admin/options_page.php'; }

One point of interest is a little trick we have used to create a one-click delete button in src/views/admin/ad_fields.php that uses a label styled as a button and a hidden checkbox.

一个有趣的地方是我们在src/views/admin/ad_fields.php中创建一个一键删除按钮的小技巧,该按钮使用样式化为按钮的标签和一个隐藏的复选框。

<label class="button"> <input type="checkbox" name="-ads[][delete]" value="1" onchange="this.form.submit()" style="display: none;" />Delete </label>

The sp-random-hello-bar-ads setting will hold an array of a values, each composed of an HTML and weight value. You may have noticed the last argument passed to register_setting() for sp-random-hello-bar-ads. This is a sanitize callback function that’s called before the setting is saved. In this case it serves two purposes. It removes any invalid elements, as well as any flagged for deletion (i.e. the button was clicked). Once sanitized, the values are passed to save_weighted_ads so we can save some extra settings: weighted-keys and total-weight, that we’ll need later when picking an item to show.

sp-random-hello-bar-ads设置将保存一个值数组,每个值均由HTML和weight值组成。 您可能已经注意到sp-random-hello-bar-ads传递给register_setting()的最后一个参数。 这是清除设置之前调用的清理回调函数。 在这种情况下,它有两个作用。 它将删除所有无效元素以及所有标记为删除的元素(即单击了按钮)。 save_weighted_ads ,这些值将传递到save_weighted_ads因此我们可以保存一些额外的设置: weighted-keys和total-weight ,稍后在选择要显示的项目时将需要它们。

public static function sanitize_ads($input) { foreach($input as $key => $ad) { if(!$ad['html'] || !is_numeric($ad['weight']) || isset($ad['delete'])) { unset($input[$key]); } } self::save_weighted_ads($input); return $input; } public static function save_weighted_ads($ads) { $weighted_array = array(); $total_weight = 0; foreach($ads as $key => $val){ $total_weight += $val['weight']; for($i=0; $i

We now have a functioning UI to enter Random Hello Bar content and enable/disable the feature.

现在,我们有一个可正常运行的UI,用于输入随机Hello Bar内容并启用/禁用该功能。

Ajax端点 (Ajax Endpoint)

It’s all well and good being able to enter Random Hello Bar content but at this point there’s no way to retrieve content on demand. Let’s fix that.

可以输入随机Hello Bar内容很好,但是目前无法按需检索内容。 让我们修复它。

First, we register Ajax hooks for logged-in and logged-out users.

首先,我们为登录和注销用户注册Ajax挂钩。

public static function public_actions() { if (!\SitePoint\RandomHelloBar::get_option('enabled')) return; add_action('wp_ajax_nopriv_get_random_hello_bar', '\SitePoint\RandomHelloBar::get_random_bar'); add_action('wp_ajax_get_random_hello_bar', '\SitePoint\RandomHelloBar::get_random_bar'); }

Both hooks call the following method.

两个钩子都调用以下方法。

public static function get_random_bar() { $weighted_keys = self::get_option('weighted-keys'); $total_weight = self::get_option('total-weight'); $rand = floor($_POST['rand'] * $total_weight); if(!$weighted_keys || !$total_weight || !$_POST['rand']) die(); $ads = self::get_option('ads'); if(!$ads) die(); if(!isset($weighted_keys[$rand])) die(); echo wp_kses_post($ads[$weighted_keys[$rand]]['html']); die(); }

How does it work? Say we’ve saved three bars as follows:

它是如何工作的? 假设我们保存了三个小节,如下所示:

html: bar1, weight: 2

html:bar1,重量:2 html: bar2, weight: 1

html:bar2,重量:1 html: bar3, weight: 1

html:bar3,重量:1

We would expect bar1 to show 50% of the time and bar2 and bar3 to each show 25% of time. Let’s also assume the client has sent through a $_POST['rand'] value of 0.33. $_POST['rand'] should always be a value from 0 to 1, such as that generated by the JavaScript Math.random() function. We rely on the $_POST['rand'] value sent from the client rather than generating a random number on the server as this is less likely to be cached. Given these values, get_random_bar() would work as follows:

我们希望bar1显示50%的时间,而bar2和bar3分别显示25%的时间。 我们还假设客户端发送了一个$_POST['rand']值0.33 。 $_POST['rand']的值应始终为0到1 ,例如JavaScript Math.random()函数生成的值。 我们依赖于客户端发送的$_POST['rand']值,而不是在服务器上生成随机数,因为它不太可能被缓存。 给定这些值, get_random_bar()将如下工作:

$weighted_keys = self::get_option('weighted-keys'); // [0, 0, 1, 2] $total_weight = self::get_option('total-weight'); // 4 //we can then turn $_POST['rand'] into a number between 0 and $total-weight -1 by doing $rand = floor($_POST['rand'] * $total_weight); // floor(0.33 * 4) = 1 $ads = self::get_option('ads'); // [0 => ['html' => 'bar1', 'weight => 2], 1 => ['html' => 'bar2', 'weight' => 1], 2 => ['html' => 'bar3', 'weight' => 1]] if(!isset($weighted_keys[$rand])) die(); // $weighted_keys[$rand] = $weighted_keys[1] = 0 //we then grab the value at index 1 of $weighted-keys, in this case 0 //and that is the index we use to retrieve a hello bar content from the saved ads option, which would be bar1 echo wp_kses_post($ads[$weighted_keys[$rand]]['html']); // $ads[0]['html'] = 'bar1'

To give another example, if $_POST['rand'] = 0.66:

再举一个例子,如果$_POST['rand'] = 0.66 :

$rand = 2 $weighted_keys[2] = 1; $ads[1] = 'bar2';

显示内容 (Displaying Content)

The server side of the plugin is ready to give you Random Hello Bars now, so it’s time for you to request and display them.

插件的服务器端现在准备为您提供随机Hello Bar,因此您可以请求并显示它们了。

The mechanics of hiding and showing the Random Hello Bar on page scroll are all encapsulated in the sp-hello-bar JavaScript module. It’s included in the plugin at src/js/SpHelloBar.js and is also available on npm. The module has absolutely zero dependencies (not even jQuery) and has been designed to be as flexible as possible. For that reason the module itself requires a throttle function to be passed into its constructor and leaves it up to you to fetch the Random Hello Bar content and insert it into the DOM. The module is only concerned with initiating, hiding and showing the Random Hello Bar.

在页面滚动中隐藏和显示随机Hello Bar的机制全部封装在sp-hello-bar JavaScript模块中。 它包含在src/js/SpHelloBar.js的插件中,也可以在npm上使用 。 该模块具有绝对零依赖性(甚至不是jQuery),并且被设计为尽可能灵活。 因此,模块本身需要将节流功能传递到其构造函数中,然后由您自己来获取Random Hello Bar内容并将其插入DOM中。 该模块仅涉及启动,隐藏和显示随机Hello Bar。

As default WordPress installs have both jQuery and Underscore.js available, so it’s easy to to create a basic script that fetches a Random Hello Bar, inserts it into the DOM and then initiates sp-hello-bar to bring it to life. It’s so easy we’ve included just such a script for you in the plugin at public/js/basic.js. That file has been compiled by Babel from the ES6 source code in src/js/basic.js.

由于默认的WordPress安装同时具有jQuery和Underscore.js可用,因此很容易创建一个基本脚本来获取随机Hello Bar,将其插入DOM,然后启动sp-hello-bar使其栩栩如生。 很简单,我们在public/js/basic.js的插件中为您提供了这样一个脚本。 该文件由Babel从src/js/basic.js的ES6源代码编译src/js/basic.js 。

import SpHelloBar from "./SpHelloBar"; import getRandomHelloBar from "./helpers/getRandomHelloBar"; import "../css/basic.css"; (function(window, $, _) { const sph = new SpHelloBar({ throttle: _.throttle }); getRandomHelloBar($, () => sph.init()); })(window, jQuery, _);

As you can see, this script constructs an instance of SpHelloBar passing in the throttle function from Underscore.js (the throttle function is used to throttle window resize and scroll events). It then calls the helper function getRandomHelloBar:

正如你所看到的,这个脚本构建的一个实例SpHelloBar传入throttle从功能Underscore.js (油门功能用于油门窗口大小调整和滚动事件)。 然后,它调用辅助函数getRandomHelloBar :

export default function ($, cb) { $.ajax({ type : "POST", url : ajax_object.ajax_url, data : { action : "get_random_hello_bar", rand : Math.random() }, success: function(data, textStatus, XMLHttpRequest) { $("body").prepend(data); cb(); } }); }

The function uses the jQuery.ajax method to request the Random Hello Bar content from our plugin. On success it inserts the content into the body and then fires the call back which we have set as SpHelloBar.init().

该函数使用jQuery.ajax方法从我们的插件请求Random Hello Bar内容。 成功后,它将内容插入到主体中,然后触发我们已设置为SpHelloBar.init() 。

As I mentioned the sp-hello-bar module has been designed to be flexible and easily extended. An example of extending it would be to take note of when a user manually closes the Random Hello Bar and then not display it to them next time. As that’s a nice user experience we’ve also included that for you in public/js/basicStorage.js.

正如我所提到的, sp-hello-bar模块的设计是灵活且易于扩展的。 扩展它的一个例子是记下用户何时手动关闭随机Hello Bar,然后下次不显示给他们。 由于这是一种不错的用户体验,因此我们也将其包含在public/js/basicStorage.js 。

import SpHelloBar from "./SpHelloBar"; import { checkStorage, disableViaStorage } from "./helpers/disableViaStorage"; import getRandomHelloBar from "./helpers/getRandomHelloBar"; (function(window, $, _) { const sph = new SpHelloBar({ throttle: _.throttle }); // extend SpHelloBar sph.after("beforeInit", function() { checkStorage.call(sph); }); sph.after("onClose", function() { disableViaStorage.call(sph); }); getRandomHelloBar($, () => sph.init()); })(window, jQuery, _);

As you can see, it’s similar to the basic.js script but this time we make use of the after() method to hook onto the beforeInit and onClose stages. The checkStorage and disableViaStorage functions shown below are simple wrappers around local storage. The various lifecycle stages are all documented on GitHub.

如您所见,它类似于basic.js脚本,但是这次我们使用after()方法来挂钩beforeInit和onClose阶段。 下面显示的checkStorage和disableViaStorage函数是本地存储的简单包装。 各个生命周期阶段都记录在GitHub上 。

const CAN_LOCAL_STORAGE = !!(window && window.localStorage); const EXPIRE_DAYS = 14; const STORAGE_KEY = 'SpHelloBarDisabled'; function futureDaysInMs(days = EXPIRE_DAYS) { return Date.now() + (1000 * 60 * 60 * 24 * days); } export function checkStorage() { // hello bar may be disabled for the number of days set in EXPIRE_DAYS when user manually closed the bar const expiry = (CAN_LOCAL_STORAGE) ? window.localStorage.getItem(STORAGE_KEY) : null; if (expiry !== null) { const now = Date.now(); if(expiry > now) { this.isEnabled = false; } else { window.localStorage.removeItem(STORAGE_KEY); } } } export function disableViaStorage() { if (CAN_LOCAL_STORAGE) window.localStorage.setItem(STORAGE_KEY, futureDaysInMs()); }

The plugin doesn’t assume that everyone will want to use one of our basic scripts or basic CSS but it’s nice to make that easily enabled via the Admin UI. This can be easily done by adding a couple more settings to our options page.

该插件并不假定每个人都希望使用我们的基本脚本或基本CSS之一,但可以通过Admin UI轻松启用它。 只需在我们的选项页面中添加几个设置即可轻松完成此操作。

public static function admin_init() { register_setting(self::PLUGIN_NAME.'-settings-group', self::PLUGIN_NAME.'-enabled'); register_setting(self::PLUGIN_NAME.'-settings-group', self::PLUGIN_NAME.'-basic-js'); register_setting(self::PLUGIN_NAME.'-settings-group', self::PLUGIN_NAME.'-load-css'); register_setting(self::PLUGIN_NAME.'-settings-group', self::PLUGIN_NAME.'-ads', '\SitePoint\RandomHelloBar::sanitize_ads'); add_settings_section(self::PLUGIN_NAME.'-section-one', 'Settings', '\SitePoint\RandomHelloBar::section_one_help', self::PLUGIN_NAME); add_settings_field(self::PLUGIN_NAME.'-enabled', 'Enabled', function() { $setting = esc_attr(self::get_option('enabled')); include dirname( __FILE__ ).'/../views/admin/enabled-fields.php'; }, self::PLUGIN_NAME, self::PLUGIN_NAME.'-section-one'); add_settings_field(self::PLUGIN_NAME.'-basic-js', 'Enqueue Basic JS', function() { $setting = esc_attr(self::get_option('basic-js')); include dirname( __FILE__ ).'/../views/admin/basic-js-fields.php'; }, self::PLUGIN_NAME, self::PLUGIN_NAME.'-section-one'); add_settings_field(self::PLUGIN_NAME.'-load-css', 'Enqueue Basic CSS', function() { $setting = esc_attr(self::get_option('load-css')); include dirname( __FILE__ ).'/../views/admin/load-css-fields.php'; }, self::PLUGIN_NAME, self::PLUGIN_NAME.'-section-one'); add_settings_section(self::PLUGIN_NAME.'-section-two', 'Hello Bar Ads', '\SitePoint\RandomHelloBar::section_two_help', self::PLUGIN_NAME); add_settings_section(self::PLUGIN_NAME.'-field-two', null, '\SitePoint\RandomHelloBar::ad_fields', self::PLUGIN_NAME); }

Then updating public_actions to enqueue them if appropriate.

然后在适当时更新public_actions以使其入队。

public static function public_actions() { if (!\SitePoint\RandomHelloBar::get_option('enabled')) return; add_action('wp_enqueue_scripts', '\SitePoint\RandomHelloBar::enqueuePublicAssets'); add_action('wp_ajax_nopriv_get_random_hello_bar', '\SitePoint\RandomHelloBar::get_random_bar'); add_action('wp_ajax_get_random_hello_bar', '\SitePoint\RandomHelloBar::get_random_bar'); } public static function enqueuePublicAssets() { $basic_js = \SitePoint\RandomHelloBar::get_option('basic-js'); if (in_array($basic_js, array('basic', 'basicStorge'))) { wp_enqueue_script( self::PLUGIN_NAME.'-basic-script', plugins_url('../../public/js/'.$basic_js.'.js' , __FILE__), array('jquery', 'underscore') ); wp_localize_script( self::PLUGIN_NAME.'-basic-script', 'ajax_object', array('ajax_url' => admin_url( 'admin-ajax.php' )) ); } if(\SitePoint\RandomHelloBar::get_option('load-css')) { wp_enqueue_style( self::PLUGIN_NAME.'-basic-css', plugins_url( '../../public/css/basic.css' , __FILE__ ) ); } }

自己做 (Make It Your Own)

While the basic scripts provided with the plugin are quite useable, the real value comes in customizing it to suit your needs. What follows are just a few suggestions of what’s possible.

尽管该插件随附的基本脚本非常有用,但真正的价值在于根据您的需求对其进行自定义。 以下只是对可能情况的一些建议。

仅在指示器存在时加载 (Only Load if Indicator Present)

One potential issue with the basic script provided is that it will load the Random Hello Bar on all pages and that may not be what you want. If you alter your WordPress theme, to add .enableSpHelloBar to the main element in your single.php post template, for example, you could use the following script and only have the Random Hello Bar on particular post pages.

提供的基本脚本的一个潜在问题是,它将在所有页面上加载随机Hello Bar,而这可能不是您想要的。 例如,如果更改WordPress主题, .enableSpHelloBar将.enableSpHelloBar添加到single.php帖子模板的主要元素中,则可以使用以下脚本,并且在特定帖子页面上仅具有随机Hello Bar。

import SpHelloBar from "./SpHelloBar"; import getRandomHelloBar from "./helpers/getRandomHelloBar"; import "../css/basic.css"; (function(window, $, _) { if (!document.getElementsByClassName('enableSpHelloBar').length) return; const sph = new SpHelloBar({ throttle: _.throttle }); getRandomHelloBar($, () => sph.init()); })(window, jQuery, _);

追踪 (Tracking)

Another common use case is to track the use of components in the page. The following script makes use of the onToggle and onClick event hooks to track when the Random Hello Bar is first displayed in the page and when its link is clicked.

另一个常见的用例是跟踪页面中组件的使用。 以下脚本利用onToggle和onClick事件挂钩来跟踪何时在页面中首次显示随机Hello Bar以及何时单击其链接。

import SpHelloBar from "./SpHelloBar"; import getRandomHelloBar from "./helpers/getRandomHelloBar"; import trackEvent from './helpers/trackEvent'; import "../css/basic.css"; (function(window, $, _) { const sph = new SpHelloBar({ throttle: _.throttle }); // extend SpHelloBar sph.after('onClick', function() { trackEvent.call(sph, 'Click'); }); sph.after('onToggle', function() { trackEvent.call(sph, 'Impression'); }); getRandomHelloBar($, () => sph.init()); })(window, jQuery, _); export default function trackEvent (label) { // only track impressions once if (!this.impressionTracked && this.isShown && label == 'Impression') { this.impressionTracked = true; } else if(this.isShown && label == 'Impression') { return; } // check for the Google Analytics global var if (typeof(ga) == 'undefined') return; ga('send', 'event', 'SP Hello Bar', label, { 'nonInteraction': true }); }

随机Hello Bar触发器 (Random Hello Bar Trigger)

By default the Random Hello Bar displays once the page is scrolled down 300px. The following script shows how you can add a custom data attribute to an element elsewhere on the page and use the element to determine the point at which the Random Hello Bar displays. For instance, you may add the attribute to an element after the main post body.

默认情况下,页面向下滚动300px后,将显示随机Hello Bar。 以下脚本显示了如何向页面上其他位置的元素添加自定义数据属性,以及如何使用该元素确定显示随机Hello Bar的点。 例如,您可以将属性添加到主体后的元素。

import SpHelloBar from "./SpHelloBar"; import getRandomHelloBar from "./helpers/getRandomHelloBar"; import "../css/basic.css"; (function(window, $, _) { let targetOffset = 300; if(document.querySelector('[data-hellobar="trigger"]')) targetOffset = document.querySelector('[data-hellobar="trigger"]').offsetTop; const sph = new SpHelloBar({ targetOffset, throttle: _.throttle }); getRandomHelloBar($, () => sph.init()); })(window, jQuery, _);

固定位置标题 (Fixed Position Header)

The navigation menus (the header) on SitePoint are statically positioned so they scroll up and down with the page content. Not all sites are set up that way. For example the SitePoint Forums have a fixed position header. It remains fixed at the top of the page as the content scrolls up and down.

SitePoint上的导航菜单(标题)是静态放置的 ,因此它们随页面内容上下滚动。 并非所有站点都以这种方式设置。 例如, SitePoint论坛具有固定位置的标题。 内容上下滚动时,它固定在页面顶部。

The fix is very simple. The Random Hello Bar works by positioning itself above the top of the screen (a negative top value) when hidden and then changing that top value to zero, which is the top off the screen when visible. To allow for a fixed header you’d simply adjust the value of top for the header’s height.

解决方法非常简单。 随机Hello Bar的工作原理是:隐藏时将其自身置于屏幕顶部上方(负的顶部值),然后将该顶部值更改为零,即可见时位于屏幕顶部的顶部。 要允许固定的标头,您只需调整top的值以适合标头的高度。

.SpHelloBar { ... &.u-show { top: 56px; } }

结论 (Conclusion)

The SitePoint Random Hello Bar is a handy plugin that is ready to go straight out of the box but can quickly and easily be customised to suit the unique needs of your site. We hope you enjoy it, and feel free to ask any questions in the comments!

SitePoint Random Hello Bar是一个方便使用的插件,可以直接使用,但可以快速,轻松地进行自定义以满足您网站的独特需求。 我们希望您喜欢它,并随时在评论中提出任何问题!

翻译自: https://www.sitepoint.com/sitepoint-random-hello-bar-wordpress-plugin/

最新回复(0)