Skip to content

Commit

Permalink
Merge pull request #319 from x-team/issue-309
Browse files Browse the repository at this point in the history
Issue 309: Theme Header and Background changes are not being logged
  • Loading branch information
frankiejarrett committed Mar 11, 2014
2 parents 666f2c0 + e366c3f commit 58fb855
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 43 deletions.
47 changes: 47 additions & 0 deletions classes/connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,51 @@ public static function delayed_log_commit() {
}
}

/**
* Compare two values and return changed keys if they are arrays
* @param mixed $old_value Value before change
* @param mixed $new_value Value after change
* @return array
*/
public static function get_changed_keys( $old_value, $new_value ) {
if ( ! is_array( $old_value ) && ! is_array( $new_value ) ) {
return array();
}

if ( ! is_array( $old_value ) ) {
return array_keys( $new_value );
}

if ( ! is_array( $new_value ) ) {
return array_keys( $old_value );
}

$diff = array_udiff_assoc(
$old_value,
$new_value,
function( $value1, $value2 ) {
return maybe_serialize( $value1 ) !== maybe_serialize( $value2 );
}
);

$result = array_keys( $diff );

// find unexisting keys in old or new value
$common_keys = array_keys( array_intersect_key( $old_value, $new_value ) );
$unique_keys_old = array_values( array_diff( array_keys( $old_value ), $common_keys ) );
$unique_keys_new = array_values( array_diff( array_keys( $new_value ), $common_keys ) );
$result = array_merge( $result, $unique_keys_old, $unique_keys_new );

// remove numeric indexes
$result = array_filter(
$result,
function( $value ) {
// check if is not valid number (is_int, is_numeric and ctype_digit are not enough)
return (string) (int) $value !== (string) $value;
}
);

return array_values( array_unique( $result ) );
}

}
189 changes: 146 additions & 43 deletions connectors/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ public static function register() {

add_action( 'admin_head', array( __CLASS__, 'highlight_field' ) );
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_jquery_color' ) );
add_action( sprintf( 'update_option_theme_mods_%s', get_option( 'stylesheet' ) ), array( __CLASS__, 'log_theme_modification' ), 10, 2 );
}

/**
* @action update_option_theme_mods_{name}
*/
public static function log_theme_modification( $old_value, $new_value ) {
self::callback_updated_option( 'theme_mods', $old_value, $new_value );
}

/**
Expand Down Expand Up @@ -73,17 +81,72 @@ public static function get_action_labels() {
*/
public static function get_context_labels() {
return array(
'settings' => __( 'Settings', 'stream' ),
'general' => __( 'General', 'stream' ),
'writing' => __( 'Writing', 'stream' ),
'reading' => __( 'Reading', 'stream' ),
'discussion' => __( 'Discussion', 'stream' ),
'media' => __( 'Media', 'stream' ),
'permalink' => __( 'Permalinks', 'stream' ),
'wp_stream' => __( 'Stream', 'stream' ),
'settings' => __( 'Settings', 'stream' ),
'general' => __( 'General', 'stream' ),
'writing' => __( 'Writing', 'stream' ),
'reading' => __( 'Reading', 'stream' ),
'discussion' => __( 'Discussion', 'stream' ),
'media' => __( 'Media', 'stream' ),
'permalink' => __( 'Permalinks', 'stream' ),
'wp_stream' => __( 'Stream', 'stream' ),
'custom_background' => __( 'Custom Background', 'stream' ),
'custom_header' => __( 'Custom Header', 'stream' ),
);
}

/**
* Return context by option name and key
*
* @return string Context slug
*/
public static function get_context_by_key( $option_name, $key ) {
$contexts = array(
'theme_mods' => array(
'custom_background' => array(
'background_image',
'background_position_x',
'background_repeat',
'background_attachment',
'background_color',
),
'custom_header' => array(
'header_image',
'header_textcolor',
),
),
);

if ( isset( $contexts[ $option_name ] ) ) {
foreach ( $contexts[ $option_name ] as $context => $keys ) {
if ( in_array( $key, $keys ) ) {
return $context;
}
}
}

return false;
}

/**
* Find out if the option key should be ignored and not logged
*
* @return bool Whether option key is ignored or not
*/
public static function is_key_ignored( $option_name, $key ) {
$ignored = array(
'theme_mods' => array(
'background_image_thumb',
'header_image_data',
),
);

if ( isset( $ignored[ $option_name ] ) ) {
return in_array( $key, $ignored[ $option_name ] );
}

return false;
}

/**
* Return translated labels for all default Settings fields found in WordPress.
*
Expand Down Expand Up @@ -184,7 +247,17 @@ public static function enqueue_jquery_color() {
*/
public static function get_serialized_field_label( $option_name, $field_key ) {
$labels = array(
// to be updated
'theme_mods' => array(
// Custom Background
'background_image' => __( 'Background Image', 'stream' ),
'background_position_x' => __( 'Background Position', 'stream' ),
'background_repeat' => __( 'Background Repeat', 'stream' ),
'background_attachment' => __( 'Background Attachment', 'stream' ),
'background_color' => __( 'Background Color', 'stream' ),
// Custom Header
'header_image' => __( 'Header Image', 'stream' ),
'header_textcolor' => __( 'Text Color', 'stream' ),
),
);

/**
Expand Down Expand Up @@ -213,22 +286,61 @@ public static function get_serialized_field_label( $option_name, $field_key ) {
public static function action_links( $links, $record ) {
$context_labels = self::get_context_labels();

$rules = array(
'background_header' => array(
'menu_slug' => 'themes.php',
'submenu_slug' => function( $record ) {
return str_replace( '_', '-', $record->context );
},
'url' => function( $rule, $record ) {
return add_query_arg( 'page', $rule['submenu_slug']( $record ), admin_url( $rule['menu_slug'] ) );
},
'applicable' => function( $submenu, $record ) {
return in_array( $record->context, array( 'custom_header', 'custom_background' ) );
}
),
'general' => array(
'menu_slug' => 'options-general.php',
'submenu_slug' => function( $record ) {
return sprintf( 'options-%s.php', $record->context );
},
'url' => function( $rule, $record ) {
return admin_url( $rule['submenu_slug']( $record ) );
},
'applicable' => function( $submenu, $record ) {
return ! empty( $submenu['options-general.php'] );
},
),
);

if ( 'settings' !== $record->context && in_array( $record->context, array_keys( $context_labels ) ) ) {
global $submenu;

if ( ! empty( $submenu['options-general.php'] ) ) {
$submenu_slug = sprintf( 'options-%s.php', $record->context );
$applicable_rules = array_filter(
$rules,
function( $rule ) use ( $submenu, $record ) {
return call_user_func( $rule['applicable'], $submenu, $record );
}
);

if ( ! empty( $applicable_rules ) ) {
// The first applicable rule wins
$rule = array_shift( $applicable_rules );
$menu_slug = $rule['menu_slug'];
$submenu_slug = $rule['submenu_slug']( $record );
$url = $rule['url']( $rule, $record );

$found_submenus = wp_list_filter(
$submenu['options-general.php'],
$submenu[ $menu_slug ],
array( 2 => $submenu_slug )
);

if ( ! empty( $found_submenus ) ) {
$target_submenu = array_pop( $found_submenus );
list( $menu_title, $capability ) = $target_submenu;

if ( current_user_can( $target_submenu[1] ) ) {
if ( current_user_can( $capability ) ) {
$text = sprintf( __( 'Edit %s Settings', 'stream' ), $context_labels[ $record->context ] );
$url = admin_url( $submenu_slug );
$field_name = get_stream_meta( $record->ID, 'option', true );

if ( '' !== $field_name ) {
Expand Down Expand Up @@ -288,72 +400,63 @@ public static function callback_update_option_tag_base( $old_value, $value ) {
* @action updated_option
*/
public static function callback_updated_option( $option, $old_value, $value ) {
global $new_whitelist_options, $whitelist_options;
global $whitelist_options, $new_whitelist_options;

if ( 0 === strpos( $option, '_transient_' ) ) {
return;
}

$options = array_merge(
(array) $whitelist_options,
$new_whitelist_options,
(array) $new_whitelist_options,
array( 'permalink' => self::$permalink_options )
);

foreach ( $options as $key => $opts ) {
if ( in_array( $option, $opts ) ) {
$current_key = $key;
$context = $key;
break;
}
}

if ( ! isset( $current_key ) ) {
$current_key = 'settings';
if ( ! isset( $context ) ) {
$context = 'settings';
}

$changed_options = array();

if ( is_array( $old_value ) && is_array( $value ) ) {
$changed_keys = array();

// Added keys
$changed_keys = array_merge( $changed_keys, array_keys( array_diff_key( $value, $old_value ) ) );

// Deleted keys
$changed_keys = array_merge( $changed_keys, array_keys( array_diff_key( $old_value, $value ) ) );

// array_diff_assoc is not sufficient
foreach ( array_diff( array_keys( $value ), $changed_keys ) as $option_key ) {
if ( $value[ $option_key ] !== $old_value[ $option_key ] ) {
$changed_keys[] = $option_key;
if ( is_array( $old_value ) || is_array( $value ) ) {
foreach ( self::get_changed_keys( $old_value, $value ) as $field_key ) {
if ( ! self::is_key_ignored( $option, $field_key ) ) {
$key_context = self::get_context_by_key( $option, $field_key );
$changed_options[] = array(
'label' => self::get_serialized_field_label( $option, $field_key ),
'option' => $option,
'context' => ( false !== $key_context ? $key_context : $context ),
// Prevent fatal error when saving option as array
'old_value' => isset( $old_value[ $field_key ] ) ? maybe_serialize( $old_value[ $field_key ] ) : null,
'value' => isset( $value[ $field_key ] ) ? maybe_serialize( $value[ $field_key ] ) : null,
);
}
}

foreach ( $changed_keys as $field_key ) {
$changed_options[] = array(
'label' => self::get_serialized_field_label( $option, $field_key ),
'option' => $current_key,
// Prevent fatal error when saving option as array
'old_value' => isset( $old_value[ $field_key ] ) ? maybe_serialize( $old_value[ $field_key ] ) : null,
'value' => isset( $value[ $field_key ] ) ? maybe_serialize( $value[ $field_key ] ) : null,
);
}
} else {
$changed_options[] = array(
'label' => self::get_field_label( $option ),
'option' => $option,
'context' => $context,
// Prevent fatal error when saving option as array
'old_value' => maybe_serialize( $old_value ),
'value' => maybe_serialize( $value ),
);
}

foreach ( $changed_options as $properties ) {
$context = $properties['context'];
self::log(
__( '"%s" setting was updated', 'stream' ),
$properties,
null,
array( $current_key => 'updated' )
array( $context => 'updated' )
);
}
}
Expand Down

0 comments on commit 58fb855

Please sign in to comment.