wo_meta = new WOMeta( AdCommander::ns() );
$this->nonce = $this->nonce( basename( __FILE__ ), AdCommander::posttype_ad() );
add_action( 'admin_enqueue_scripts', array( $this, 'maybe_delete_meta_box_order' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'edit_form_after_title', array( $this, 'posttype_meta_boxes' ), 100 );
add_action( 'save_post_' . AdCommander::posttype_ad(), array( $this, 'save_posted_metadata' ), 10, 2 );
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
// Add info to the new columns.
add_action( 'manage_' . AdCommander::posttype_ad() . '_posts_custom_column', array( $this, 'manage_ad_column_data' ), 10, 3 );
add_filter( 'manage_edit-' . AdCommander::posttype_ad() . '_columns', array( $this, 'manage_ad_columns' ) );
/**
* Targeting
*/
$this->admin_targeting()->hooks();
}
/**
* Sets the current meta if it is not yet set.
*
* @return mixed
*/
private function current_meta() {
global $post;
if ( ! $this->current_meta && isset( $post->ID ) ) {
$this->current_meta = $this->wo_meta->get_post_meta( $post->ID, AdPostMeta::post_meta_keys() );
}
return $this->current_meta;
}
/**
* Create any needed admin notices.
*
* @return void
*/
public function admin_notices() {
$this->notice_unfiltered_html();
$this->notice_invalid_ad();
}
/**
* Create notice if unfiltered HTML disabled.
*
* @return void
*/
private function notice_unfiltered_html() {
if ( $this->is_screen( array( AdCommander::posttype_ad(), AdCommander::posttype_placement(), 'edit-' . AdCommander::tax_group() ) ) && ! self::allow_unfiltered_html() ) {
$screen = get_current_screen();
if ( $screen->base === 'edit-tags' ) {
return;
}
?>
is_screen( array( AdCommander::posttype_ad() ) ) && ( $message = $this->invalid_ad_message() ) !== false ) {
?>
ID ) || ! $this->has_ad_saved() || ! isset( $post->post_type ) || $post->post_type !== AdCommander::posttype_ad() ) {
return false;
}
$ad_type = $this->wo_meta->get_value( $this->current_meta(), 'adtype' );
if ( $ad_type === 'bannerad' && ! has_post_thumbnail( $post->ID ) ) {
$message = __( 'This ad will not display because it does not yet have an image.', 'ad-commander' );
} elseif ( ( $ad_type === 'textcode' && ! $this->wo_meta->get_value( $this->current_meta(), 'adcontent_text' ) ) ||
( $ad_type === 'richcontent' && ! $this->wo_meta->get_value( $this->current_meta(), 'adcontent_rich' ) ) ) {
$message = __( 'This ad will not display because it does not yet have any content.', 'ad-commander' );
}
return $message;
}
/**
* Possibly delete a user's meta box order due to an ACF conflict.
*
* @return void
*/
public function maybe_delete_meta_box_order() {
/**
* User meta box order doesn't work right with our meta box setup if ACF is active.
* Not enqueuing anything here, but want to delete this early on in the page load.
* Without this, sorted meta boxes end up at the bottom.
*/
if ( $this->is_screen( array( AdCommander::posttype_ad() ) ) ) {
$meta_box_order = get_user_meta( get_current_user_id(), 'meta-box-order_' . AdCommander::posttype_ad(), true );
if ( $meta_box_order && isset( $meta_box_order['acf_after_title'] ) ) {
delete_user_meta( get_current_user_id(), 'meta-box-order_' . AdCommander::posttype_ad() );
}
}
}
/**
* Enqueue scripts if we're on a screen that needs them.
*
* @return void
*/
public function admin_enqueue_scripts() {
if ( $this->is_screen( array( AdCommander::posttype_ad() ) ) ) {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'jquery-ui-core' );
wp_enqueue_script( 'jquery-ui-datepicker' );
$this->enqueue_jquery_ui_styles();
$settingrestrict_handle = $this->enqueue_setting_restrict();
$repeater_handle = $this->wo_meta->repeater_enqueue();
$targeting_handle = $this->admin_targeting()->enqueue();
$deps = array(
'jquery',
'jquery-ui-core',
'jquery-ui-datepicker',
$settingrestrict_handle,
$repeater_handle,
$targeting_handle,
);
$handle = Util::ns( 'adpost' );
wp_register_script(
$handle,
AdCommander::assets_url() . 'js/ad-post.js',
$deps,
AdCommander::version(),
array( 'in_footer' => true )
);
wp_enqueue_script( $handle );
Util::enqueue_script_data(
$handle,
array(
'media_rest_url' => get_rest_url( null, 'wp/v2/media/' ),
)
);
}
}
/**
* Check if user has meta boxes (other than slug) hidden.
* This could maybe happen because of another plugin? This is more precautionary than anything.
*
* NOTE: This function is not currently in use. If we hide Screen Options in the future, may reactivate.
*
* @return void
*/
public function set_user_metaboxes() {
$current_screen = get_current_screen();
if ( isset( $current_screen->id ) && $current_screen->id === AdCommander::posttype_ad() ) {
$user_id = get_current_user_id();
if ( ! $user_id ) {
return;
}
$meta_key_hidden = 'metaboxhidden_' . AdCommander::posttype_ad();
$hidden = get_user_meta( $user_id, $meta_key_hidden, true );
$should_hide = array( 'slugdiv' );
if ( $hidden !== $should_hide ) {
update_user_meta( $user_id, $meta_key_hidden, $should_hide );
}
}
}
/**
* Hook function for creating/editing meta boxes for our post type.
*
* @return void
*/
public function posttype_meta_boxes() {
$current_screen = get_current_screen();
if ( isset( $current_screen->id ) && $current_screen->id === AdCommander::posttype_ad() ) {
/**
* Insert our nonce field
*/
$this->nonce_field( $this->nonce );
/**
* Create meta boxes.
*/
global $wp_meta_boxes;
/**
* Settings
*/
add_meta_box( 'adcmdrsettingsdiv', __( 'Ad Settings & Usage', 'ad-commander' ), array( $this, 'adcmdrsettings_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
/**
* Banner Ad
*/
add_filter( 'postbox_classes_' . AdCommander::posttype_ad() . '_postimagediv', array( $this, 'add_bannerad_metabox_classes' ) );
add_filter( 'admin_post_thumbnail_html', array( $this, 'adcmdrbanner_meta_box' ), 10, 2 );
if ( isset( $wp_meta_boxes[ AdCommander::posttype_ad() ]['side']['low']['postimagediv'] ) ) {
/**
* If the meta boxes were manually sorted, this won't fire.
* Becomes a bit of a UI issue if using ACF and manually sorting...
*/
$featured_image_meta = $wp_meta_boxes[ AdCommander::posttype_ad() ]['side']['low']['postimagediv'];
if ( isset( $featured_image_meta['title'] ) ) {
remove_meta_box( 'postimagediv', AdCommander::posttype_ad(), 'side' );
add_meta_box( 'postimagediv', $featured_image_meta['title'], 'post_thumbnail_meta_box', AdCommander::posttype_ad(), 'normal', 'high' );
}
}
/**
* Text/Code meta box
*/
add_filter( 'postbox_classes_' . AdCommander::posttype_ad() . '_adcmdrtextcodediv', array( $this, 'add_textcode_metabox_classes' ) );
add_filter( 'postbox_classes_' . AdCommander::posttype_ad() . '_adcmdrrichcontentdiv', array( $this, 'add_richcontent_metabox_classes' ) );
add_meta_box( 'adcmdrtextcodediv', __( 'Text or Code Ad', 'ad-commander' ), array( $this, 'adcmdrtextcode_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
add_meta_box( 'adcmdrrichcontentdiv', __( 'Rich Content Ad', 'ad-commander' ), array( $this, 'adcmdrrichcontent_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
/**
* Layout
*/
add_meta_box( 'adcmdrlayoutdiv', __( 'Layout', 'ad-commander' ), array( $this, 'adcmdrlayout_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
/**
* Targeting
*/
add_meta_box( 'adcmdrtargetingdiv', __( 'Targeting', 'ad-commander' ), array( $this, 'adcmdrtargeting_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
/**
* Expirations
*/
$expirations_title = __( 'Expirations', 'ad-commander' );
if ( ! ProBridge::instance()->is_pro_loaded() ) {
$expirations_title .= ProBridge::pro_label();
}
add_meta_box( 'adcmdrexpirationsdiv', $expirations_title, array( $this, 'adcmdrexpirations_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
/**
* Advanced
*/
add_meta_box( 'adcmdradvanceddiv', __( 'Advanced', 'ad-commander' ), array( $this, 'adcmdradvanced_meta_box' ), AdCommander::posttype_ad(), 'normal', 'high' );
/**
* Statistics
*/
add_meta_box( 'adcmdrreportdiv', __( 'Tracking', 'ad-commander' ), array( $this, 'adcmdrreport_meta_box' ), AdCommander::posttype_ad(), 'side', 'default' );
}
}
/**
* Add classes to a metbox.
*
* @param array $classes Current classes.
*
* @return array
*/
public function add_bannerad_metabox_classes( $classes ) {
array_push( $classes, 'adcmdr-mode-restrict adcmdr-mode-restrict--bannerad' );
return $classes;
}
/**
* Add classes to a metbox.
*
* @param array $classes Current classes.
*
* @return array
*/
public function add_textcode_metabox_classes( $classes ) {
array_push( $classes, 'adcmdr-mode-restrict adcmdr-mode-restrict--textcode' );
return $classes;
}
/**
* Add classes to a metbox.
*
* @param array $classes Current classes.
*
* @return array
*/
public function add_richcontent_metabox_classes( $classes ) {
array_push( $classes, 'adcmdr-mode-restrict adcmdr-mode-restrict--richcontent' );
return $classes;
}
/**
* Add fields to the Settings meta box.
*
* @return void
*/
public function adcmdrsettings_meta_box() {
$this->metaitem_addtype();
$this->metaitem_usage();
}
/**
* Add fields to the banner meta box.
* This filters the HTML in the Featured Image div, so it works a bit differently.
*
* @param string $content The current content.
* @param int $post_id The current post id.
*
* @return string
*/
public function adcmdrbanner_meta_box( $content, $post_id ) {
$content .= '';
// $content .= $this->metaitem_bannerurl();
$content .= $this->metaitem_display_size();
$content .= $this->metaitem_bannerurlsettings();
$content .= '
';
return $content;
}
/**
* Add fields to the Text/Code meta box.
*
* @return void
*/
public function adcmdrtextcode_meta_box() {
$this->metaitem_adcontent_textarea();
}
/**
* Add fields to the Rich Content meta box.
*
* @return void
*/
public function adcmdrrichcontent_meta_box() {
$this->metaitem_adcontent_richcontent();
}
/**
* Add fields to the Expirations meta box.
*
* @return void
*/
public function adcmdrexpirations_meta_box() {
$this->metaitem_expire_datetime();
$this->metaitem_expire_stats();
}
/**
* Add fields to the Reports meta box.
*
* @return void
*/
public function adcmdrreport_meta_box() {
$this->metaitem_tracking();
$this->metaitem_donottrack();
}
/**
* Add fields to the Layout meta box.
*
* @return void
*/
public function adcmdrlayout_meta_box() {
$this->info( __( "Apply layout settings to an individual ad. If this ad is used in a group, some of these settings will be ignored in favor of the group's layout.", 'ad-commander' ) );
$this->metaitem_ad_label();
$this->metaitem_responsive_adimages();
$this->metaitem_float();
$this->metaitem_margin();
$this->metaitem_custom_classes();
}
/**
* Add fields to the Targeting meta box.
*
* @return void
*/
public function adcmdrtargeting_meta_box() {
$this->metaitem_content_targeting();
}
/**
* Add fields to the Advanced meta box.
*
* @return void
*/
public function adcmdradvanced_meta_box() {
$this->metaitem_disable_consent();
$this->metaitem_additional_code();
}
/**
* HTML for targeting meta item.
*/
private function metaitem_content_targeting() {
$this->info( __( 'Only display this ad if certain conditions are met.', 'ad-commander' ) );
$this->admin_targeting()->metaitem_targeting( $this->wo_meta->get_value( $this->current_meta(), 'content_conditions' ) );
$this->admin_targeting()->metaitem_targeting( $this->wo_meta->get_value( $this->current_meta(), 'visitor_conditions' ), false, 'visitor' );
}
/**
* HTML/fields for Display Size meta.
*
* @return string
*/
private function metaitem_display_size() {
return '' . $this->message( __( 'Theme styles may override these settings.', 'ad-commander' ), array(), array( 'display' => false ) );
}
/**
* HTML/fields for Additional Code meta.
*/
private function metaitem_additional_code() {
?>
info( __( 'Javascript and CSS allowed (must include style or script tags). Use with caution and test your ad display and tracking.', 'ad-commander' ) );
Doc::doc_link( 'custom_code' );
?>
wo_meta->label( 'custom_code_before', __( 'Custom Code - Before Ad', 'ad-commander' ) ); ?>
wo_meta->textarea( 'custom_code_before', $this->wo_meta->get_value( $this->current_meta(), 'custom_code_before' ), array( 'rows' => 5 ) ); ?>
wo_meta->label( 'custom_code_after', __( 'Custom Code - After Ad', 'ad-commander' ) ); ?>
wo_meta->textarea( 'custom_code_after', $this->wo_meta->get_value( $this->current_meta(), 'custom_code_after' ), array( 'rows' => 5 ) ); ?>
wo_meta->label( 'disable_consent', __( 'Disable Consent Requirement', 'ad-commander' ) );
$this->wo_meta->checkbox( 'disable_consent', $this->wo_meta->get_value( $this->current_meta(), 'disable_consent' ) );
$this->wo_meta->label( 'disable_consent', __( 'Ignore site-wide setting and disable consent requirement for this ad.', 'ad-commander' ) );
$this->message( __( 'Note that this setting will be ignored if ad is used in a group or placement. You must disable consent for the entire group or placement instead.', 'ad-commander' ) );
?>
wo_meta->label( 'custom_classes', __( 'Custom Classes', 'ad-commander' ) );
$this->wo_meta->input( 'custom_classes', $this->wo_meta->get_value( $this->current_meta(), 'custom_classes' ), 'text' );
?>
is_pro_loaded();
$classes = array( 'expire_datetime', 'group' );
if ( $disabled ) {
$classes[] = 'disabled';
} else {
$info = __( "Expired ads will move to Draft status. Leave values blank to disable a feature. To schedule a start date, edit this Ad post's Publish date and time in the Publish settings.", 'ad-commander' );
$this->info( $info );
}
Doc::doc_link( 'expiring_ads' );
$this->message( __( 'Expire ad at the below date and time.', 'ad-commander' ) );
?>
is_pro_loaded();
$disabled_c = false;
$disabled_i = false;
$click_disabled = '';
$imp_disabled = '';
if ( ! $disabled ) {
if ( ! Tracking::instance()->should_track_local( 'clicks', false ) ) {
$disabled_c = true;
$click_disabled = __( 'Local click tracking is disabled.', 'ad-commander' );
}
if ( ! Tracking::instance()->should_track_local( 'impressions', false ) ) {
$disabled_i = true;
$imp_disabled = __( 'Local impression tracking is disabled.', 'ad-commander' );
}
if ( $this->wo_meta->get_value( $this->current_meta(), 'donottrack_c' ) ) {
$disabled_c = true;
if ( ! $click_disabled ) {
$click_disabled = __( 'Local click tracking is disabled for this ad.', 'ad-commander' );
}
}
if ( $this->wo_meta->get_value( $this->current_meta(), 'donottrack_i' ) ) {
$disabled_i = true;
if ( ! $imp_disabled ) {
$imp_disabled = __( 'Local impression tracking is disabled for this ad', 'ad-commander' );
}
}
}
$classes = array( 'expire_stats', 'divide' );
if ( $disabled ) {
$classes[] = 'disabled';
}
?>
wo_meta->label( 'adtype', __( 'Ad Type', 'ad-commander' ) );
$this->wo_meta->select(
'adtype',
AdPostMeta::ad_types(),
$this->wo_meta->get_value( $this->current_meta(), 'adtype' ),
array(
'empty_text' => __( 'Select an ad type', 'ad-commander' ),
)
);
Doc::doc_link( 'ad_type' );
?>
ID ) && $this->has_ad_saved() ) :
?>
wo_meta->label( 'responsive_banners', __( 'Responsive Ad Images', 'ad-commander' ) ); ?>
wo_meta->radiogroup( 'responsive_banners', $radios, $this->wo_meta->get_value( $this->current_meta(), 'responsive_banners', 'site_default' ) ); ?>
wo_meta->label( 'ad_label', __( 'Ad Label', 'ad-commander' ) ); ?>
wo_meta->radiogroup( 'ad_label', $radios, $this->wo_meta->get_value( $this->current_meta(), 'ad_label', 'site_default' ) ); ?>
';
$html .= '';
$html .= $this->wo_meta->label( 'bannerurl', __( 'Banner Link', 'ad-commander' ), array( 'display' => false ) );
$html .= $this->wo_meta->input(
'bannerurl',
$this->wo_meta->get_value( $this->current_meta(), 'bannerurl' ),
'url',
array(
'placeholder' => 'https:// ',
'display' => false,
)
);
$html .= '
';
$html .= '';
$html .= $this->wo_meta->label( 'newwindow', __( 'Open in a new window', 'ad-commander' ), array( 'display' => false ) );
$html .= $this->wo_meta->radiogroup( 'newwindow', $radios, $this->wo_meta->get_value( $this->current_meta(), 'newwindow', 'site_default' ), array( 'display' => false ) );
$html .= '
';
$html .= '';
$html .= '';
return $html;
}
/**
* HTML/fields for Content ad meta.
*/
private function metaitem_adcontent_textarea() {
?>
wo_meta->textarea( 'adcontent_text', $this->wo_meta->get_value( $this->current_meta(), 'adcontent_text' ) ); ?>
message( __( 'Paste your entire ad code here. Linebreaks will be removed from output. For text ads with linebreaks, use the Rich Content Editor.', 'ad-commander' ) ); ?>
wo_meta->get_value( $this->current_meta(), 'adcontent_rich' );
$editor_id = $this->wo_meta->make_key( 'adcontent_rich' );
$settings = array(
'wpautop' => true, // use wpautop?
'media_buttons' => true, // show insert/upload button(s)
'textarea_name' => $editor_id, // set the textarea name to something different, square brackets [] can be used here
'textarea_rows' => get_option( 'default_post_edit_rows', 10 ), // rows="..."
'tabindex' => '',
'editor_css' => '', // extra styles for both visual and HTML editors buttons,
'editor_class' => '', // add extra class(es) to the editor textarea
'teeny' => false, // output the minimal editor config used in Press This
'dfw' => false, // replace the default fullscreen with DFW (supported on the front-end in WordPress 3.4)
'tinymce' => true, // load TinyMCE, can be used to pass settings directly to TinyMCE using an array()
'quicktags' => true, // load Quicktags, can be used to pass settings directly to Quicktags using an array()
);
wp_editor( $content === null ? '' : $content, $editor_id, $settings );
?>
ID ) && $this->has_ad_saved() ) :
$reports = new AdminReports();
?>
wo_meta->message( $message, $args );
}
/**
* Check if this ad has saved previously.
*
* @return bool
*/
private function has_ad_saved() {
global $post;
return isset( $post->post_status ) && $post->post_status !== 'auto-draft';
}
/**
* Save posted meta data. Interfaces with WOMeta, and then performs additional tasks.
*
* @param int $post_id The Post ID that has saved.
* @param object $post The WP_Post object that has saved.
*
* @return void
*/
public function save_posted_metadata( $post_id, $post ) {
if ( $this->wo_meta->save_posted_metadata( $post, AdPostMeta::post_meta_keys(), $this->nonce, AdCommander::capability() ) ) {
$this->save_expire_gmt( $post_id );
}
delete_transient( AdminReports::filter_ads_transient() );
}
/**
* Convert the saved expire meta into a GMT timestamp and save it.
*
* @param int $post_id The post ID that was saved.
*
* @return void
*/
private function save_expire_gmt( $post_id ) {
$post_meta = $this->wo_meta->get_post_meta( $post_id, AdPostMeta::post_meta_keys() );
$expire_date = $this->wo_meta->get_value( $post_meta, 'expire_date' );
$expire_hour = $this->wo_meta->get_value( $post_meta, 'expire_hour' );
$expire_min = $this->wo_meta->get_value( $post_meta, 'expire_min' );
$expire_ampm = $this->wo_meta->get_value( $post_meta, 'expire_ampm' );
$expire_gmt = null;
if ( $expire_date && $expire_hour && $expire_min && $expire_ampm ) {
$expire_date = Util::datetime_wp_timezone( $expire_date . ' ' . $expire_hour . ':' . $expire_min . ' ' . $expire_ampm );
$expire_gmt = $expire_date->getTimestamp();
}
$this->wo_meta->update_post_meta( $post_id, 'expire_gmt', $expire_gmt );
}
/**
* Output content within an individual column on the Group taxonomy page.
*
* @param string $string Column name.
* @param array $column Existing columns.
* @param int $term_id The Term ID.
*
* @return void
*/
public function manage_ad_column_data( $column, $post_id ) {
switch ( $column ) {
case 'type':
$adtype = get_post_meta( $post_id, $this->wo_meta->make_key( 'adtype' ), true );
if ( $adtype ) {
echo esc_html( AdPostMeta::ad_types()[ $adtype ] );
}
break;
}
}
/**
* Update columns on the Group taxonomy page.
*
* @param array $columns The current columns.
*
* @return array
*/
public function manage_ad_columns( $columns ) {
/**
* Change existing columns
*/
unset( $columns['author'] );
/**
* Sort columns and add new
*/
$new_columns = array();
foreach ( $columns as $key => $label ) {
$new_columns[ $key ] = $label;
if ( $key === 'title' ) {
$new_columns['type'] = __( 'Type', 'ad-commander' );
}
}
return $new_columns;
}
}