container = $container; } /** * Hooks admin screens and WooCommerce integration. * * @since 1.0.0 */ public function register() { if ( ! is_admin() ) { return; } add_action( 'admin_menu', array( $this, 'menu' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'assets' ) ); add_action( 'admin_init', array( $this, 'maybe_redirect_wizard' ) ); add_action( 'add_meta_boxes', array( $this, 'order_metabox' ) ); add_filter( 'plugin_action_links_' . plugin_basename( PPL_AFW_FILE ), array( $this, 'action_links' ) ); } /** * HPOS-safe order edit URL. * * @since 1.0.0 * @param int $order_id Order id. * @return string */ public static function order_edit_url( $order_id ) { if ( class_exists( \Automattic\WooCommerce\Utilities\OrderUtil::class ) && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) { return admin_url( 'admin.php?page=wc-orders&action=edit&id=' . absint( $order_id ) ); } return admin_url( 'post.php?post=' . absint( $order_id ) . '&action=edit' ); } /** * Registers the top level menu and submenus. * * @since 1.0.0 */ public function menu() { add_menu_page( __( 'Affiliates', 'affireo-affiliates-for-woocommerce' ), __( 'Affiliates', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_affiliates', 'ppl-afw', array( $this, 'render_overview' ), 'dashicons-groups', 56 ); $pages = array( array( __( 'Overview', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_affiliates', 'ppl-afw', 'render_overview' ), array( __( 'All Affiliates', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_affiliates', 'ppl-afw-affiliates', 'render_affiliates' ), array( __( 'Referrals', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_affiliates', 'ppl-afw-referrals', 'render_referrals' ), array( __( 'Visits', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_affiliates', 'ppl-afw-visits', 'render_visits' ), array( __( 'Payouts', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_payouts', 'ppl-afw-payouts', 'render_payouts' ), ); $pages[] = array( __( 'Reports', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_view_reports', 'ppl-afw-reports', 'render_reports' ); $pages[] = array( __( 'Tools', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_settings', 'ppl-afw-tools', 'render_tools' ); $pages[] = array( __( 'Settings', 'affireo-affiliates-for-woocommerce' ), 'ppl_afw_manage_settings', 'ppl-afw-settings', 'render_settings' ); /** * Filters the Affiliates submenu pages. * * Each entry is array( label, capability, slug, render method ). * * @since 1.0.0 * @param array[] $pages Submenu definitions. */ $pages = apply_filters( 'ppl_afw_admin_pages', $pages ); foreach ( $pages as $page ) { add_submenu_page( 'ppl-afw', $page[0], $page[0], $page[1], $page[2], array( $this, $page[3] ) ); } } /** * Adds a Settings link to the plugin row on the Plugins screen. * * @since 1.0.0 * @param string[] $links Existing action links. * @return string[] */ public function action_links( $links ) { array_unshift( $links, '' . esc_html__( 'Settings', 'affireo-affiliates-for-woocommerce' ) . '' ); return $links; } /** * Loads admin CSS and JavaScript on plugin screens. * * @since 1.0.0 * @param string $hook Current screen hook. */ public function assets( $hook ) { if ( false === strpos( $hook, 'ppl-afw' ) ) { return; } $css = PPL_AFW_DIR . 'assets/css/admin.css'; wp_enqueue_style( 'ppl-afw-admin', PPL_AFW_URL . 'assets/css/admin.css', array(), file_exists( $css ) ? md5_file( $css ) : PPL_AFW_VERSION ); /** * Filters the script dependencies of the admin script. * * @since 1.2.0 * @param string[] $deps Script handles. * @param string $hook Current screen hook. */ $deps = (array) apply_filters( 'ppl_afw_admin_script_deps', array( 'jquery', 'jquery-ui-sortable' ), $hook ); $js = PPL_AFW_DIR . 'assets/js/admin.js'; wp_enqueue_script( 'ppl-afw-admin', PPL_AFW_URL . 'assets/js/admin.js', $deps, file_exists( $js ) ? md5_file( $js ) : PPL_AFW_VERSION, true ); wp_localize_script( 'ppl-afw-admin', 'pplAfwAdmin', array( 'i18n' => array( 'chooseImage' => __( 'Select image', 'affireo-affiliates-for-woocommerce' ), 'useImage' => __( 'Use image', 'affireo-affiliates-for-woocommerce' ), ), ) ); } /** * Redirects to the setup wizard once after activation. * * @since 1.0.0 */ public function maybe_redirect_wizard() { if ( get_transient( 'ppl_afw_activation_redirect' ) && current_user_can( 'ppl_afw_manage_settings' ) && ! wp_doing_ajax() ) { delete_transient( 'ppl_afw_activation_redirect' ); if ( ! get_option( 'ppl_afw_setup_complete' ) ) { wp_safe_redirect( admin_url( 'admin.php?page=ppl-afw-settings&wizard=1' ) ); exit; } } } /** * Renders a view template. * * Each variable a view may use is assigned by name, so a view only ever * sees the values listed here. * * @since 1.0.0 * @param string $name View file name without extension. * @param array $vars Variables exposed to the view. */ private function view( $name, array $vars = array() ) { $container = $this->container; $affiliate = $vars['affiliate'] ?? null; $payout = $vars['payout'] ?? null; $totals = $vars['totals'] ?? array(); $series = $vars['series'] ?? array(); $counts = $vars['counts'] ?? array(); $leaders = $vars['leaders'] ?? array(); $from = $vars['from'] ?? ''; $to = $vars['to'] ?? ''; $status = $vars['status'] ?? ''; $statuses = $vars['statuses'] ?? array(); $tab = $vars['tab'] ?? ''; $s = $vars['s'] ?? array(); include PPL_AFW_DIR . 'includes/admin/views/' . sanitize_file_name( $name ) . '.php'; } /** * Overview dashboard. * * @since 1.0.0 */ public function render_overview() { $stats = $this->container->get( 'stats' ); $to = gmdate( 'Y-m-d' ); $from = gmdate( 'Y-m-d', time() - 29 * DAY_IN_SECONDS ); $this->view( 'overview', array( 'totals' => $stats->totals( 0, $from, $to ), 'series' => $stats->series( 0, $from, $to ), 'counts' => $this->container->get( 'affiliates.repository' )->status_counts(), 'leaders' => $stats->leaderboard( 30, 5 ), ) ); } /** * Affiliates list or detail screen. * * @since 1.0.0 */ public function render_affiliates() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- routing only. $preview_id = isset( $_GET['preview'] ) ? absint( wp_unslash( $_GET['preview'] ) ) : 0; if ( $preview_id && current_user_can( 'ppl_afw_impersonate_affiliates' ) ) { $affiliate = $this->container->get( 'affiliates.repository' )->find( $preview_id ); if ( $affiliate && 'active' === $affiliate->status ) { $this->render_preview( $affiliate ); return; } } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- routing only. $view_id = isset( $_GET['view'] ) ? absint( wp_unslash( $_GET['view'] ) ) : 0; if ( $view_id ) { $affiliate = $this->container->get( 'affiliates.repository' )->find( $view_id ); if ( $affiliate ) { $this->view( 'affiliate-detail', array( 'affiliate' => $affiliate ) ); return; } } $table = new Affiliates_Table( $this->container ); $table->prepare_items(); ?>
' . esc_html( sanitize_text_field( wp_unslash( $_GET['ppl_msg'] ) ) ) . '
' . esc_html( sanitize_text_field( wp_unslash( $_GET['ppl_err'] ) ) ) . '
' . esc_html__( 'No affiliate attributed to this order.', 'affireo-affiliates-for-woocommerce' ) . '
'; } else { $affiliate = $this->container->get( 'affiliates.repository' )->find( $affiliate_id ); $user = $affiliate ? get_userdata( (int) $affiliate->user_id ) : null; $detail = admin_url( 'admin.php?page=ppl-afw-affiliates&view=' . $affiliate_id ); $referrals = admin_url( 'admin.php?page=ppl-afw-referrals&order_id=' . $order->get_id() ); echo '' . esc_html( $user ? $user->display_name : '#' . $affiliate_id ) . ' (' . esc_html( $affiliate->slug ?? '' ) . ')
' . esc_html__( 'View commissions for this order', 'affireo-affiliates-for-woocommerce' ) . '
'; } /** * Fires at the end of the order's Affiliate attribution box. * * @since 1.3.0 * @param \WC_Order $order Order object. * @param int $affiliate_id Attributed affiliate id, 0 for none. */ do_action( 'ppl_afw_order_metabox', $order, $affiliate_id ); } }