From 6cef03593b1861fba7d4d24758729deb2b617b58 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Mon, 26 Jan 2015 19:42:43 -0500 Subject: [PATCH 01/18] Initial refactoring of admin.php --- admin.php | 215 ++++++++++++++++++++++++++---------------------------- 1 file changed, 103 insertions(+), 112 deletions(-) diff --git a/admin.php b/admin.php index 6e38dd1..0a0cd27 100644 --- a/admin.php +++ b/admin.php @@ -1,122 +1,113 @@ '.__('Settings').''; - } - - return $links; +function optimizely_admin_warnings() { + if ( ! get_option( 'optimizely_project_code' ) && ! isset( $_POST['submit'] ) ) : + ?> +
+

+ authenticate and choose a project to begin using Optimizely on your site.', 'optimizely' ), 'admin.php?page=optimizely-config') ?> +

+
+

Settings saved.

"; - - } - - include(dirname( __FILE__ ) . '/config.php'); - +function optimizely_admin_menu() { + add_menu_page( __( 'Optimizely', 'optimizely' ), __( 'Optimizely', 'optimizely' ), 'manage_options', 'optimizely-config', 'optimizely_conf', plugin_dir_url( __FILE__ ) . 'images/optimizely-icon.png' ); } +add_action( 'admin_menu', 'optimizely_admin_menu' ); -function optimizely_admin_warnings() { - if ( !get_option('optimizely_project_code') && !isset($_POST['submit']) ) { - function optimizely_warning() { - echo " -

".__('Optimizely is almost ready.')." ".sprintf(__('You must authenticate and choose a project to begin using Optimizely on your site.'), "admin.php?page=optimizely-config")."

"; - } - add_action('admin_notices', 'optimizely_warning'); - return; - } +function optimizely_plugin_action_links( $links, $file ) { + if ( $file == plugin_basename( dirname(__FILE__) . '/optimizely.php' ) ) { + $links[] = '' . __( 'Settings', 'optimizely' ) . ''; + } + + return $links; } +add_filter( 'plugin_action_links', 'optimizely_plugin_action_links', 10, 2 ); -function optimizely_admin_menu() { - add_menu_page( __('Optimizely'), __('Optimizely'), 'manage_options', 'optimizely-config', 'optimizely_conf',plugin_dir_url( __FILE__ ).'images/optimizely-icon.png'); -} +function optimizely_conf() { + global $optimizely_nonce, $DEFAULT_VARIATION_TEMPLATE; + + if ( isset( $_POST['submit'] ) ) { + if ( ! current_user_can ('manage_options') ) { + die( __( 'Cheatin’ uh?', 'optimizely' ) ); + } + + check_admin_referer( $optimizely_nonce ); + + $token = sanitize_text_field( $_POST['token'] ); + $project_id = sanitize_text_field( $_POST['project_id'] ); + $num_variations = sanitize_text_field( $_POST['num_variations'] ); + $optimizely_post_types = array_map( $_POST['optimizely_post_types'], 'sanitize_text_field' ); + $optimizely_visitor_count = sanitize_text_field( $_POST['optimizely_visitor_count'] ); + $project_name = sanitize_text_field( stripcslashes( $_POST['project_name'] ) ); + $project_code = sanitize_text_field( stripcslashes( $_POST['project_code'] ) ); + $variation_template = sanitize_text_field( stripcslashes( $_POST['variation_template' ] ) ); + + if ( empty( $token ) ) { + delete_option( 'optimizely_token' ); + } else { + update_option( 'optimizely_token', $token ); + } + + if ( empty( $project_id ) ) { + delete_option( 'optimizely_project_id' ); + } else { + update_option( 'optimizely_project_id', $project_id ); + } + + if ( empty( $num_variations ) ) { + delete_option( 'num_variations' ); + } else { + update_option( 'num_variations', $num_variations ); + } + + if ( empty( $optimizely_post_types ) ) { + update_option( 'optimizely_post_types', '' ); + } else { + $post_type_string = ''; + foreach ( $optimizely_post_types as $post_type ) { + $post_type_string = $post_type_string . $post_type . ','; + } + update_option( 'optimizely_post_types', rtrim( $post_type_string, ',' ) ); + } + + if ( empty( $optimizely_visitor_count ) ) { + delete_option( 'optimizely_visitor_count'); + } else { + update_option( 'optimizely_visitor_count', $optimizely_visitor_count ); + } + + if ( empty( $project_name ) ) { + delete_option( 'optimizely_project_name' ); + } else { + update_option( 'optimizely_project_name', $project_name ); + } + + if ( empty( $project_code ) ) { + delete_option( 'optimizely_project_code' ); + } else { + update_option( 'optimizely_project_code', $project_code ); + } + + if ( empty( $variation_template ) ) { + update_option( 'optimizely_variation_template', $DEFAULT_VARIATION_TEMPLATE ); + } else { + update_option( 'optimizely_variation_template', $variation_template ); + } + + ?> +

.

+ Date: Mon, 26 Jan 2015 19:45:36 -0500 Subject: [PATCH 02/18] Fix tabbing and spacing in main plugin file --- optimizely.php | 63 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/optimizely.php b/optimizely.php index 61c2ce9..c2636ff 100644 --- a/optimizely.php +++ b/optimizely.php @@ -6,7 +6,7 @@ /* Plugin Name: Optimizely Plugin URI: http://wordpress.org/extend/plugins/optimizely/ -Description: Simple, fast, and powerful. Optimizely is a dramatically easier way for you to improve your website through A/B testing. Create an experiment in minutes with our easy-to-use visual interface with absolutely no coding or engineering required. Convert your website visitors into customers and earn more revenue today! To get started: 1) Click the "Activate" link to the left of this description, 2) Sign up for an Optimizely account, and 3) Go to the settings page, and enter your Optimizely project code. +Description: Simple, fast, and powerful. Optimizely is a dramatically easier way for you to improve your website through A/B testing. Create an experiment in minutes with our easy-to-use visual interface with absolutely no coding or engineering required. Convert your website visitors into customers and earn more revenue today! To get started: 1 ) Click the "Activate" link to the left of this description, 2 ) Sign up for an Optimizely account, and 3 ) Go to the settings page, and enter your Optimizely project code. Author: Arthur Suermondt, Jon Noronha, Brad Taylor Version: 3.0.0 Author URI: http://www.optimizely.com/ @@ -29,42 +29,41 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ if ( is_admin() ) { - require_once dirname( __FILE__ ) . '/admin.php'; - require_once dirname( __FILE__ ) . '/edit.php'; - wp_enqueue_script('jquery'); - wp_enqueue_script('jquery-ui-core'); - wp_enqueue_script('jquery-ui-tabs'); - wp_enqueue_script('jquery-ui-progressbar'); - wp_enqueue_script('jquery-ui-tooltip'); - wp_enqueue_script('optimizely_api', plugins_url('optimizely.js', __FILE__)); - wp_enqueue_script('optimizely_editor', plugins_url('edit.js', __FILE__)); - wp_localize_script('optimizely_editor', 'wpAjaxUrl', admin_url('admin-ajax.php')); - wp_enqueue_script('optimizely_config', plugins_url('config.js', __FILE__)); - wp_enqueue_script('optimizely_results', plugins_url('results.js', __FILE__)); - wp_enqueue_style('jquery_ui_styles', plugins_url('jquery-ui.css', __FILE__)); - wp_enqueue_style('font_awesome_styles',plugins_url('font-awesome.min.css', __FILE__)); - wp_enqueue_style('optimizely_styles', plugins_url('style.css', __FILE__)); + require_once dirname( __FILE__ ) . '/admin.php'; + require_once dirname( __FILE__ ) . '/edit.php'; + wp_enqueue_script( 'jquery' ); + wp_enqueue_script( 'jquery-ui-core' ); + wp_enqueue_script( 'jquery-ui-tabs' ); + wp_enqueue_script( 'jquery-ui-progressbar' ); + wp_enqueue_script( 'jquery-ui-tooltip' ); + wp_enqueue_script( 'optimizely_api', plugins_url( 'optimizely.js', __FILE__ ) ); + wp_enqueue_script( 'optimizely_editor', plugins_url( 'edit.js', __FILE__ ) ); + wp_localize_script( 'optimizely_editor', 'wpAjaxUrl', admin_url( 'admin-ajax.php' ) ); + wp_enqueue_script( 'optimizely_config', plugins_url( 'config.js', __FILE__ ) ); + wp_enqueue_script( 'optimizely_results', plugins_url( 'results.js', __FILE__ ) ); + wp_enqueue_style( 'jquery_ui_styles', plugins_url( 'jquery-ui.css', __FILE__ ) ); + wp_enqueue_style( 'font_awesome_styles',plugins_url( 'font-awesome.min.css', __FILE__ ) ); + wp_enqueue_style( 'optimizely_styles', plugins_url( 'style.css', __FILE__ ) ); } +$DEFAULT_VARIATION_TEMPLATE = '$( ".post-$POST_ID .entry-title a" ).text( "$NEW_TITLE" );'; +add_option( 'optimizely_variation_template', $DEFAULT_VARIATION_TEMPLATE ); +$DEFAULT_VISITOR_COUNT = 10316; +add_option( 'optimizely_post_types', 'post' ); +add_option( 'optimizely_visitor_count', $DEFAULT_VISITOR_COUNT ); +add_option( 'num_variations', 2 ); - $DEFAULT_VARIATION_TEMPLATE = '$(".post-$POST_ID .entry-title a").text("$NEW_TITLE");'; - add_option('optimizely_variation_template', $DEFAULT_VARIATION_TEMPLATE); - $DEFAULT_VISITOR_COUNT = 10316; - add_option('optimizely_post_types', 'post'); - add_option('optimizely_visitor_count', $DEFAULT_VISITOR_COUNT); - add_option('num_variations', 2); +add_option( 'optimizely_launch_auto', false ); - add_option('optimizely_launch_auto', false); +// Force Optimizely to load first in the head tag +add_action( 'wp_head', 'add_optimizely_script', -1000 ); - // Force Optimizely to load first in the head tag - add_action('wp_head', 'add_optimizely_script', -1000); - - function add_optimizely_script() { - echo get_option('optimizely_project_code'); - } +function add_optimizely_script() { + echo get_option( 'optimizely_project_code' ); +} - function can_create_experiments() { - return get_option('optimizely_token'); - } +function can_create_experiments() { + return get_option( 'optimizely_token' ); +} ?> \ No newline at end of file From 9afd10a55b2668ba426902bb5b90da510c2fc410 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Tue, 24 Feb 2015 18:26:40 -0500 Subject: [PATCH 03/18] Additional formatting tweaks to admin.php --- admin.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/admin.php b/admin.php index 0a0cd27..d9a7704 100644 --- a/admin.php +++ b/admin.php @@ -11,7 +11,7 @@ function optimizely_admin_warnings() { ?>

- authenticate and choose a project to begin using Optimizely on your site.', 'optimizely' ), 'admin.php?page=optimizely-config') ?> + authenticate and choose a project to begin using Optimizely on your site.', 'optimizely' ), 'admin.php?page=optimizely-config' ) ?>

' . __( 'Settings', 'optimizely' ) . ''; + if ( $file == plugin_basename( dirname( __FILE__ ) . '/optimizely.php' ) ) { + $links[] = '' . esc_html__( 'Settings', 'optimizely' ) . ''; } return $links; @@ -37,7 +37,7 @@ function optimizely_conf() { global $optimizely_nonce, $DEFAULT_VARIATION_TEMPLATE; if ( isset( $_POST['submit'] ) ) { - if ( ! current_user_can ('manage_options') ) { + if ( ! current_user_can( 'manage_options' ) ) { die( __( 'Cheatin’ uh?', 'optimizely' ) ); } From be367d9073b9ca65f9948e019ef2a7574f4316c3 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Tue, 24 Feb 2015 20:09:37 -0500 Subject: [PATCH 04/18] Consolidating constants, removing unsafe saving of a script tag value, adding i18n compatibility --- admin.php | 54 +++++++----- config.php | 225 ++++++++++++++++++++++++------------------------- edit.php | 18 ++-- optimizely.php | 58 ++++++++++--- 4 files changed, 192 insertions(+), 163 deletions(-) diff --git a/admin.php b/admin.php index d9a7704..8a0f466 100644 --- a/admin.php +++ b/admin.php @@ -1,29 +1,43 @@
-

- authenticate and choose a project to begin using Optimizely on your site.', 'optimizely' ), 'admin.php?page=optimizely-config' ) ?> +

+ %s %s.', + esc_html__( 'You must', 'optimizely' ), + esc_html__( 'authenticate and choose a project', 'optimizely' ), + esc_html__( 'to begin using Optimizely on your site', 'optimizely' ) + ); + ?>

' . esc_html__( 'Settings', 'optimizely' ) . ''; @@ -33,23 +47,23 @@ function optimizely_plugin_action_links( $links, $file ) { } add_filter( 'plugin_action_links', 'optimizely_plugin_action_links', 10, 2 ); +/** + * Update the Optimizely configuration. + */ function optimizely_conf() { - global $optimizely_nonce, $DEFAULT_VARIATION_TEMPLATE; - if ( isset( $_POST['submit'] ) ) { if ( ! current_user_can( 'manage_options' ) ) { die( __( 'Cheatin’ uh?', 'optimizely' ) ); } - check_admin_referer( $optimizely_nonce ); + check_admin_referer( OPTIMIZELY_NONCE ); $token = sanitize_text_field( $_POST['token'] ); $project_id = sanitize_text_field( $_POST['project_id'] ); $num_variations = sanitize_text_field( $_POST['num_variations'] ); - $optimizely_post_types = array_map( $_POST['optimizely_post_types'], 'sanitize_text_field' ); + $optimizely_post_types = array_map( 'sanitize_text_field', $_POST['optimizely_post_types'] ); $optimizely_visitor_count = sanitize_text_field( $_POST['optimizely_visitor_count'] ); $project_name = sanitize_text_field( stripcslashes( $_POST['project_name'] ) ); - $project_code = sanitize_text_field( stripcslashes( $_POST['project_code'] ) ); $variation_template = sanitize_text_field( stripcslashes( $_POST['variation_template' ] ) ); if ( empty( $token ) ) { @@ -81,7 +95,7 @@ function optimizely_conf() { } if ( empty( $optimizely_visitor_count ) ) { - delete_option( 'optimizely_visitor_count'); + delete_option( 'optimizely_visitor_count' ); } else { update_option( 'optimizely_visitor_count', $optimizely_visitor_count ); } @@ -92,14 +106,8 @@ function optimizely_conf() { update_option( 'optimizely_project_name', $project_name ); } - if ( empty( $project_code ) ) { - delete_option( 'optimizely_project_code' ); - } else { - update_option( 'optimizely_project_code', $project_code ); - } - if ( empty( $variation_template ) ) { - update_option( 'optimizely_variation_template', $DEFAULT_VARIATION_TEMPLATE ); + update_option( 'optimizely_variation_template', OPTIMIZELY_DEFAULT_VARIATION_TEMPLATE ); } else { update_option( 'optimizely_variation_template', $variation_template ); } diff --git a/config.php b/config.php index 94aee40..8e9fc8f 100644 --- a/config.php +++ b/config.php @@ -1,128 +1,121 @@
- +
+
    +
  • +
  • +
+
+

+
- - }); - -
- -
-

Wordpress Headline Results This is a list of all of the experiments that are running headline tests.

+
+
+

+
+
+

+
+

+
+

+

Please Note: Only experiements created through Wordpress will be displayed here. Experiments created directly in Optimizely will not be displayed here.', 'optimizely' ) ?>

+
+
+
+
+

+
+
+ +

+

Optimizely optimizely.com

+

+

optimizely.com/account.

+

+ +
+ +

+ -
+

+ + +

+

+
-
- -
-
-

Ready to launch! These experiments experiments are ready to launch!

+

+

+ true + ); + + $selected_post_types_str = get_option( 'optimizely_post_types', array() ); + $selected_post_types = ( ! empty( $selected_post_types_str ) ) ? explode( ',', $selected_post_types_str ) : array(); + $post_types = get_post_types( $args, 'objects' ); + foreach( $post_types as $post_type ) { + if ( 'page' != $post_type->name && 'attachment' != $post_type->name ) { + if ( in_array( $post_type->name, $selected_post_types ) ) { + echo ' ' . esc_attr( $post_type->label ) . '
'; + } else { + echo ' ' . esc_attr( $post_type->label ) . '
'; + } + } + } + ?> +

+

-
-
-

Not ready to launch These experiments still need a few more visitors before we can declare a winner

+ -
-
- Loading Results.....
- - -
+

Y

-
-

No results!

-

A headline experiement must be created in Wordpress before any results will be displayed here. Please create a new post with multiple headlines, publish the post, and start the experiment. Once the experiment is created and running it will display the results here. Please Note: Only experiements created through Wordpress will be displayed here. Experiments created directly in Optimizely will not be displayed here.

-
-
+

+

-
-
-

-
- - -

About Optimizely

-

Simple, fast, and powerful. Optimizely is a dramatically easier way for you to improve your website through A/B testing. Create an experiment in minutes with absolutely no coding or engineering required. Convert your website visitors into customers and earn more revenue: create an account at optimizely.com and start A/B testing today!

-

Optimizely API tokens

-

Once you create an account, you can find your API Token on your account page at optimizely.com/account. -

- -
- -

- - - -

Choose a Project

- - -

Optimizely will add the following project code to your page automatically:

- + -

Post Types

-

Please choose the post types you would like to conduct A/B testing on

- true - ); - $selected_post_types = explode(',',get_option('optimizely_post_types')); - $post_types = get_post_types($args, 'objects' ); - foreach($post_types as $post_type){ - if($post_type->name != 'page' && $post_type->name != 'attachment'){ - if(in_array($post_type->name,$selected_post_types)){ - echo ' ' . $post_type->label . '
'; - }else{ - echo ' ' . $post_type->label . '
'; - } - - } - } - ?> +

+

+ +
+ -

Variation Code

-

Optimizely will use this variation code to change headlines on your site. We've provided code that works with the default theme, but you might want to add or change it to work with your themes and plugins.

- - - -

You can use the variables $POST_ID, $OLD_TITLE, and $NEW_TITLE in your code.

- -

Number of Variations to test

-

Place a number in the text box below. This will be the additional number of variations a user can test per post.

- - - -

Powered Testing

-

By default we use a sample size of 10,316 per variation to be considered powered. This is based on a baseline conversion rate of 3%, a minimum relative change of 20%, 80% statistical power, 95% statistical significance and 1-tailed test. If you need to change this number use the Sample Size Calculator to adjust to your needs

- Visitors Per Variation -
- - -

- - - - -
-
-
+

+ + +
+
+
diff --git a/edit.php b/edit.php index 66b94d6..55de7e2 100644 --- a/edit.php +++ b/edit.php @@ -1,14 +1,12 @@ "; } - if ( can_create_experiments() ) { + if ( optimizely_can_create_experiments() ) { echo $contents; ?> diff --git a/optimizely.php b/optimizely.php index c2636ff..ea4fbec 100644 --- a/optimizely.php +++ b/optimizely.php @@ -28,9 +28,23 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +// Constants for default settings +define( 'OPTIMIZELY_DEFAULT_VARIATION_TEMPLATE', '$( ".post-$POST_ID .entry-title a" ).text( "$NEW_TITLE" );' ); +define( 'OPTIMIZELY_DEFAULT_VISITOR_COUNT', 10316 ); +define( 'OPTIMIZELY_NUM_VARIATIONS', 2 ); +define( 'OPTIMIZELY_NONCE', 'optimizely-update-code' ); + +// Include files are only required on the admin dashboard if ( is_admin() ) { - require_once dirname( __FILE__ ) . '/admin.php'; - require_once dirname( __FILE__ ) . '/edit.php'; + require_once( dirname( __FILE__ ) . '/admin.php' ); + require_once( dirname( __FILE__ ) . '/edit.php' ); +} + +/** + * Enqueues Optimizely scripts required by the admin dashboard. + */ +function optimizely_enqueue_scripts() { wp_enqueue_script( 'jquery' ); wp_enqueue_script( 'jquery-ui-core' ); wp_enqueue_script( 'jquery-ui-tabs' ); @@ -42,28 +56,44 @@ wp_enqueue_script( 'optimizely_config', plugins_url( 'config.js', __FILE__ ) ); wp_enqueue_script( 'optimizely_results', plugins_url( 'results.js', __FILE__ ) ); wp_enqueue_style( 'jquery_ui_styles', plugins_url( 'jquery-ui.css', __FILE__ ) ); - wp_enqueue_style( 'font_awesome_styles',plugins_url( 'font-awesome.min.css', __FILE__ ) ); + wp_enqueue_style( 'font_awesome_styles', plugins_url( 'font-awesome.min.css', __FILE__ ) ); wp_enqueue_style( 'optimizely_styles', plugins_url( 'style.css', __FILE__ ) ); } +add_action( 'admin_enqueue_scripts', 'optimizely_enqueue_scripts' ); -$DEFAULT_VARIATION_TEMPLATE = '$( ".post-$POST_ID .entry-title a" ).text( "$NEW_TITLE" );'; -add_option( 'optimizely_variation_template', $DEFAULT_VARIATION_TEMPLATE ); -$DEFAULT_VISITOR_COUNT = 10316; +add_option( 'optimizely_variation_template', OPTIMIZELY_DEFAULT_VARIATION_TEMPLATE ); add_option( 'optimizely_post_types', 'post' ); -add_option( 'optimizely_visitor_count', $DEFAULT_VISITOR_COUNT ); +add_option( 'optimizely_visitor_count', OPTIMIZELY_DEFAULT_VISITOR_COUNT ); add_option( 'num_variations', 2 ); - add_option( 'optimizely_launch_auto', false ); -// Force Optimizely to load first in the head tag -add_action( 'wp_head', 'add_optimizely_script', -1000 ); +/** + * Force Optimizely to load first in the head tag. + */ +function optimizely_add_script() { + $project_code = get_option( 'optimizely_project_code' ); + if ( ! empty( $project_code ) ) { + // This cannot be escaped since optimizely_generate_script generates a script tag. + // It is however fully escaped within the function. + echo optimizely_generate_script( $project_code ); + } +} +add_action( 'wp_head', 'optimizely_add_script', -1000 ); -function add_optimizely_script() { - echo get_option( 'optimizely_project_code' ); +/** + * Generates the Optimizely script tag. + * @param int $project_code + * @return string + */ +function optimizely_generate_script() { + return ''; } -function can_create_experiments() { - return get_option( 'optimizely_token' ); +/** + * Check capabilites for creating experiments. + */ +function optimizely_can_create_experiments() { + return get_option( 'optimizely_token', false ); } ?> \ No newline at end of file From 89268850b8b04339149221b0e74c323d44123d28 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Tue, 24 Feb 2015 21:27:33 -0500 Subject: [PATCH 05/18] Updated edit.php, additional cleanup and phpdoc --- admin.php | 16 ++-- config.php | 10 +-- edit.php | 223 ++++++++++++++++++++++++++++++------------------- optimizely.php | 10 +-- 4 files changed, 154 insertions(+), 105 deletions(-) diff --git a/admin.php b/admin.php index 8a0f466..858e590 100644 --- a/admin.php +++ b/admin.php @@ -1,8 +1,10 @@ true ); - $selected_post_types_str = get_option( 'optimizely_post_types', array() ); + $selected_post_types_str = get_option( 'optimizely_post_types', 'post' ); $selected_post_types = ( ! empty( $selected_post_types_str ) ) ? explode( ',', $selected_post_types_str ) : array(); $post_types = get_post_types( $args, 'objects' ); foreach( $post_types as $post_type ) { @@ -97,20 +97,20 @@

- + -

Y

+

- +


- +

diff --git a/edit.php b/edit.php index 55de7e2..8e72dcd 100644 --- a/edit.php +++ b/edit.php @@ -1,117 +1,166 @@ ID, "post_title$i", true); - $contents .= "

"; - $contents .= ""; - $contents .= ""; - $contents .= "

"; - } - - if ( optimizely_can_create_experiments() ) { - echo $contents; - - ?> - -
- Start Experiment -

- View on Optimizely -

Status: ID, 'optimizely_experiment_status', true); ?> -
- Results: View Results

-
- - - - - - - - -

Please configure your API credentials in the Optimizely settings page.

+

%s', + esc_html__( 'Please configure your API credentials in the', 'optimizely' ), + esc_url( menu_page_url( 'optimizely-config', false ) ), + esc_html__( 'Optimizely settings page', 'optimizely' ) + ); ?>.

ID, $meta_key, true ); + echo '

'; + echo sprintf( + '', + esc_attr( $meta_key ), + esc_html__( 'Variation', 'optimizely' ), + absint( $i ) + ); + echo sprintf( + '', + esc_attr( $meta_key ), + esc_attr( $meta_key ), + esc_html__( 'Title', 'optimizely' ), + absint( $i ), + esc_attr( $titles[ $i ] ) + ); + echo '

'; + } + ?> +
+ +
+
+ +

+ +

: ID, 'optimizely_experiment_status', true ) ) ?> +
+ :

+
+ + + + + + + (int)$post_id, - 'post_title' => $winning_var_title - ); +/** + * Update the post title on an AJAX request for the winner of the test. + * @param int $post_id + */ +function optimizely_update_post_title() { + if ( isset( $_REQUEST['post_id'] ) && isset( $_REQUEST['title'] ) ) { + $post_id = absint( $_REQUEST['post_id'] ); + $winning_var_title = sanitize_text_field( $_REQUEST['title'] ); + + wp_update_post( array( + 'ID' => $post_id, + 'post_title' => $winning_var_title + ) ); + } + + exit; +} +add_action( 'wp_ajax_update_post_title', 'optimizely_update_post_title' ); - wp_update_post( $my_post ); +/** + * Check if this is a post type that uses Optimizely. + * @param string $post_type + * @return boolean + */ +function optimizely_is_post_type_enabled( $post_type ) { + $selected_post_types = explode( ',', get_option( 'optimizely_post_types' ) ); + if ( ! empty( $selected_post_types ) && in_array( $post_type, $selected_post_types ) ) { + return true; + } else { + return false; + } } +/** + * Return the meta key format used for all post title variations. + * @param int $i + * @return string + */ +function optimizely_meta_key( $i ) { + return 'post_title' . absint( $i ); +} ?> \ No newline at end of file diff --git a/optimizely.php b/optimizely.php index ea4fbec..7545638 100644 --- a/optimizely.php +++ b/optimizely.php @@ -61,20 +61,14 @@ function optimizely_enqueue_scripts() { } add_action( 'admin_enqueue_scripts', 'optimizely_enqueue_scripts' ); -add_option( 'optimizely_variation_template', OPTIMIZELY_DEFAULT_VARIATION_TEMPLATE ); -add_option( 'optimizely_post_types', 'post' ); -add_option( 'optimizely_visitor_count', OPTIMIZELY_DEFAULT_VISITOR_COUNT ); -add_option( 'num_variations', 2 ); -add_option( 'optimizely_launch_auto', false ); - /** * Force Optimizely to load first in the head tag. */ function optimizely_add_script() { $project_code = get_option( 'optimizely_project_code' ); if ( ! empty( $project_code ) ) { - // This cannot be escaped since optimizely_generate_script generates a script tag. - // It is however fully escaped within the function. + // This cannot be escaped since optimizely_generate_script returns a script tag. + // The output of this script is fully escaped within the function below. echo optimizely_generate_script( $project_code ); } } From 29136808597344bdfe60ff29772d2d49f12e5d01 Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 25 Feb 2015 11:49:56 -0500 Subject: [PATCH 06/18] Reformated edit.js, moved JS call to a ready action, fixed button display --- edit.js | 423 +++++++++++++++++++++++++------------------------ edit.php | 1 - optimizely.php | 11 +- style.css | 70 ++++---- 4 files changed, 258 insertions(+), 247 deletions(-) diff --git a/edit.js b/edit.js index 55f3ac6..4c41f8f 100644 --- a/edit.js +++ b/edit.js @@ -1,209 +1,214 @@ -function optimizelyEditPage() { - var $ = jQuery; - - // Initialize data from the input fields - var projectId = $('#optimizely_project_id').val(); - var optly = new OptimizelyAPI($("#optimizely_token").val()); - if(!!$("#optimizely_experiment_id").val()){ - optly.get('experiments/'+$("#optimizely_experiment_id").val(),function(response){ - optly.experiment = response; - showExperiment(optly.experiment); - }); - }else{ - optly.experiment = { - id: $("#optimizely_experiment_id").val(), - status: $("#optimizely_experiment_status").val() - } - $('#optimizely_not_created').show(); - $('#optimizely_created').hide(); - } - - // On click, run the createExperiment function - $('#optimizely_create').click(function(){ - createExperiment(); - }); - - // Then, handle starts and pauses on the experiment - $('#optimizely_toggle_running').click(function(){ - if (optly.experiment.status == "Running") { - pauseExperiment(optly.experiment); - } else { - startExperiment(optly.experiment); - } - }); - - // Render the experiment's state on the page - function showExperiment(experiment) { - // ID and links - $("#optimizely_experiment_id").val(experiment.id); - $('#optimizely_view').attr('href','https://www.optimizely.com/edit?experiment_id=' + experiment.id); - - // Status and buttons - $("#optimizely_experiment_status").val(experiment.status); - $('#optimizely_experiment_status_text').text(experiment.status); - if (experiment.status == "Running") { - $('#optimizely_toggle_running').text('Pause Experiment'); - } else { - $('#optimizely_toggle_running').text('Start Experiment'); - } - - // Hide create button, show status - - $('#optimizely_not_created').hide(); - $('#optimizely_created').show(); - - // Update Wordpress backend w/ experiment data - var data = { - action: "update_experiment_meta", - post_id: $('#post_ID').val(), - optimizely_experiment_id: experiment.id, - optimizely_experiment_status: experiment.status - }; - - $('.optimizely_variation').each(function(index, input) { - data[$(input).attr('name')] = $(input).val(); - }); - $.post(wpAjaxUrl, data); - } - - /* - This function creates an experiment by providing a description based on the post's title and an edit_url based on the permalink of the Wordpress post. We send these as a POST request and register a callback to run the onExperimentCreated function when it completes. - */ - function createExperiment() { - $('#optimizely_create').text('Creating...'); - experiment = {}; - post_id = $('#post_ID').val(); - experiment.description = "Wordpress ["+post_id+"]: " + $('#title').val(); - experiment.edit_url = $('#sample-permalink').text(); - var loc = document.createElement('a'); - loc.href = experiment.edit_url; - var urlTargetdomain = loc.hostname; - experiment.url_conditions = [ - { - "match_type": "substring", - "value": urlTargetdomain - } - ]; - optly.post('projects/' + projectId + '/experiments', experiment, onExperimentCreated); - } - - /* - The experiment we created has two built-in variations, but now we need to add a third and update the content. Since we're adding a variation, we also need to calculate the traffic weight to use for each one. Once we've done this, we'll call the createVariation function explained below. - - Our experiment comes with an Engagement goal, but we'll also add one to measure views to the post. - - */ - function onExperimentCreated(experiment) { - // Pause for 200ms so that the experiment is guarenteed to be created before editing and adding variations - - setTimeout(function () { - optly.experiment = experiment; - var variations = $('.optimizely_variation').filter(function(){return $(this).val().length > 0}) - - // Set variation weights - var numVariations = variations.length + 1; - var variationWeight = Math.floor(10000 / numVariations); - var leftoverWeight = 10000 - variationWeight*numVariations; - - // Create variations - variations.each(function(index, input) { - var weight = variationWeight; - createVariation(experiment, index + 1, $(input).val(), weight); - }); - - // Update original with correct traffic allocation - var origVariationWeight = {"weight":variationWeight + (leftoverWeight > 0 ? leftoverWeight : 0)}; - optly.patch('variations/' + experiment.variation_ids[0], origVariationWeight, checkExperimentReady); - - // Create goal - createGoal(experiment); - }, 200); - - } - - /* - We create a pageview goal that measures how many times the post is viewed. We add one url, the permalink, and use the substring match type. We also set "addable" to false so that the goal won't clog up the list of goals for other experiments. - - Finally, we associate the goal with the experiment we just created by adding the experiment's id to experiment_ids. We POST the goal to the projects/{id}/goals endpoint to create it. - */ - function createGoal(experiment) { - - var goal = { - goal_type: 3, // pageview goal - title: "Views to page", - urls: [$('#sample-permalink').text()], - url_match_types: [4], // substring - addable: false, // don't clog up the goal list - experiment_ids: [experiment.id] - } - - optly.post('projects/' + experiment.project_id + '/goals/', goal, checkExperimentReady); - - } - - /* - To create a variation, we first generate the variation code. We use a template based on the Wordpress theme, and then we drop in the values for our variation. The result would be: - - $(".post-27 .entry-title a").text("Alternate Title #1"); - - Once we've generated this variation code, we include it in the js_component parameter of our API request. We also add a variation title and weight. - - In this example, we have two alternate headlines plus an original. When we created the experiment, it also came with two variations that were created automatically. We'll leave variation 0 alone as the original, update variation 1 to use the first alternate headline, and create a new variation 2 with the second alternate headline. - */ - - function createVariation(experiment, index, newTitle, weight) { - - // Generate variation code - var variationTemplate = $('#optimizely_variation_template').val(); - var postId = $('#post_ID').val(); - var originalTitle = $('#title').val(); - var code = variationTemplate - .replace(/\$OLD_TITLE/g, originalTitle) - .replace(/\$NEW_TITLE/g, newTitle) - .replace(/\$POST_ID/g, postId); - - // Request data - var variation = { - "description": newTitle, - "js_component": code, - "weight": weight, - } - - // Update variation #1, create the others - if (index == 1) { - optly.patch('variations/' + experiment.variation_ids[1], variation, checkExperimentReady); - } else { - optly.post('experiments/' + experiment.id + '/variations', variation, checkExperimentReady); - } - - } - - /* - Once all the PUT and POST requests have returned, we're done! At this point, we can let the user know that the experiment is created and ready. - */ - function checkExperimentReady(response) { - if (optly.outstandingRequests == 0) { - showExperiment(optly.experiment); - } - } - - /* - To start a pause an experiment, we just need to change it's status to running. The patch method GETs the experiment metadata, changes the specified fields, and PUTs the object back to Optimizely. - */ - function startExperiment(experiment) { - $('#optimizely_toggle_running').text('Starting...'); - optly.patch('experiments/' + experiment.id, {'status': 'Running'}, function(response) { - optly.experiment = response; - showExperiment(optly.experiment); - }); - } - - function pauseExperiment(experiment) { - $('#optimizely_toggle_running').text('Pausing...'); - optly.patch('experiments/' + experiment.id, {'status': 'Paused'}, function(response) { - optly.experiment = response; - showExperiment(optly.experiment); - }); - } - -} \ No newline at end of file +( function( $ ) { + + function optimizelyEditPage() { + // Initialize data from the input fields + var projectId = $( '#optimizely_project_id' ).val(); + var optly = new OptimizelyAPI( $( '#optimizely_token' ).val() ); + + if ( !! $( '#optimizely_experiment_id' ).val() ) { + optly.get( 'experiments/' + $( '#optimizely_experiment_id' ).val(), function( response ) { + optly.experiment = response; + showExperiment( optly.experiment ); + }); + } else { + optly.experiment = { + id: $( '#optimizely_experiment_id' ).val(), + status: $( '#optimizely_experiment_status' ).val() + } + $( '#optimizely_not_created' ).show(); + $( '#optimizely_created' ).hide(); + } + + // On click, run the createExperiment function + $( '#optimizely_create' ).click( function() { + createExperiment(); + }); + + // Then, handle starts and pauses on the experiment + $( '#optimizely_toggle_running' ).click( function() { + if ( optly.experiment.status == 'Running' ) { + pauseExperiment( optly.experiment ); + } else { + startExperiment( optly.experiment ); + } + }); + + // Render the experiment's state on the page + function showExperiment( experiment ) { + // ID and links + $( '#optimizely_experiment_id' ).val( experiment.id ); + $( '#optimizely_view' ).attr( 'href', 'https://www.optimizely.com/edit?experiment_id=' + experiment.id ); + + // Status and buttons + $( '#optimizely_experiment_status' ).val( experiment.status ); + $( '#optimizely_experiment_status_text' ).text( experiment.status ); + if ( experiment.status == 'Running' ) { + $( '#optimizely_toggle_running' ).text( 'Pause Experiment' ); + } else { + $( '#optimizely_toggle_running' ).text( 'Start Experiment' ); + } + + // Hide create button, show status + $( '#optimizely_not_created' ).hide(); + $( '#optimizely_created' ).show(); + + // Update Wordpress backend w/ experiment data + var data = { + action: 'update_experiment_meta', + post_id: $( '#post_ID' ).val(), + optimizely_experiment_id: experiment.id, + optimizely_experiment_status: experiment.status + }; + + $( '.optimizely_variation' ).each( function( index, input ) { + data[ $( input ).attr( 'name' ) ] = $( input ).val(); + }); + $.post( wpAjaxUrl, data ); + } + + // This function creates an experiment by providing a description based on the post's title and an edit_url based on the permalink of the Wordpress post. We send these as a POST request and register a callback to run the onExperimentCreated function when it completes. + function createExperiment() { + $( '#optimizely_create' ).text( 'Creating...' ); + experiment = {}; + post_id = $( '#post_ID' ).val(); + experiment.description = 'Wordpress [' + post_id + ']: ' + $( '#title' ).val(); + experiment.edit_url = $( '#sample-permalink' ).text(); + var loc = document.createElement( 'a' ); + loc.href = experiment.edit_url; + var urlTargetdomain = loc.hostname; + experiment.url_conditions = [ + { + 'match_type': 'substring', + 'value': urlTargetdomain + } + ]; + optly.post( 'projects/' + projectId + '/experiments', experiment, onExperimentCreated ); + } + + /* + The experiment we created has two built-in variations, but now we need to add a third and update the content. + Since we're adding a variation, we also need to calculate the traffic weight to use for each one. + Once we've done this, we'll call the createVariation function explained below. + Our experiment comes with an Engagement goal, but we'll also add one to measure views to the post. + */ + function onExperimentCreated( experiment ) { + // Pause for 200ms so that the experiment is guarenteed to be created before editing and adding variations + setTimeout( function () { + optly.experiment = experiment; + var variations = $( '.optimizely_variation' ).filter( function() { + return $( this ).val().length > 0 + }); + + // Set variation weights + var numVariations = variations.length + 1; + var variationWeight = Math.floor( 10000 / numVariations ); + var leftoverWeight = 10000 - ( variationWeight * numVariations ); + + // Create variations + variations.each( function( index, input ) { + var weight = variationWeight; + createVariation( experiment, index + 1, $( input ).val(), weight ); + }); + + // Update original with correct traffic allocation + var origVariationWeight = { 'weight': variationWeight + ( leftoverWeight > 0 ? leftoverWeight : 0 ) }; + optly.patch( 'variations/' + experiment.variation_ids[0], origVariationWeight, checkExperimentReady ); + + // Create goal + createGoal( experiment ); + }, 200 ); + } + + /* + We create a pageview goal that measures how many times the post is viewed. + We add one url, the permalink, and use the substring match type. + We also set 'addable' to false so that the goal won't clog up the list of goals for other experiments. + Finally, we associate the goal with the experiment we just created by adding the experiment's id to experiment_ids. + We POST the goal to the projects/{id}/goals endpoint to create it. + */ + function createGoal( experiment ) { + var goal = { + goal_type: 3, // pageview goal + title: 'Views to page', + urls: [ $( '#sample-permalink' ).text() ], + url_match_types: [4], // substring + addable: false, // don't clog up the goal list + experiment_ids: [ experiment.id ] + } + + optly.post( 'projects/' + experiment.project_id + '/goals/', goal, checkExperimentReady ); + } + + + /* + To create a variation, we first generate the variation code. + We use a template based on the Wordpress theme, and then we drop in the values for our variation. The result would be: + $( '.post-27 .entry-title a' ).text( 'Alternate Title #1' ); + Once we've generated this variation code, we include it in the js_component parameter of our API request. + We also add a variation title and weight. + In this example, we have two alternate headlines plus an original. + When we created the experiment, it also came with two variations that were created automatically. + We'll leave variation 0 alone as the original, update variation 1 to use the first alternate headline, and create a new variation 2 with the second alternate headline. + */ + function createVariation( experiment, index, newTitle, weight ) { + // Generate variation code + var variationTemplate = $( '#optimizely_variation_template' ).val(); + var postId = $( '#post_ID' ).val(); + var originalTitle = $( '#title' ).val(); + var code = variationTemplate + .replace( /\$OLD_TITLE/g, originalTitle ) + .replace( /\$NEW_TITLE/g, newTitle ) + .replace( /\$POST_ID/g, postId ); + + // Request data + var variation = { + 'description': newTitle, + 'js_component': code, + 'weight': weight, + } + + // Update variation #1, create the others + if ( index == 1 ) { + optly.patch( 'variations/' + experiment.variation_ids[1], variation, checkExperimentReady ); + } else { + optly.post( 'experiments/' + experiment.id + '/variations', variation, checkExperimentReady ); + } + } + + /* + Once all the PUT and POST requests have returned, we're done! + At this point, we can let the user know that the experiment is created and ready. + */ + function checkExperimentReady( response ) { + if ( 0 == optly.outstandingRequests ) { + showExperiment( optly.experiment ); + } + } + + /* + To start a pause an experiment, we just need to change it's status to running. + The patch method GETs the experiment metadata, changes the specified fields, and PUTs the object back to Optimizely. + */ + function startExperiment( experiment ) { + $( '#optimizely_toggle_running' ).text( 'Starting...' ); + optly.patch( 'experiments/' + experiment.id, { 'status': 'Running' }, function( response ) { + optly.experiment = response; + showExperiment( optly.experiment ); + }); + } + + function pauseExperiment( experiment ) { + $( '#optimizely_toggle_running' ).text( 'Pausing...' ); + optly.patch( 'experiments/' + experiment.id, { 'status': 'Paused' }, function( response ) { + optly.experiment = response; + showExperiment( optly.experiment ); + }); + } + + } + + $( document ).ready( function() { + optimizelyEditPage(); + }); + +})( jQuery ); \ No newline at end of file diff --git a/edit.php b/edit.php index 8e72dcd..89c3c1a 100644 --- a/edit.php +++ b/edit.php @@ -77,7 +77,6 @@ function optimizely_title_variations_render( $post ) { - h2{ +#optimizely-tabs #stillwaiting > h2 { padding: 0px 0px 10px 10px; border-left: solid 1px #1964AF; border-bottom: solid 1px #1964AF; @@ -182,14 +186,14 @@ } -#optimizely-tabs #stillwaiting > h2 > span, #optimizely-tabs #tabs-1 > h2 > span{ +#optimizely-tabs #stillwaiting > h2 > span, #optimizely-tabs #tabs-1 > h2 > span { font-size: 13px; float: right; } -#noresults{ +#noresults { display:none; } From 6a3ccb1177f01c30e3065faabcb2a3e76e14a60a Mon Sep 17 00:00:00 2001 From: bcampeau Date: Wed, 25 Feb 2015 12:09:38 -0500 Subject: [PATCH 07/18] Finished cleaning up config.js, fixed issue with JS code generator, reduced inline JS for config.php --- config.js | 106 ++++++++++++++++++++++++++++--------------------- config.php | 7 +--- edit.js | 2 +- optimizely.php | 2 +- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/config.js b/config.js index 3db6eca..a852c86 100644 --- a/config.js +++ b/config.js @@ -1,47 +1,63 @@ -// Javascript for plugin settings page - -function optimizelyConfigPage() { - var $ = jQuery; - - /* - - AUTHENTICATION W/ OPTIMIZELY - - When the user presses the button, we call the GET projects/ endpoint to list out all the projects in their account. For each project, we show its name in the dropdown and store its ID in the value attribute for submission to a form. - - */ - - $("button#connect_optimizely").click(function(event) { - event.preventDefault(); - $("#project_id").html(""); - - optly = new OptimizelyAPI($("#token").val()); - - optly.get('projects', function(response) { - $("#project_id").empty(); - - $.each(response, function(key, val) { - $("#project_id").append(""); - }); - - $("#project_id").change(); // update project code w/ the default value - }); - - /* - - CHOOSING A PROJECT - - When the user selects a project from the dropdown, we populate the project code box with the Optimizely snippet for that project ID. - - */ - $('#project_id').change(function() { - var id = $('#project_id').val(); - var name = $('#project_id option:selected').text(); - var project_code = ''; - $('#project_code').text(project_code); - $('#project_name').val(name); - }); - }); +( function( $ ) { + + // Javascript for plugin settings page + function optimizelyConfigPage() { + + /* + AUTHENTICATION W/ OPTIMIZELY + When the user presses the button, we call the GET projects/ endpoint to list out all the projects in their account. + For each project, we show its name in the dropdown and store its ID in the value attribute for submission to a form. + */ + + $( 'button#connect_optimizely' ).click( function( event ) { + event.preventDefault(); + $loading = $( '